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