##// END OF EJS Templates
zmqterminal frontend now uses IPythonInputSplitter, and non-ascii characters work.
Thomas Kluyver -
Show More
@@ -1,282 +1,282 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Frontend of ipython working with python-zmq
2 """Frontend of ipython working with python-zmq
3
3
4 Ipython's frontend, is a ipython interface that send request to kernel and proccess the kernel's outputs.
4 Ipython's frontend, is a ipython interface that send request to kernel and proccess the kernel's outputs.
5
5
6 For more details, see the ipython-zmq design
6 For more details, see the ipython-zmq design
7 """
7 """
8 #-----------------------------------------------------------------------------
8 #-----------------------------------------------------------------------------
9 # Copyright (C) 2010 The IPython Development Team
9 # Copyright (C) 2010 The IPython Development Team
10 #
10 #
11 # Distributed under the terms of the BSD License. The full license is in
11 # Distributed under the terms of the BSD License. The full license is in
12 # the file COPYING, distributed as part of this software.
12 # the file COPYING, distributed as part of this software.
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14
14
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16 # Imports
16 # Imports
17 #-----------------------------------------------------------------------------
17 #-----------------------------------------------------------------------------
18
18
19 import __builtin__
19 import __builtin__
20 from contextlib import nested
20 from contextlib import nested
21 import time
21 import time
22 import sys
22 import sys
23 import os
23 import os
24 import signal
24 import signal
25 import uuid
25 import uuid
26 import cPickle as pickle
26 import cPickle as pickle
27 import code
27 import code
28 import zmq
28 import zmq
29 import readline
29 import readline
30 import rlcompleter
30 import rlcompleter
31 import time
31 import time
32
32
33 #-----------------------------------------------------------------------------
33 #-----------------------------------------------------------------------------
34 # Imports from ipython
34 # Imports from ipython
35 #-----------------------------------------------------------------------------
35 #-----------------------------------------------------------------------------
36 from IPython.external.argparse import ArgumentParser
36 from IPython.external.argparse import ArgumentParser
37 from IPython.utils.traitlets import (
37 from IPython.utils.traitlets import (
38 Int, Str, CBool, CaselessStrEnum, Enum, List, Unicode
38 Int, Str, CBool, CaselessStrEnum, Enum, List, Unicode
39 )
39 )
40 from IPython.core.interactiveshell import get_default_colors
40 from IPython.core.interactiveshell import get_default_colors
41 from IPython.core.excolors import exception_colors
41 from IPython.core.excolors import exception_colors
42 from IPython.utils import PyColorize
42 from IPython.utils import PyColorize
43 from IPython.core.inputsplitter import InputSplitter
43 from IPython.core.inputsplitter import IPythonInputSplitter
44 from IPython.frontend.zmqterminal.kernelmanager import KernelManager2p as KernelManager
44 from IPython.frontend.zmqterminal.kernelmanager import KernelManager2p as KernelManager
45 from IPython.zmq.session import Session
45 from IPython.zmq.session import Session
46 from IPython.frontend.zmqterminal.completer import ClientCompleter2p
46 from IPython.frontend.zmqterminal.completer import ClientCompleter2p
47
47
48 #-----------------------------------------------------------------------------
48 #-----------------------------------------------------------------------------
49 # Network Constants
49 # Network Constants
50 #-----------------------------------------------------------------------------
50 #-----------------------------------------------------------------------------
51
51
52 from IPython.utils.localinterfaces import LOCALHOST, LOCAL_IPS
52 from IPython.utils.localinterfaces import LOCALHOST, LOCAL_IPS
53 class Frontend(object):
53 class Frontend(object):
54 """ this class is a simple frontend to ipython-zmq
54 """ this class is a simple frontend to ipython-zmq
55
55
56 NOTE: this class use kernelmanager to manipulate sockets
56 NOTE: this class use kernelmanager to manipulate sockets
57
57
58 Parameters:
58 Parameters:
59 -----------
59 -----------
60 kernelmanager : object
60 kernelmanager : object
61 instantiated object from class KernelManager in module kernelmanager
61 instantiated object from class KernelManager in module kernelmanager
62
62
63 """
63 """
64
64
65 def __init__(self,kernelmanager):
65 def __init__(self,kernelmanager):
66 self.km = kernelmanager
66 self.km = kernelmanager
67 self.session = kernelmanager.session
67 self.session = kernelmanager.session
68 self.request_socket = self.km.xreq_channel.socket
68 self.request_socket = self.km.xreq_channel.socket
69 self.sub_socket = self.km.sub_channel.socket
69 self.sub_socket = self.km.sub_channel.socket
70 self.reply_socket = self.km.rep_channel.socket
70 self.reply_socket = self.km.rep_channel.socket
71 self.msg_header = self.km.session.msg_header()
71 self.msg_header = self.km.session.msg_header()
72 self.completer = ClientCompleter2p(self,self.km)
72 self.completer = ClientCompleter2p(self,self.km)
73 readline.parse_and_bind("tab: complete")
73 readline.parse_and_bind("tab: complete")
74 readline.parse_and_bind('set show-all-if-ambiguous on')
74 readline.parse_and_bind('set show-all-if-ambiguous on')
75 readline.set_completer(self.completer.complete)
75 readline.set_completer(self.completer.complete)
76
76
77 history_path = os.path.expanduser('~/.ipython/history')
77 history_path = os.path.expanduser('~/.ipython/history')
78 if os.path.isfile(history_path):
78 if os.path.isfile(history_path):
79 rlcompleter.readline.read_history_file(history_path)
79 rlcompleter.readline.read_history_file(history_path)
80 else:
80 else:
81 print("history file can not be readed.")
81 print("history file can not be readed.")
82
82
83 self.messages = {}
83 self.messages = {}
84
84
85 self._splitter = InputSplitter()
85 self._splitter = IPythonInputSplitter()
86 self.code = ""
86 self.code = ""
87
87
88 self.prompt_count = 0
88 self.prompt_count = 0
89 self._get_initail_promt()
89 self._get_initail_promt()
90
90
91 def _get_initail_promt(self):
91 def _get_initail_promt(self):
92 self._execute('', hidden=True)
92 self._execute('', hidden=True)
93
93
94 def interact(self):
94 def interact(self):
95 """ let you get input from console using inputsplitter, then
95 """ let you get input from console using inputsplitter, then
96 while you enter code it can indent and set index id to any input
96 while you enter code it can indent and set index id to any input
97
97
98 """
98 """
99
99
100 try:
100 try:
101 self._splitter.push(raw_input('In[%i]:'%self.prompt_count+self.code))
101 self._splitter.push(raw_input('In[%i]:'%self.prompt_count+self.code))
102 while self._splitter.push_accepts_more():
102 while self._splitter.push_accepts_more():
103 self.code = raw_input('.....:'+' '*self._splitter.indent_spaces)
103 self.code = raw_input('.....:'+' '*self._splitter.indent_spaces)
104 self._splitter.push(' '*self._splitter.indent_spaces+self.code)
104 self._splitter.push(' '*self._splitter.indent_spaces+self.code)
105 self._execute(self._splitter.source,False)
105 self._execute(self._splitter.source,False)
106 self._splitter.reset()
106 self._splitter.reset()
107 except KeyboardInterrupt:
107 except KeyboardInterrupt:
108 print('\nKeyboardInterrupt\n')
108 print('\nKeyboardInterrupt\n')
109 pass
109 pass
110
110
111
111
112 def start(self):
112 def start(self):
113 """ init a bucle that call interact method to get code.
113 """ init a bucle that call interact method to get code.
114
114
115 """
115 """
116 while True:
116 while True:
117 try:
117 try:
118 self.interact()
118 self.interact()
119 except KeyboardInterrupt:
119 except KeyboardInterrupt:
120 print('\nKeyboardInterrupt\n')
120 print('\nKeyboardInterrupt\n')
121 pass
121 pass
122 except EOFError:
122 except EOFError:
123 answer = ''
123 answer = ''
124 while True:
124 while True:
125 answer = raw_input('\nDo you really want to exit ([y]/n)?')
125 answer = raw_input('\nDo you really want to exit ([y]/n)?')
126 if answer == 'y' or answer == '' :
126 if answer == 'y' or answer == '' :
127 self.km.shutdown_kernel()
127 self.km.shutdown_kernel()
128 sys.exit()
128 sys.exit()
129 elif answer == 'n':
129 elif answer == 'n':
130 break
130 break
131
131
132 def _execute(self, source, hidden = True):
132 def _execute(self, source, hidden = True):
133 """ Execute 'source'. If 'hidden', do not show any output.
133 """ Execute 'source'. If 'hidden', do not show any output.
134
134
135 See parent class :meth:`execute` docstring for full details.
135 See parent class :meth:`execute` docstring for full details.
136 """
136 """
137 self.km.xreq_channel.execute(source, hidden)
137 self.km.xreq_channel.execute(source, hidden)
138 self.handle_xreq_channel()
138 self.handle_xreq_channel()
139 self.handle_rep_channel()
139 self.handle_rep_channel()
140
140
141 def handle_xreq_channel(self):
141 def handle_xreq_channel(self):
142 # Give the kernel up to 0.5s to respond
142 # Give the kernel up to 0.5s to respond
143 for i in range(5):
143 for i in range(5):
144 if self.km.xreq_channel.was_called():
144 if self.km.xreq_channel.was_called():
145 self.msg_xreq = self.km.xreq_channel.get_msg()
145 self.msg_xreq = self.km.xreq_channel.get_msg()
146 if self.msg_header["session"] == self.msg_xreq["parent_header"]["session"] :
146 if self.msg_header["session"] == self.msg_xreq["parent_header"]["session"] :
147 if self.msg_xreq["content"]["status"] == 'ok' :
147 if self.msg_xreq["content"]["status"] == 'ok' :
148 if self.msg_xreq["msg_type"] == "execute_reply" :
148 if self.msg_xreq["msg_type"] == "execute_reply" :
149 self.handle_sub_channel()
149 self.handle_sub_channel()
150 self.prompt_count = self.msg_xreq["content"]["execution_count"]+1
150 self.prompt_count = self.msg_xreq["content"]["execution_count"]+1
151
151
152 else:
152 else:
153 etb = self.msg_xreq["content"]["traceback"]
153 etb = self.msg_xreq["content"]["traceback"]
154 print >> sys.stderr, etb[0]
154 print >> sys.stderr, etb[0]
155 print >> sys.stderr, etb[1]
155 print >> sys.stderr, etb[1]
156 print >> sys.stderr, etb[2]
156 print >> sys.stderr, etb[2]
157 self.prompt_count = self.msg_xreq["content"]["execution_count"]+1
157 self.prompt_count = self.msg_xreq["content"]["execution_count"]+1
158 break
158 break
159 time.sleep(0.1)
159 time.sleep(0.1)
160
160
161
161
162 def handle_sub_channel(self):
162 def handle_sub_channel(self):
163 """ Method to procces subscribe channel's messages
163 """ Method to procces subscribe channel's messages
164
164
165 this method read a message and procces the content
165 this method read a message and procces the content
166 in differents outputs like stdout, stderr, pyout
166 in differents outputs like stdout, stderr, pyout
167 and status
167 and status
168
168
169 Arguments:
169 Arguments:
170 sub_msg: message receive from kernel in the sub socket channel
170 sub_msg: message receive from kernel in the sub socket channel
171 capture by kernel manager.
171 capture by kernel manager.
172
172
173 """
173 """
174 while self.km.sub_channel.was_called():
174 while self.km.sub_channel.was_called():
175 sub_msg = self.km.sub_channel.get_msg()
175 sub_msg = self.km.sub_channel.get_msg()
176 if self.msg_header["username"] == sub_msg['parent_header']['username'] and self.km.session.session == sub_msg['parent_header']['session']:
176 if self.msg_header["username"] == sub_msg['parent_header']['username'] and self.km.session.session == sub_msg['parent_header']['session']:
177 if sub_msg['msg_type'] == 'status' :
177 if sub_msg['msg_type'] == 'status' :
178 if sub_msg["content"]["execution_state"] == "busy" :
178 if sub_msg["content"]["execution_state"] == "busy" :
179 pass
179 pass
180
180
181 if sub_msg['msg_type'] == 'stream' :
181 if sub_msg['msg_type'] == 'stream' :
182 if sub_msg["content"]["name"] == "stdout":
182 if sub_msg["content"]["name"] == "stdout":
183 print >> sys.stdout,sub_msg["content"]["data"]
183 print >> sys.stdout,sub_msg["content"]["data"]
184 sys.stdout.flush()
184 sys.stdout.flush()
185 if sub_msg["content"]["name"] == "stderr" :
185 if sub_msg["content"]["name"] == "stderr" :
186 print >> sys.stderr,sub_msg["content"]["data"]
186 print >> sys.stderr,sub_msg["content"]["data"]
187 sys.stderr.flush()
187 sys.stderr.flush()
188
188
189 if sub_msg['msg_type'] == 'pyout' :
189 if sub_msg['msg_type'] == 'pyout' :
190 print >> sys.stdout,"Out[%i]:"%sub_msg["content"]["execution_count"], sub_msg["content"]["data"]["text/plain"]
190 print >> sys.stdout,"Out[%i]:"%sub_msg["content"]["execution_count"], sub_msg["content"]["data"]["text/plain"]
191 sys.stdout.flush()
191 sys.stdout.flush()
192
192
193 def handle_rep_channel(self):
193 def handle_rep_channel(self):
194 """ Method to capture raw_input
194 """ Method to capture raw_input
195 """
195 """
196 if self.km.rep_channel.was_called() :
196 if self.km.rep_channel.was_called() :
197 self.msg_rep = self.km.rep_channel.get_msg()
197 self.msg_rep = self.km.rep_channel.get_msg()
198 if self.msg_header["session"] == self.msg_rep["parent_header"]["session"] :
198 if self.msg_header["session"] == self.msg_rep["parent_header"]["session"] :
199 raw_data = raw_input(self.msg_rep["content"]["prompt"])
199 raw_data = raw_input(self.msg_rep["content"]["prompt"])
200 self.km.rep_channel.input(raw_data)
200 self.km.rep_channel.input(raw_data)
201
201
202
202
203
203
204
204
205 def start_frontend():
205 def start_frontend():
206 """ Entry point for application.
206 """ Entry point for application.
207
207
208 """
208 """
209 # Parse command line arguments.
209 # Parse command line arguments.
210 parser = ArgumentParser()
210 parser = ArgumentParser()
211 kgroup = parser.add_argument_group('kernel options')
211 kgroup = parser.add_argument_group('kernel options')
212 kgroup.add_argument('-e', '--existing', action='store_true',
212 kgroup.add_argument('-e', '--existing', action='store_true',
213 help='connect to an existing kernel')
213 help='connect to an existing kernel')
214 kgroup.add_argument('--ip', type=str, default=LOCALHOST,
214 kgroup.add_argument('--ip', type=str, default=LOCALHOST,
215 help=\
215 help=\
216 "set the kernel\'s IP address [default localhost].\
216 "set the kernel\'s IP address [default localhost].\
217 If the IP address is something other than localhost, then \
217 If the IP address is something other than localhost, then \
218 Consoles on other machines will be able to connect\
218 Consoles on other machines will be able to connect\
219 to the Kernel, so be careful!")
219 to the Kernel, so be careful!")
220 kgroup.add_argument('--xreq', type=int, metavar='PORT', default=0,
220 kgroup.add_argument('--xreq', type=int, metavar='PORT', default=0,
221 help='set the XREQ channel port [default random]')
221 help='set the XREQ channel port [default random]')
222 kgroup.add_argument('--sub', type=int, metavar='PORT', default=0,
222 kgroup.add_argument('--sub', type=int, metavar='PORT', default=0,
223 help='set the SUB channel port [default random]')
223 help='set the SUB channel port [default random]')
224 kgroup.add_argument('--rep', type=int, metavar='PORT', default=0,
224 kgroup.add_argument('--rep', type=int, metavar='PORT', default=0,
225 help='set the REP channel port [default random]')
225 help='set the REP channel port [default random]')
226 kgroup.add_argument('--hb', type=int, metavar='PORT', default=0,
226 kgroup.add_argument('--hb', type=int, metavar='PORT', default=0,
227 help='set the heartbeat port [default random]')
227 help='set the heartbeat port [default random]')
228
228
229 egroup = kgroup.add_mutually_exclusive_group()
229 egroup = kgroup.add_mutually_exclusive_group()
230 egroup.add_argument('--pure', action='store_true', help = \
230 egroup.add_argument('--pure', action='store_true', help = \
231 'use a pure Python kernel instead of an IPython kernel')
231 'use a pure Python kernel instead of an IPython kernel')
232 egroup.add_argument('--pylab', type=str, metavar='GUI', nargs='?',
232 egroup.add_argument('--pylab', type=str, metavar='GUI', nargs='?',
233 const='auto', help = \
233 const='auto', help = \
234 "Pre-load matplotlib and numpy for interactive use. If GUI is not \
234 "Pre-load matplotlib and numpy for interactive use. If GUI is not \
235 given, the GUI backend is matplotlib's, otherwise use one of: \
235 given, the GUI backend is matplotlib's, otherwise use one of: \
236 ['tk', 'gtk', 'qt', 'wx', 'inline'].")
236 ['tk', 'gtk', 'qt', 'wx', 'inline'].")
237 egroup.add_argument('--colors', type=str,
237 egroup.add_argument('--colors', type=str,
238 help="Set the color scheme (LightBG,Linux,NoColor). This is guessed\
238 help="Set the color scheme (LightBG,Linux,NoColor). This is guessed\
239 based on the pygments style if not set.")
239 based on the pygments style if not set.")
240
240
241 args = parser.parse_args()
241 args = parser.parse_args()
242
242
243 # parse the colors arg down to current known labels
243 # parse the colors arg down to current known labels
244 if args.colors:
244 if args.colors:
245 colors=args.colors.lower()
245 colors=args.colors.lower()
246 if colors in ('lightbg', 'light'):
246 if colors in ('lightbg', 'light'):
247 colors='lightbg'
247 colors='lightbg'
248 elif colors in ('dark', 'linux'):
248 elif colors in ('dark', 'linux'):
249 colors='linux'
249 colors='linux'
250 else:
250 else:
251 colors='nocolor'
251 colors='nocolor'
252 else:
252 else:
253 colors=None
253 colors=None
254
254
255 # Create a KernelManager and start a kernel.
255 # Create a KernelManager and start a kernel.
256 kernel_manager = KernelManager(xreq_address=(args.ip, args.xreq),
256 kernel_manager = KernelManager(xreq_address=(args.ip, args.xreq),
257 sub_address=(args.ip, args.sub),
257 sub_address=(args.ip, args.sub),
258 rep_address=(args.ip, args.rep),
258 rep_address=(args.ip, args.rep),
259 hb_address=(args.ip, args.hb))
259 hb_address=(args.ip, args.hb))
260 if not args.existing:
260 if not args.existing:
261 # if not args.ip in LOCAL_IPS+ALL_ALIAS:
261 # if not args.ip in LOCAL_IPS+ALL_ALIAS:
262 # raise ValueError("Must bind a local ip, such as: %s"%LOCAL_IPS)
262 # raise ValueError("Must bind a local ip, such as: %s"%LOCAL_IPS)
263
263
264 kwargs = dict(ip=args.ip)
264 kwargs = dict(ip=args.ip)
265 if args.pure:
265 if args.pure:
266 kwargs['ipython']=False
266 kwargs['ipython']=False
267 else:
267 else:
268 kwargs['colors']=colors
268 kwargs['colors']=colors
269 if args.pylab:
269 if args.pylab:
270 kwargs['pylab']=args.pylab
270 kwargs['pylab']=args.pylab
271 kernel_manager.start_kernel(**kwargs)
271 kernel_manager.start_kernel(**kwargs)
272
272
273
273
274 kernel_manager.start_channels()
274 kernel_manager.start_channels()
275 time.sleep(4)
275 time.sleep(4)
276
276
277 frontend=Frontend(kernel_manager)
277 frontend=Frontend(kernel_manager)
278 return frontend
278 return frontend
279
279
280 if __name__ == "__main__" :
280 if __name__ == "__main__" :
281 frontend=start_frontend()
281 frontend=start_frontend()
282 frontend.start()
282 frontend.start()
General Comments 0
You need to be logged in to leave comments. Login now