##// END OF EJS Templates
Fix ``%history -f foo`` in kernel....
Thomas Kluyver -
Show More
@@ -1,795 +1,795 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 """An interactive kernel that talks to frontends over 0MQ."""
2 """An interactive kernel that talks to frontends over 0MQ."""
3
3
4 #-----------------------------------------------------------------------------
4 #-----------------------------------------------------------------------------
5 # Imports
5 # Imports
6 #-----------------------------------------------------------------------------
6 #-----------------------------------------------------------------------------
7 from __future__ import print_function
7 from __future__ import print_function
8
8
9 # Standard library imports
9 # Standard library imports
10 import sys
10 import sys
11 import time
11 import time
12 import traceback
12 import traceback
13 import logging
13 import logging
14 import uuid
14 import uuid
15
15
16 from datetime import datetime
16 from datetime import datetime
17 from signal import (
17 from signal import (
18 signal, default_int_handler, SIGINT
18 signal, default_int_handler, SIGINT
19 )
19 )
20
20
21 # System library imports
21 # System library imports
22 import zmq
22 import zmq
23 from zmq.eventloop import ioloop
23 from zmq.eventloop import ioloop
24 from zmq.eventloop.zmqstream import ZMQStream
24 from zmq.eventloop.zmqstream import ZMQStream
25
25
26 # Local imports
26 # Local imports
27 from IPython.config.configurable import Configurable
27 from IPython.config.configurable import Configurable
28 from IPython.core.error import StdinNotImplementedError
28 from IPython.core.error import StdinNotImplementedError
29 from IPython.core import release
29 from IPython.core import release
30 from IPython.utils import py3compat
30 from IPython.utils import py3compat
31 from IPython.utils.py3compat import builtin_mod, unicode_type, string_types
31 from IPython.utils.py3compat import builtin_mod, unicode_type, string_types
32 from IPython.utils.jsonutil import json_clean
32 from IPython.utils.jsonutil import json_clean
33 from IPython.utils.traitlets import (
33 from IPython.utils.traitlets import (
34 Any, Instance, Float, Dict, List, Set, Integer, Unicode,
34 Any, Instance, Float, Dict, List, Set, Integer, Unicode,
35 Type, Bool,
35 Type, Bool,
36 )
36 )
37
37
38 from .serialize import serialize_object, unpack_apply_message
38 from .serialize import serialize_object, unpack_apply_message
39 from .session import Session
39 from .session import Session
40 from .zmqshell import ZMQInteractiveShell
40 from .zmqshell import ZMQInteractiveShell
41
41
42
42
43 #-----------------------------------------------------------------------------
43 #-----------------------------------------------------------------------------
44 # Main kernel class
44 # Main kernel class
45 #-----------------------------------------------------------------------------
45 #-----------------------------------------------------------------------------
46
46
47 protocol_version = list(release.kernel_protocol_version_info)
47 protocol_version = list(release.kernel_protocol_version_info)
48 ipython_version = list(release.version_info)
48 ipython_version = list(release.version_info)
49 language_version = list(sys.version_info[:3])
49 language_version = list(sys.version_info[:3])
50
50
51
51
52 class Kernel(Configurable):
52 class Kernel(Configurable):
53
53
54 #---------------------------------------------------------------------------
54 #---------------------------------------------------------------------------
55 # Kernel interface
55 # Kernel interface
56 #---------------------------------------------------------------------------
56 #---------------------------------------------------------------------------
57
57
58 # attribute to override with a GUI
58 # attribute to override with a GUI
59 eventloop = Any(None)
59 eventloop = Any(None)
60 def _eventloop_changed(self, name, old, new):
60 def _eventloop_changed(self, name, old, new):
61 """schedule call to eventloop from IOLoop"""
61 """schedule call to eventloop from IOLoop"""
62 loop = ioloop.IOLoop.instance()
62 loop = ioloop.IOLoop.instance()
63 loop.add_timeout(time.time()+0.1, self.enter_eventloop)
63 loop.add_timeout(time.time()+0.1, self.enter_eventloop)
64
64
65 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
65 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
66 shell_class = Type(ZMQInteractiveShell)
66 shell_class = Type(ZMQInteractiveShell)
67
67
68 session = Instance(Session)
68 session = Instance(Session)
69 profile_dir = Instance('IPython.core.profiledir.ProfileDir')
69 profile_dir = Instance('IPython.core.profiledir.ProfileDir')
70 shell_streams = List()
70 shell_streams = List()
71 control_stream = Instance(ZMQStream)
71 control_stream = Instance(ZMQStream)
72 iopub_socket = Instance(zmq.Socket)
72 iopub_socket = Instance(zmq.Socket)
73 stdin_socket = Instance(zmq.Socket)
73 stdin_socket = Instance(zmq.Socket)
74 log = Instance(logging.Logger)
74 log = Instance(logging.Logger)
75
75
76 user_module = Any()
76 user_module = Any()
77 def _user_module_changed(self, name, old, new):
77 def _user_module_changed(self, name, old, new):
78 if self.shell is not None:
78 if self.shell is not None:
79 self.shell.user_module = new
79 self.shell.user_module = new
80
80
81 user_ns = Instance(dict, args=None, allow_none=True)
81 user_ns = Instance(dict, args=None, allow_none=True)
82 def _user_ns_changed(self, name, old, new):
82 def _user_ns_changed(self, name, old, new):
83 if self.shell is not None:
83 if self.shell is not None:
84 self.shell.user_ns = new
84 self.shell.user_ns = new
85 self.shell.init_user_ns()
85 self.shell.init_user_ns()
86
86
87 # identities:
87 # identities:
88 int_id = Integer(-1)
88 int_id = Integer(-1)
89 ident = Unicode()
89 ident = Unicode()
90
90
91 def _ident_default(self):
91 def _ident_default(self):
92 return unicode_type(uuid.uuid4())
92 return unicode_type(uuid.uuid4())
93
93
94 # Private interface
94 # Private interface
95
95
96 _darwin_app_nap = Bool(True, config=True,
96 _darwin_app_nap = Bool(True, config=True,
97 help="""Whether to use appnope for compatiblity with OS X App Nap.
97 help="""Whether to use appnope for compatiblity with OS X App Nap.
98
98
99 Only affects OS X >= 10.9.
99 Only affects OS X >= 10.9.
100 """
100 """
101 )
101 )
102
102
103 # Time to sleep after flushing the stdout/err buffers in each execute
103 # Time to sleep after flushing the stdout/err buffers in each execute
104 # cycle. While this introduces a hard limit on the minimal latency of the
104 # cycle. While this introduces a hard limit on the minimal latency of the
105 # execute cycle, it helps prevent output synchronization problems for
105 # execute cycle, it helps prevent output synchronization problems for
106 # clients.
106 # clients.
107 # Units are in seconds. The minimum zmq latency on local host is probably
107 # Units are in seconds. The minimum zmq latency on local host is probably
108 # ~150 microseconds, set this to 500us for now. We may need to increase it
108 # ~150 microseconds, set this to 500us for now. We may need to increase it
109 # a little if it's not enough after more interactive testing.
109 # a little if it's not enough after more interactive testing.
110 _execute_sleep = Float(0.0005, config=True)
110 _execute_sleep = Float(0.0005, config=True)
111
111
112 # Frequency of the kernel's event loop.
112 # Frequency of the kernel's event loop.
113 # Units are in seconds, kernel subclasses for GUI toolkits may need to
113 # Units are in seconds, kernel subclasses for GUI toolkits may need to
114 # adapt to milliseconds.
114 # adapt to milliseconds.
115 _poll_interval = Float(0.05, config=True)
115 _poll_interval = Float(0.05, config=True)
116
116
117 # If the shutdown was requested over the network, we leave here the
117 # If the shutdown was requested over the network, we leave here the
118 # necessary reply message so it can be sent by our registered atexit
118 # necessary reply message so it can be sent by our registered atexit
119 # handler. This ensures that the reply is only sent to clients truly at
119 # handler. This ensures that the reply is only sent to clients truly at
120 # the end of our shutdown process (which happens after the underlying
120 # the end of our shutdown process (which happens after the underlying
121 # IPython shell's own shutdown).
121 # IPython shell's own shutdown).
122 _shutdown_message = None
122 _shutdown_message = None
123
123
124 # This is a dict of port number that the kernel is listening on. It is set
124 # This is a dict of port number that the kernel is listening on. It is set
125 # by record_ports and used by connect_request.
125 # by record_ports and used by connect_request.
126 _recorded_ports = Dict()
126 _recorded_ports = Dict()
127
127
128 # A reference to the Python builtin 'raw_input' function.
128 # A reference to the Python builtin 'raw_input' function.
129 # (i.e., __builtin__.raw_input for Python 2.7, builtins.input for Python 3)
129 # (i.e., __builtin__.raw_input for Python 2.7, builtins.input for Python 3)
130 _sys_raw_input = Any()
130 _sys_raw_input = Any()
131 _sys_eval_input = Any()
131 _sys_eval_input = Any()
132
132
133 # set of aborted msg_ids
133 # set of aborted msg_ids
134 aborted = Set()
134 aborted = Set()
135
135
136
136
137 def __init__(self, **kwargs):
137 def __init__(self, **kwargs):
138 super(Kernel, self).__init__(**kwargs)
138 super(Kernel, self).__init__(**kwargs)
139
139
140 # Initialize the InteractiveShell subclass
140 # Initialize the InteractiveShell subclass
141 self.shell = self.shell_class.instance(parent=self,
141 self.shell = self.shell_class.instance(parent=self,
142 profile_dir = self.profile_dir,
142 profile_dir = self.profile_dir,
143 user_module = self.user_module,
143 user_module = self.user_module,
144 user_ns = self.user_ns,
144 user_ns = self.user_ns,
145 kernel = self,
145 kernel = self,
146 )
146 )
147 self.shell.displayhook.session = self.session
147 self.shell.displayhook.session = self.session
148 self.shell.displayhook.pub_socket = self.iopub_socket
148 self.shell.displayhook.pub_socket = self.iopub_socket
149 self.shell.displayhook.topic = self._topic('pyout')
149 self.shell.displayhook.topic = self._topic('pyout')
150 self.shell.display_pub.session = self.session
150 self.shell.display_pub.session = self.session
151 self.shell.display_pub.pub_socket = self.iopub_socket
151 self.shell.display_pub.pub_socket = self.iopub_socket
152 self.shell.data_pub.session = self.session
152 self.shell.data_pub.session = self.session
153 self.shell.data_pub.pub_socket = self.iopub_socket
153 self.shell.data_pub.pub_socket = self.iopub_socket
154
154
155 # TMP - hack while developing
155 # TMP - hack while developing
156 self.shell._reply_content = None
156 self.shell._reply_content = None
157
157
158 # Build dict of handlers for message types
158 # Build dict of handlers for message types
159 msg_types = [ 'execute_request', 'complete_request',
159 msg_types = [ 'execute_request', 'complete_request',
160 'object_info_request', 'history_request',
160 'object_info_request', 'history_request',
161 'kernel_info_request',
161 'kernel_info_request',
162 'connect_request', 'shutdown_request',
162 'connect_request', 'shutdown_request',
163 'apply_request',
163 'apply_request',
164 ]
164 ]
165 self.shell_handlers = {}
165 self.shell_handlers = {}
166 for msg_type in msg_types:
166 for msg_type in msg_types:
167 self.shell_handlers[msg_type] = getattr(self, msg_type)
167 self.shell_handlers[msg_type] = getattr(self, msg_type)
168
168
169 comm_msg_types = [ 'comm_open', 'comm_msg', 'comm_close' ]
169 comm_msg_types = [ 'comm_open', 'comm_msg', 'comm_close' ]
170 comm_manager = self.shell.comm_manager
170 comm_manager = self.shell.comm_manager
171 for msg_type in comm_msg_types:
171 for msg_type in comm_msg_types:
172 self.shell_handlers[msg_type] = getattr(comm_manager, msg_type)
172 self.shell_handlers[msg_type] = getattr(comm_manager, msg_type)
173
173
174 control_msg_types = msg_types + [ 'clear_request', 'abort_request' ]
174 control_msg_types = msg_types + [ 'clear_request', 'abort_request' ]
175 self.control_handlers = {}
175 self.control_handlers = {}
176 for msg_type in control_msg_types:
176 for msg_type in control_msg_types:
177 self.control_handlers[msg_type] = getattr(self, msg_type)
177 self.control_handlers[msg_type] = getattr(self, msg_type)
178
178
179
179
180 def dispatch_control(self, msg):
180 def dispatch_control(self, msg):
181 """dispatch control requests"""
181 """dispatch control requests"""
182 idents,msg = self.session.feed_identities(msg, copy=False)
182 idents,msg = self.session.feed_identities(msg, copy=False)
183 try:
183 try:
184 msg = self.session.unserialize(msg, content=True, copy=False)
184 msg = self.session.unserialize(msg, content=True, copy=False)
185 except:
185 except:
186 self.log.error("Invalid Control Message", exc_info=True)
186 self.log.error("Invalid Control Message", exc_info=True)
187 return
187 return
188
188
189 self.log.debug("Control received: %s", msg)
189 self.log.debug("Control received: %s", msg)
190
190
191 header = msg['header']
191 header = msg['header']
192 msg_id = header['msg_id']
192 msg_id = header['msg_id']
193 msg_type = header['msg_type']
193 msg_type = header['msg_type']
194
194
195 handler = self.control_handlers.get(msg_type, None)
195 handler = self.control_handlers.get(msg_type, None)
196 if handler is None:
196 if handler is None:
197 self.log.error("UNKNOWN CONTROL MESSAGE TYPE: %r", msg_type)
197 self.log.error("UNKNOWN CONTROL MESSAGE TYPE: %r", msg_type)
198 else:
198 else:
199 try:
199 try:
200 handler(self.control_stream, idents, msg)
200 handler(self.control_stream, idents, msg)
201 except Exception:
201 except Exception:
202 self.log.error("Exception in control handler:", exc_info=True)
202 self.log.error("Exception in control handler:", exc_info=True)
203
203
204 def dispatch_shell(self, stream, msg):
204 def dispatch_shell(self, stream, msg):
205 """dispatch shell requests"""
205 """dispatch shell requests"""
206 # flush control requests first
206 # flush control requests first
207 if self.control_stream:
207 if self.control_stream:
208 self.control_stream.flush()
208 self.control_stream.flush()
209
209
210 idents,msg = self.session.feed_identities(msg, copy=False)
210 idents,msg = self.session.feed_identities(msg, copy=False)
211 try:
211 try:
212 msg = self.session.unserialize(msg, content=True, copy=False)
212 msg = self.session.unserialize(msg, content=True, copy=False)
213 except:
213 except:
214 self.log.error("Invalid Message", exc_info=True)
214 self.log.error("Invalid Message", exc_info=True)
215 return
215 return
216
216
217 header = msg['header']
217 header = msg['header']
218 msg_id = header['msg_id']
218 msg_id = header['msg_id']
219 msg_type = msg['header']['msg_type']
219 msg_type = msg['header']['msg_type']
220
220
221 # Print some info about this message and leave a '--->' marker, so it's
221 # Print some info about this message and leave a '--->' marker, so it's
222 # easier to trace visually the message chain when debugging. Each
222 # easier to trace visually the message chain when debugging. Each
223 # handler prints its message at the end.
223 # handler prints its message at the end.
224 self.log.debug('\n*** MESSAGE TYPE:%s***', msg_type)
224 self.log.debug('\n*** MESSAGE TYPE:%s***', msg_type)
225 self.log.debug(' Content: %s\n --->\n ', msg['content'])
225 self.log.debug(' Content: %s\n --->\n ', msg['content'])
226
226
227 if msg_id in self.aborted:
227 if msg_id in self.aborted:
228 self.aborted.remove(msg_id)
228 self.aborted.remove(msg_id)
229 # is it safe to assume a msg_id will not be resubmitted?
229 # is it safe to assume a msg_id will not be resubmitted?
230 reply_type = msg_type.split('_')[0] + '_reply'
230 reply_type = msg_type.split('_')[0] + '_reply'
231 status = {'status' : 'aborted'}
231 status = {'status' : 'aborted'}
232 md = {'engine' : self.ident}
232 md = {'engine' : self.ident}
233 md.update(status)
233 md.update(status)
234 reply_msg = self.session.send(stream, reply_type, metadata=md,
234 reply_msg = self.session.send(stream, reply_type, metadata=md,
235 content=status, parent=msg, ident=idents)
235 content=status, parent=msg, ident=idents)
236 return
236 return
237
237
238 handler = self.shell_handlers.get(msg_type, None)
238 handler = self.shell_handlers.get(msg_type, None)
239 if handler is None:
239 if handler is None:
240 self.log.error("UNKNOWN MESSAGE TYPE: %r", msg_type)
240 self.log.error("UNKNOWN MESSAGE TYPE: %r", msg_type)
241 else:
241 else:
242 # ensure default_int_handler during handler call
242 # ensure default_int_handler during handler call
243 sig = signal(SIGINT, default_int_handler)
243 sig = signal(SIGINT, default_int_handler)
244 try:
244 try:
245 handler(stream, idents, msg)
245 handler(stream, idents, msg)
246 except Exception:
246 except Exception:
247 self.log.error("Exception in message handler:", exc_info=True)
247 self.log.error("Exception in message handler:", exc_info=True)
248 finally:
248 finally:
249 signal(SIGINT, sig)
249 signal(SIGINT, sig)
250
250
251 def enter_eventloop(self):
251 def enter_eventloop(self):
252 """enter eventloop"""
252 """enter eventloop"""
253 self.log.info("entering eventloop")
253 self.log.info("entering eventloop")
254 # restore default_int_handler
254 # restore default_int_handler
255 signal(SIGINT, default_int_handler)
255 signal(SIGINT, default_int_handler)
256 while self.eventloop is not None:
256 while self.eventloop is not None:
257 try:
257 try:
258 self.eventloop(self)
258 self.eventloop(self)
259 except KeyboardInterrupt:
259 except KeyboardInterrupt:
260 # Ctrl-C shouldn't crash the kernel
260 # Ctrl-C shouldn't crash the kernel
261 self.log.error("KeyboardInterrupt caught in kernel")
261 self.log.error("KeyboardInterrupt caught in kernel")
262 continue
262 continue
263 else:
263 else:
264 # eventloop exited cleanly, this means we should stop (right?)
264 # eventloop exited cleanly, this means we should stop (right?)
265 self.eventloop = None
265 self.eventloop = None
266 break
266 break
267 self.log.info("exiting eventloop")
267 self.log.info("exiting eventloop")
268
268
269 def start(self):
269 def start(self):
270 """register dispatchers for streams"""
270 """register dispatchers for streams"""
271 self.shell.exit_now = False
271 self.shell.exit_now = False
272 if self.control_stream:
272 if self.control_stream:
273 self.control_stream.on_recv(self.dispatch_control, copy=False)
273 self.control_stream.on_recv(self.dispatch_control, copy=False)
274
274
275 def make_dispatcher(stream):
275 def make_dispatcher(stream):
276 def dispatcher(msg):
276 def dispatcher(msg):
277 return self.dispatch_shell(stream, msg)
277 return self.dispatch_shell(stream, msg)
278 return dispatcher
278 return dispatcher
279
279
280 for s in self.shell_streams:
280 for s in self.shell_streams:
281 s.on_recv(make_dispatcher(s), copy=False)
281 s.on_recv(make_dispatcher(s), copy=False)
282
282
283 # publish idle status
283 # publish idle status
284 self._publish_status('starting')
284 self._publish_status('starting')
285
285
286 def do_one_iteration(self):
286 def do_one_iteration(self):
287 """step eventloop just once"""
287 """step eventloop just once"""
288 if self.control_stream:
288 if self.control_stream:
289 self.control_stream.flush()
289 self.control_stream.flush()
290 for stream in self.shell_streams:
290 for stream in self.shell_streams:
291 # handle at most one request per iteration
291 # handle at most one request per iteration
292 stream.flush(zmq.POLLIN, 1)
292 stream.flush(zmq.POLLIN, 1)
293 stream.flush(zmq.POLLOUT)
293 stream.flush(zmq.POLLOUT)
294
294
295
295
296 def record_ports(self, ports):
296 def record_ports(self, ports):
297 """Record the ports that this kernel is using.
297 """Record the ports that this kernel is using.
298
298
299 The creator of the Kernel instance must call this methods if they
299 The creator of the Kernel instance must call this methods if they
300 want the :meth:`connect_request` method to return the port numbers.
300 want the :meth:`connect_request` method to return the port numbers.
301 """
301 """
302 self._recorded_ports = ports
302 self._recorded_ports = ports
303
303
304 #---------------------------------------------------------------------------
304 #---------------------------------------------------------------------------
305 # Kernel request handlers
305 # Kernel request handlers
306 #---------------------------------------------------------------------------
306 #---------------------------------------------------------------------------
307
307
308 def _make_metadata(self, other=None):
308 def _make_metadata(self, other=None):
309 """init metadata dict, for execute/apply_reply"""
309 """init metadata dict, for execute/apply_reply"""
310 new_md = {
310 new_md = {
311 'dependencies_met' : True,
311 'dependencies_met' : True,
312 'engine' : self.ident,
312 'engine' : self.ident,
313 'started': datetime.now(),
313 'started': datetime.now(),
314 }
314 }
315 if other:
315 if other:
316 new_md.update(other)
316 new_md.update(other)
317 return new_md
317 return new_md
318
318
319 def _publish_pyin(self, code, parent, execution_count):
319 def _publish_pyin(self, code, parent, execution_count):
320 """Publish the code request on the pyin stream."""
320 """Publish the code request on the pyin stream."""
321
321
322 self.session.send(self.iopub_socket, u'pyin',
322 self.session.send(self.iopub_socket, u'pyin',
323 {u'code':code, u'execution_count': execution_count},
323 {u'code':code, u'execution_count': execution_count},
324 parent=parent, ident=self._topic('pyin')
324 parent=parent, ident=self._topic('pyin')
325 )
325 )
326
326
327 def _publish_status(self, status, parent=None):
327 def _publish_status(self, status, parent=None):
328 """send status (busy/idle) on IOPub"""
328 """send status (busy/idle) on IOPub"""
329 self.session.send(self.iopub_socket,
329 self.session.send(self.iopub_socket,
330 u'status',
330 u'status',
331 {u'execution_state': status},
331 {u'execution_state': status},
332 parent=parent,
332 parent=parent,
333 ident=self._topic('status'),
333 ident=self._topic('status'),
334 )
334 )
335
335
336
336
337 def execute_request(self, stream, ident, parent):
337 def execute_request(self, stream, ident, parent):
338 """handle an execute_request"""
338 """handle an execute_request"""
339
339
340 self._publish_status(u'busy', parent)
340 self._publish_status(u'busy', parent)
341
341
342 try:
342 try:
343 content = parent[u'content']
343 content = parent[u'content']
344 code = content[u'code']
344 code = py3compat.cast_unicode_py2(content[u'code'])
345 silent = content[u'silent']
345 silent = content[u'silent']
346 store_history = content.get(u'store_history', not silent)
346 store_history = content.get(u'store_history', not silent)
347 except:
347 except:
348 self.log.error("Got bad msg: ")
348 self.log.error("Got bad msg: ")
349 self.log.error("%s", parent)
349 self.log.error("%s", parent)
350 return
350 return
351
351
352 md = self._make_metadata(parent['metadata'])
352 md = self._make_metadata(parent['metadata'])
353
353
354 shell = self.shell # we'll need this a lot here
354 shell = self.shell # we'll need this a lot here
355
355
356 # Replace raw_input. Note that is not sufficient to replace
356 # Replace raw_input. Note that is not sufficient to replace
357 # raw_input in the user namespace.
357 # raw_input in the user namespace.
358 if content.get('allow_stdin', False):
358 if content.get('allow_stdin', False):
359 raw_input = lambda prompt='': self._raw_input(prompt, ident, parent)
359 raw_input = lambda prompt='': self._raw_input(prompt, ident, parent)
360 input = lambda prompt='': eval(raw_input(prompt))
360 input = lambda prompt='': eval(raw_input(prompt))
361 else:
361 else:
362 raw_input = input = lambda prompt='' : self._no_raw_input()
362 raw_input = input = lambda prompt='' : self._no_raw_input()
363
363
364 if py3compat.PY3:
364 if py3compat.PY3:
365 self._sys_raw_input = builtin_mod.input
365 self._sys_raw_input = builtin_mod.input
366 builtin_mod.input = raw_input
366 builtin_mod.input = raw_input
367 else:
367 else:
368 self._sys_raw_input = builtin_mod.raw_input
368 self._sys_raw_input = builtin_mod.raw_input
369 self._sys_eval_input = builtin_mod.input
369 self._sys_eval_input = builtin_mod.input
370 builtin_mod.raw_input = raw_input
370 builtin_mod.raw_input = raw_input
371 builtin_mod.input = input
371 builtin_mod.input = input
372
372
373 # Set the parent message of the display hook and out streams.
373 # Set the parent message of the display hook and out streams.
374 shell.set_parent(parent)
374 shell.set_parent(parent)
375
375
376 # Re-broadcast our input for the benefit of listening clients, and
376 # Re-broadcast our input for the benefit of listening clients, and
377 # start computing output
377 # start computing output
378 if not silent:
378 if not silent:
379 self._publish_pyin(code, parent, shell.execution_count)
379 self._publish_pyin(code, parent, shell.execution_count)
380
380
381 reply_content = {}
381 reply_content = {}
382 try:
382 try:
383 # FIXME: the shell calls the exception handler itself.
383 # FIXME: the shell calls the exception handler itself.
384 shell.run_cell(code, store_history=store_history, silent=silent)
384 shell.run_cell(code, store_history=store_history, silent=silent)
385 except:
385 except:
386 status = u'error'
386 status = u'error'
387 # FIXME: this code right now isn't being used yet by default,
387 # FIXME: this code right now isn't being used yet by default,
388 # because the run_cell() call above directly fires off exception
388 # because the run_cell() call above directly fires off exception
389 # reporting. This code, therefore, is only active in the scenario
389 # reporting. This code, therefore, is only active in the scenario
390 # where runlines itself has an unhandled exception. We need to
390 # where runlines itself has an unhandled exception. We need to
391 # uniformize this, for all exception construction to come from a
391 # uniformize this, for all exception construction to come from a
392 # single location in the codbase.
392 # single location in the codbase.
393 etype, evalue, tb = sys.exc_info()
393 etype, evalue, tb = sys.exc_info()
394 tb_list = traceback.format_exception(etype, evalue, tb)
394 tb_list = traceback.format_exception(etype, evalue, tb)
395 reply_content.update(shell._showtraceback(etype, evalue, tb_list))
395 reply_content.update(shell._showtraceback(etype, evalue, tb_list))
396 else:
396 else:
397 status = u'ok'
397 status = u'ok'
398 finally:
398 finally:
399 # Restore raw_input.
399 # Restore raw_input.
400 if py3compat.PY3:
400 if py3compat.PY3:
401 builtin_mod.input = self._sys_raw_input
401 builtin_mod.input = self._sys_raw_input
402 else:
402 else:
403 builtin_mod.raw_input = self._sys_raw_input
403 builtin_mod.raw_input = self._sys_raw_input
404 builtin_mod.input = self._sys_eval_input
404 builtin_mod.input = self._sys_eval_input
405
405
406 reply_content[u'status'] = status
406 reply_content[u'status'] = status
407
407
408 # Return the execution counter so clients can display prompts
408 # Return the execution counter so clients can display prompts
409 reply_content['execution_count'] = shell.execution_count - 1
409 reply_content['execution_count'] = shell.execution_count - 1
410
410
411 # FIXME - fish exception info out of shell, possibly left there by
411 # FIXME - fish exception info out of shell, possibly left there by
412 # runlines. We'll need to clean up this logic later.
412 # runlines. We'll need to clean up this logic later.
413 if shell._reply_content is not None:
413 if shell._reply_content is not None:
414 reply_content.update(shell._reply_content)
414 reply_content.update(shell._reply_content)
415 e_info = dict(engine_uuid=self.ident, engine_id=self.int_id, method='execute')
415 e_info = dict(engine_uuid=self.ident, engine_id=self.int_id, method='execute')
416 reply_content['engine_info'] = e_info
416 reply_content['engine_info'] = e_info
417 # reset after use
417 # reset after use
418 shell._reply_content = None
418 shell._reply_content = None
419
419
420 if 'traceback' in reply_content:
420 if 'traceback' in reply_content:
421 self.log.info("Exception in execute request:\n%s", '\n'.join(reply_content['traceback']))
421 self.log.info("Exception in execute request:\n%s", '\n'.join(reply_content['traceback']))
422
422
423
423
424 # At this point, we can tell whether the main code execution succeeded
424 # At this point, we can tell whether the main code execution succeeded
425 # or not. If it did, we proceed to evaluate user_variables/expressions
425 # or not. If it did, we proceed to evaluate user_variables/expressions
426 if reply_content['status'] == 'ok':
426 if reply_content['status'] == 'ok':
427 reply_content[u'user_variables'] = \
427 reply_content[u'user_variables'] = \
428 shell.user_variables(content.get(u'user_variables', []))
428 shell.user_variables(content.get(u'user_variables', []))
429 reply_content[u'user_expressions'] = \
429 reply_content[u'user_expressions'] = \
430 shell.user_expressions(content.get(u'user_expressions', {}))
430 shell.user_expressions(content.get(u'user_expressions', {}))
431 else:
431 else:
432 # If there was an error, don't even try to compute variables or
432 # If there was an error, don't even try to compute variables or
433 # expressions
433 # expressions
434 reply_content[u'user_variables'] = {}
434 reply_content[u'user_variables'] = {}
435 reply_content[u'user_expressions'] = {}
435 reply_content[u'user_expressions'] = {}
436
436
437 # Payloads should be retrieved regardless of outcome, so we can both
437 # Payloads should be retrieved regardless of outcome, so we can both
438 # recover partial output (that could have been generated early in a
438 # recover partial output (that could have been generated early in a
439 # block, before an error) and clear the payload system always.
439 # block, before an error) and clear the payload system always.
440 reply_content[u'payload'] = shell.payload_manager.read_payload()
440 reply_content[u'payload'] = shell.payload_manager.read_payload()
441 # Be agressive about clearing the payload because we don't want
441 # Be agressive about clearing the payload because we don't want
442 # it to sit in memory until the next execute_request comes in.
442 # it to sit in memory until the next execute_request comes in.
443 shell.payload_manager.clear_payload()
443 shell.payload_manager.clear_payload()
444
444
445 # Flush output before sending the reply.
445 # Flush output before sending the reply.
446 sys.stdout.flush()
446 sys.stdout.flush()
447 sys.stderr.flush()
447 sys.stderr.flush()
448 # FIXME: on rare occasions, the flush doesn't seem to make it to the
448 # FIXME: on rare occasions, the flush doesn't seem to make it to the
449 # clients... This seems to mitigate the problem, but we definitely need
449 # clients... This seems to mitigate the problem, but we definitely need
450 # to better understand what's going on.
450 # to better understand what's going on.
451 if self._execute_sleep:
451 if self._execute_sleep:
452 time.sleep(self._execute_sleep)
452 time.sleep(self._execute_sleep)
453
453
454 # Send the reply.
454 # Send the reply.
455 reply_content = json_clean(reply_content)
455 reply_content = json_clean(reply_content)
456
456
457 md['status'] = reply_content['status']
457 md['status'] = reply_content['status']
458 if reply_content['status'] == 'error' and \
458 if reply_content['status'] == 'error' and \
459 reply_content['ename'] == 'UnmetDependency':
459 reply_content['ename'] == 'UnmetDependency':
460 md['dependencies_met'] = False
460 md['dependencies_met'] = False
461
461
462 reply_msg = self.session.send(stream, u'execute_reply',
462 reply_msg = self.session.send(stream, u'execute_reply',
463 reply_content, parent, metadata=md,
463 reply_content, parent, metadata=md,
464 ident=ident)
464 ident=ident)
465
465
466 self.log.debug("%s", reply_msg)
466 self.log.debug("%s", reply_msg)
467
467
468 if not silent and reply_msg['content']['status'] == u'error':
468 if not silent and reply_msg['content']['status'] == u'error':
469 self._abort_queues()
469 self._abort_queues()
470
470
471 self._publish_status(u'idle', parent)
471 self._publish_status(u'idle', parent)
472
472
473 def complete_request(self, stream, ident, parent):
473 def complete_request(self, stream, ident, parent):
474 txt, matches = self._complete(parent)
474 txt, matches = self._complete(parent)
475 matches = {'matches' : matches,
475 matches = {'matches' : matches,
476 'matched_text' : txt,
476 'matched_text' : txt,
477 'status' : 'ok'}
477 'status' : 'ok'}
478 matches = json_clean(matches)
478 matches = json_clean(matches)
479 completion_msg = self.session.send(stream, 'complete_reply',
479 completion_msg = self.session.send(stream, 'complete_reply',
480 matches, parent, ident)
480 matches, parent, ident)
481 self.log.debug("%s", completion_msg)
481 self.log.debug("%s", completion_msg)
482
482
483 def object_info_request(self, stream, ident, parent):
483 def object_info_request(self, stream, ident, parent):
484 content = parent['content']
484 content = parent['content']
485 object_info = self.shell.object_inspect(content['oname'],
485 object_info = self.shell.object_inspect(content['oname'],
486 detail_level = content.get('detail_level', 0)
486 detail_level = content.get('detail_level', 0)
487 )
487 )
488 # Before we send this object over, we scrub it for JSON usage
488 # Before we send this object over, we scrub it for JSON usage
489 oinfo = json_clean(object_info)
489 oinfo = json_clean(object_info)
490 msg = self.session.send(stream, 'object_info_reply',
490 msg = self.session.send(stream, 'object_info_reply',
491 oinfo, parent, ident)
491 oinfo, parent, ident)
492 self.log.debug("%s", msg)
492 self.log.debug("%s", msg)
493
493
494 def history_request(self, stream, ident, parent):
494 def history_request(self, stream, ident, parent):
495 # We need to pull these out, as passing **kwargs doesn't work with
495 # We need to pull these out, as passing **kwargs doesn't work with
496 # unicode keys before Python 2.6.5.
496 # unicode keys before Python 2.6.5.
497 hist_access_type = parent['content']['hist_access_type']
497 hist_access_type = parent['content']['hist_access_type']
498 raw = parent['content']['raw']
498 raw = parent['content']['raw']
499 output = parent['content']['output']
499 output = parent['content']['output']
500 if hist_access_type == 'tail':
500 if hist_access_type == 'tail':
501 n = parent['content']['n']
501 n = parent['content']['n']
502 hist = self.shell.history_manager.get_tail(n, raw=raw, output=output,
502 hist = self.shell.history_manager.get_tail(n, raw=raw, output=output,
503 include_latest=True)
503 include_latest=True)
504
504
505 elif hist_access_type == 'range':
505 elif hist_access_type == 'range':
506 session = parent['content']['session']
506 session = parent['content']['session']
507 start = parent['content']['start']
507 start = parent['content']['start']
508 stop = parent['content']['stop']
508 stop = parent['content']['stop']
509 hist = self.shell.history_manager.get_range(session, start, stop,
509 hist = self.shell.history_manager.get_range(session, start, stop,
510 raw=raw, output=output)
510 raw=raw, output=output)
511
511
512 elif hist_access_type == 'search':
512 elif hist_access_type == 'search':
513 n = parent['content'].get('n')
513 n = parent['content'].get('n')
514 unique = parent['content'].get('unique', False)
514 unique = parent['content'].get('unique', False)
515 pattern = parent['content']['pattern']
515 pattern = parent['content']['pattern']
516 hist = self.shell.history_manager.search(
516 hist = self.shell.history_manager.search(
517 pattern, raw=raw, output=output, n=n, unique=unique)
517 pattern, raw=raw, output=output, n=n, unique=unique)
518
518
519 else:
519 else:
520 hist = []
520 hist = []
521 hist = list(hist)
521 hist = list(hist)
522 content = {'history' : hist}
522 content = {'history' : hist}
523 content = json_clean(content)
523 content = json_clean(content)
524 msg = self.session.send(stream, 'history_reply',
524 msg = self.session.send(stream, 'history_reply',
525 content, parent, ident)
525 content, parent, ident)
526 self.log.debug("Sending history reply with %i entries", len(hist))
526 self.log.debug("Sending history reply with %i entries", len(hist))
527
527
528 def connect_request(self, stream, ident, parent):
528 def connect_request(self, stream, ident, parent):
529 if self._recorded_ports is not None:
529 if self._recorded_ports is not None:
530 content = self._recorded_ports.copy()
530 content = self._recorded_ports.copy()
531 else:
531 else:
532 content = {}
532 content = {}
533 msg = self.session.send(stream, 'connect_reply',
533 msg = self.session.send(stream, 'connect_reply',
534 content, parent, ident)
534 content, parent, ident)
535 self.log.debug("%s", msg)
535 self.log.debug("%s", msg)
536
536
537 def kernel_info_request(self, stream, ident, parent):
537 def kernel_info_request(self, stream, ident, parent):
538 vinfo = {
538 vinfo = {
539 'protocol_version': protocol_version,
539 'protocol_version': protocol_version,
540 'ipython_version': ipython_version,
540 'ipython_version': ipython_version,
541 'language_version': language_version,
541 'language_version': language_version,
542 'language': 'python',
542 'language': 'python',
543 }
543 }
544 msg = self.session.send(stream, 'kernel_info_reply',
544 msg = self.session.send(stream, 'kernel_info_reply',
545 vinfo, parent, ident)
545 vinfo, parent, ident)
546 self.log.debug("%s", msg)
546 self.log.debug("%s", msg)
547
547
548 def shutdown_request(self, stream, ident, parent):
548 def shutdown_request(self, stream, ident, parent):
549 self.shell.exit_now = True
549 self.shell.exit_now = True
550 content = dict(status='ok')
550 content = dict(status='ok')
551 content.update(parent['content'])
551 content.update(parent['content'])
552 self.session.send(stream, u'shutdown_reply', content, parent, ident=ident)
552 self.session.send(stream, u'shutdown_reply', content, parent, ident=ident)
553 # same content, but different msg_id for broadcasting on IOPub
553 # same content, but different msg_id for broadcasting on IOPub
554 self._shutdown_message = self.session.msg(u'shutdown_reply',
554 self._shutdown_message = self.session.msg(u'shutdown_reply',
555 content, parent
555 content, parent
556 )
556 )
557
557
558 self._at_shutdown()
558 self._at_shutdown()
559 # call sys.exit after a short delay
559 # call sys.exit after a short delay
560 loop = ioloop.IOLoop.instance()
560 loop = ioloop.IOLoop.instance()
561 loop.add_timeout(time.time()+0.1, loop.stop)
561 loop.add_timeout(time.time()+0.1, loop.stop)
562
562
563 #---------------------------------------------------------------------------
563 #---------------------------------------------------------------------------
564 # Engine methods
564 # Engine methods
565 #---------------------------------------------------------------------------
565 #---------------------------------------------------------------------------
566
566
567 def apply_request(self, stream, ident, parent):
567 def apply_request(self, stream, ident, parent):
568 try:
568 try:
569 content = parent[u'content']
569 content = parent[u'content']
570 bufs = parent[u'buffers']
570 bufs = parent[u'buffers']
571 msg_id = parent['header']['msg_id']
571 msg_id = parent['header']['msg_id']
572 except:
572 except:
573 self.log.error("Got bad msg: %s", parent, exc_info=True)
573 self.log.error("Got bad msg: %s", parent, exc_info=True)
574 return
574 return
575
575
576 self._publish_status(u'busy', parent)
576 self._publish_status(u'busy', parent)
577
577
578 # Set the parent message of the display hook and out streams.
578 # Set the parent message of the display hook and out streams.
579 shell = self.shell
579 shell = self.shell
580 shell.set_parent(parent)
580 shell.set_parent(parent)
581
581
582 # pyin_msg = self.session.msg(u'pyin',{u'code':code}, parent=parent)
582 # pyin_msg = self.session.msg(u'pyin',{u'code':code}, parent=parent)
583 # self.iopub_socket.send(pyin_msg)
583 # self.iopub_socket.send(pyin_msg)
584 # self.session.send(self.iopub_socket, u'pyin', {u'code':code},parent=parent)
584 # self.session.send(self.iopub_socket, u'pyin', {u'code':code},parent=parent)
585 md = self._make_metadata(parent['metadata'])
585 md = self._make_metadata(parent['metadata'])
586 try:
586 try:
587 working = shell.user_ns
587 working = shell.user_ns
588
588
589 prefix = "_"+str(msg_id).replace("-","")+"_"
589 prefix = "_"+str(msg_id).replace("-","")+"_"
590
590
591 f,args,kwargs = unpack_apply_message(bufs, working, copy=False)
591 f,args,kwargs = unpack_apply_message(bufs, working, copy=False)
592
592
593 fname = getattr(f, '__name__', 'f')
593 fname = getattr(f, '__name__', 'f')
594
594
595 fname = prefix+"f"
595 fname = prefix+"f"
596 argname = prefix+"args"
596 argname = prefix+"args"
597 kwargname = prefix+"kwargs"
597 kwargname = prefix+"kwargs"
598 resultname = prefix+"result"
598 resultname = prefix+"result"
599
599
600 ns = { fname : f, argname : args, kwargname : kwargs , resultname : None }
600 ns = { fname : f, argname : args, kwargname : kwargs , resultname : None }
601 # print ns
601 # print ns
602 working.update(ns)
602 working.update(ns)
603 code = "%s = %s(*%s,**%s)" % (resultname, fname, argname, kwargname)
603 code = "%s = %s(*%s,**%s)" % (resultname, fname, argname, kwargname)
604 try:
604 try:
605 exec(code, shell.user_global_ns, shell.user_ns)
605 exec(code, shell.user_global_ns, shell.user_ns)
606 result = working.get(resultname)
606 result = working.get(resultname)
607 finally:
607 finally:
608 for key in ns:
608 for key in ns:
609 working.pop(key)
609 working.pop(key)
610
610
611 result_buf = serialize_object(result,
611 result_buf = serialize_object(result,
612 buffer_threshold=self.session.buffer_threshold,
612 buffer_threshold=self.session.buffer_threshold,
613 item_threshold=self.session.item_threshold,
613 item_threshold=self.session.item_threshold,
614 )
614 )
615
615
616 except:
616 except:
617 # invoke IPython traceback formatting
617 # invoke IPython traceback formatting
618 shell.showtraceback()
618 shell.showtraceback()
619 # FIXME - fish exception info out of shell, possibly left there by
619 # FIXME - fish exception info out of shell, possibly left there by
620 # run_code. We'll need to clean up this logic later.
620 # run_code. We'll need to clean up this logic later.
621 reply_content = {}
621 reply_content = {}
622 if shell._reply_content is not None:
622 if shell._reply_content is not None:
623 reply_content.update(shell._reply_content)
623 reply_content.update(shell._reply_content)
624 e_info = dict(engine_uuid=self.ident, engine_id=self.int_id, method='apply')
624 e_info = dict(engine_uuid=self.ident, engine_id=self.int_id, method='apply')
625 reply_content['engine_info'] = e_info
625 reply_content['engine_info'] = e_info
626 # reset after use
626 # reset after use
627 shell._reply_content = None
627 shell._reply_content = None
628
628
629 self.session.send(self.iopub_socket, u'pyerr', reply_content, parent=parent,
629 self.session.send(self.iopub_socket, u'pyerr', reply_content, parent=parent,
630 ident=self._topic('pyerr'))
630 ident=self._topic('pyerr'))
631 self.log.info("Exception in apply request:\n%s", '\n'.join(reply_content['traceback']))
631 self.log.info("Exception in apply request:\n%s", '\n'.join(reply_content['traceback']))
632 result_buf = []
632 result_buf = []
633
633
634 if reply_content['ename'] == 'UnmetDependency':
634 if reply_content['ename'] == 'UnmetDependency':
635 md['dependencies_met'] = False
635 md['dependencies_met'] = False
636 else:
636 else:
637 reply_content = {'status' : 'ok'}
637 reply_content = {'status' : 'ok'}
638
638
639 # put 'ok'/'error' status in header, for scheduler introspection:
639 # put 'ok'/'error' status in header, for scheduler introspection:
640 md['status'] = reply_content['status']
640 md['status'] = reply_content['status']
641
641
642 # flush i/o
642 # flush i/o
643 sys.stdout.flush()
643 sys.stdout.flush()
644 sys.stderr.flush()
644 sys.stderr.flush()
645
645
646 reply_msg = self.session.send(stream, u'apply_reply', reply_content,
646 reply_msg = self.session.send(stream, u'apply_reply', reply_content,
647 parent=parent, ident=ident,buffers=result_buf, metadata=md)
647 parent=parent, ident=ident,buffers=result_buf, metadata=md)
648
648
649 self._publish_status(u'idle', parent)
649 self._publish_status(u'idle', parent)
650
650
651 #---------------------------------------------------------------------------
651 #---------------------------------------------------------------------------
652 # Control messages
652 # Control messages
653 #---------------------------------------------------------------------------
653 #---------------------------------------------------------------------------
654
654
655 def abort_request(self, stream, ident, parent):
655 def abort_request(self, stream, ident, parent):
656 """abort a specifig msg by id"""
656 """abort a specifig msg by id"""
657 msg_ids = parent['content'].get('msg_ids', None)
657 msg_ids = parent['content'].get('msg_ids', None)
658 if isinstance(msg_ids, string_types):
658 if isinstance(msg_ids, string_types):
659 msg_ids = [msg_ids]
659 msg_ids = [msg_ids]
660 if not msg_ids:
660 if not msg_ids:
661 self.abort_queues()
661 self.abort_queues()
662 for mid in msg_ids:
662 for mid in msg_ids:
663 self.aborted.add(str(mid))
663 self.aborted.add(str(mid))
664
664
665 content = dict(status='ok')
665 content = dict(status='ok')
666 reply_msg = self.session.send(stream, 'abort_reply', content=content,
666 reply_msg = self.session.send(stream, 'abort_reply', content=content,
667 parent=parent, ident=ident)
667 parent=parent, ident=ident)
668 self.log.debug("%s", reply_msg)
668 self.log.debug("%s", reply_msg)
669
669
670 def clear_request(self, stream, idents, parent):
670 def clear_request(self, stream, idents, parent):
671 """Clear our namespace."""
671 """Clear our namespace."""
672 self.shell.reset(False)
672 self.shell.reset(False)
673 msg = self.session.send(stream, 'clear_reply', ident=idents, parent=parent,
673 msg = self.session.send(stream, 'clear_reply', ident=idents, parent=parent,
674 content = dict(status='ok'))
674 content = dict(status='ok'))
675
675
676
676
677 #---------------------------------------------------------------------------
677 #---------------------------------------------------------------------------
678 # Protected interface
678 # Protected interface
679 #---------------------------------------------------------------------------
679 #---------------------------------------------------------------------------
680
680
681 def _wrap_exception(self, method=None):
681 def _wrap_exception(self, method=None):
682 # import here, because _wrap_exception is only used in parallel,
682 # import here, because _wrap_exception is only used in parallel,
683 # and parallel has higher min pyzmq version
683 # and parallel has higher min pyzmq version
684 from IPython.parallel.error import wrap_exception
684 from IPython.parallel.error import wrap_exception
685 e_info = dict(engine_uuid=self.ident, engine_id=self.int_id, method=method)
685 e_info = dict(engine_uuid=self.ident, engine_id=self.int_id, method=method)
686 content = wrap_exception(e_info)
686 content = wrap_exception(e_info)
687 return content
687 return content
688
688
689 def _topic(self, topic):
689 def _topic(self, topic):
690 """prefixed topic for IOPub messages"""
690 """prefixed topic for IOPub messages"""
691 if self.int_id >= 0:
691 if self.int_id >= 0:
692 base = "engine.%i" % self.int_id
692 base = "engine.%i" % self.int_id
693 else:
693 else:
694 base = "kernel.%s" % self.ident
694 base = "kernel.%s" % self.ident
695
695
696 return py3compat.cast_bytes("%s.%s" % (base, topic))
696 return py3compat.cast_bytes("%s.%s" % (base, topic))
697
697
698 def _abort_queues(self):
698 def _abort_queues(self):
699 for stream in self.shell_streams:
699 for stream in self.shell_streams:
700 if stream:
700 if stream:
701 self._abort_queue(stream)
701 self._abort_queue(stream)
702
702
703 def _abort_queue(self, stream):
703 def _abort_queue(self, stream):
704 poller = zmq.Poller()
704 poller = zmq.Poller()
705 poller.register(stream.socket, zmq.POLLIN)
705 poller.register(stream.socket, zmq.POLLIN)
706 while True:
706 while True:
707 idents,msg = self.session.recv(stream, zmq.NOBLOCK, content=True)
707 idents,msg = self.session.recv(stream, zmq.NOBLOCK, content=True)
708 if msg is None:
708 if msg is None:
709 return
709 return
710
710
711 self.log.info("Aborting:")
711 self.log.info("Aborting:")
712 self.log.info("%s", msg)
712 self.log.info("%s", msg)
713 msg_type = msg['header']['msg_type']
713 msg_type = msg['header']['msg_type']
714 reply_type = msg_type.split('_')[0] + '_reply'
714 reply_type = msg_type.split('_')[0] + '_reply'
715
715
716 status = {'status' : 'aborted'}
716 status = {'status' : 'aborted'}
717 md = {'engine' : self.ident}
717 md = {'engine' : self.ident}
718 md.update(status)
718 md.update(status)
719 reply_msg = self.session.send(stream, reply_type, metadata=md,
719 reply_msg = self.session.send(stream, reply_type, metadata=md,
720 content=status, parent=msg, ident=idents)
720 content=status, parent=msg, ident=idents)
721 self.log.debug("%s", reply_msg)
721 self.log.debug("%s", reply_msg)
722 # We need to wait a bit for requests to come in. This can probably
722 # We need to wait a bit for requests to come in. This can probably
723 # be set shorter for true asynchronous clients.
723 # be set shorter for true asynchronous clients.
724 poller.poll(50)
724 poller.poll(50)
725
725
726
726
727 def _no_raw_input(self):
727 def _no_raw_input(self):
728 """Raise StdinNotImplentedError if active frontend doesn't support
728 """Raise StdinNotImplentedError if active frontend doesn't support
729 stdin."""
729 stdin."""
730 raise StdinNotImplementedError("raw_input was called, but this "
730 raise StdinNotImplementedError("raw_input was called, but this "
731 "frontend does not support stdin.")
731 "frontend does not support stdin.")
732
732
733 def _raw_input(self, prompt, ident, parent):
733 def _raw_input(self, prompt, ident, parent):
734 # Flush output before making the request.
734 # Flush output before making the request.
735 sys.stderr.flush()
735 sys.stderr.flush()
736 sys.stdout.flush()
736 sys.stdout.flush()
737 # flush the stdin socket, to purge stale replies
737 # flush the stdin socket, to purge stale replies
738 while True:
738 while True:
739 try:
739 try:
740 self.stdin_socket.recv_multipart(zmq.NOBLOCK)
740 self.stdin_socket.recv_multipart(zmq.NOBLOCK)
741 except zmq.ZMQError as e:
741 except zmq.ZMQError as e:
742 if e.errno == zmq.EAGAIN:
742 if e.errno == zmq.EAGAIN:
743 break
743 break
744 else:
744 else:
745 raise
745 raise
746
746
747 # Send the input request.
747 # Send the input request.
748 content = json_clean(dict(prompt=prompt))
748 content = json_clean(dict(prompt=prompt))
749 self.session.send(self.stdin_socket, u'input_request', content, parent,
749 self.session.send(self.stdin_socket, u'input_request', content, parent,
750 ident=ident)
750 ident=ident)
751
751
752 # Await a response.
752 # Await a response.
753 while True:
753 while True:
754 try:
754 try:
755 ident, reply = self.session.recv(self.stdin_socket, 0)
755 ident, reply = self.session.recv(self.stdin_socket, 0)
756 except Exception:
756 except Exception:
757 self.log.warn("Invalid Message:", exc_info=True)
757 self.log.warn("Invalid Message:", exc_info=True)
758 except KeyboardInterrupt:
758 except KeyboardInterrupt:
759 # re-raise KeyboardInterrupt, to truncate traceback
759 # re-raise KeyboardInterrupt, to truncate traceback
760 raise KeyboardInterrupt
760 raise KeyboardInterrupt
761 else:
761 else:
762 break
762 break
763 try:
763 try:
764 value = py3compat.unicode_to_str(reply['content']['value'])
764 value = py3compat.unicode_to_str(reply['content']['value'])
765 except:
765 except:
766 self.log.error("Got bad raw_input reply: ")
766 self.log.error("Got bad raw_input reply: ")
767 self.log.error("%s", parent)
767 self.log.error("%s", parent)
768 value = ''
768 value = ''
769 if value == '\x04':
769 if value == '\x04':
770 # EOF
770 # EOF
771 raise EOFError
771 raise EOFError
772 return value
772 return value
773
773
774 def _complete(self, msg):
774 def _complete(self, msg):
775 c = msg['content']
775 c = msg['content']
776 try:
776 try:
777 cpos = int(c['cursor_pos'])
777 cpos = int(c['cursor_pos'])
778 except:
778 except:
779 # If we don't get something that we can convert to an integer, at
779 # If we don't get something that we can convert to an integer, at
780 # least attempt the completion guessing the cursor is at the end of
780 # least attempt the completion guessing the cursor is at the end of
781 # the text, if there's any, and otherwise of the line
781 # the text, if there's any, and otherwise of the line
782 cpos = len(c['text'])
782 cpos = len(c['text'])
783 if cpos==0:
783 if cpos==0:
784 cpos = len(c['line'])
784 cpos = len(c['line'])
785 return self.shell.complete(c['text'], c['line'], cpos)
785 return self.shell.complete(c['text'], c['line'], cpos)
786
786
787 def _at_shutdown(self):
787 def _at_shutdown(self):
788 """Actions taken at shutdown by the kernel, called by python's atexit.
788 """Actions taken at shutdown by the kernel, called by python's atexit.
789 """
789 """
790 # io.rprint("Kernel at_shutdown") # dbg
790 # io.rprint("Kernel at_shutdown") # dbg
791 if self._shutdown_message is not None:
791 if self._shutdown_message is not None:
792 self.session.send(self.iopub_socket, self._shutdown_message, ident=self._topic('shutdown'))
792 self.session.send(self.iopub_socket, self._shutdown_message, ident=self._topic('shutdown'))
793 self.log.debug("%s", self._shutdown_message)
793 self.log.debug("%s", self._shutdown_message)
794 [ s.flush(zmq.POLLOUT) for s in self.shell_streams ]
794 [ s.flush(zmq.POLLOUT) for s in self.shell_streams ]
795
795
@@ -1,242 +1,244 b''
1 # coding: utf-8
1 # coding: utf-8
2 """Compatibility tricks for Python 3. Mainly to do with unicode."""
2 """Compatibility tricks for Python 3. Mainly to do with unicode."""
3 import functools
3 import functools
4 import os
4 import os
5 import sys
5 import sys
6 import re
6 import re
7 import types
7 import types
8
8
9 from .encoding import DEFAULT_ENCODING
9 from .encoding import DEFAULT_ENCODING
10
10
11 orig_open = open
11 orig_open = open
12
12
13 def no_code(x, encoding=None):
13 def no_code(x, encoding=None):
14 return x
14 return x
15
15
16 def decode(s, encoding=None):
16 def decode(s, encoding=None):
17 encoding = encoding or DEFAULT_ENCODING
17 encoding = encoding or DEFAULT_ENCODING
18 return s.decode(encoding, "replace")
18 return s.decode(encoding, "replace")
19
19
20 def encode(u, encoding=None):
20 def encode(u, encoding=None):
21 encoding = encoding or DEFAULT_ENCODING
21 encoding = encoding or DEFAULT_ENCODING
22 return u.encode(encoding, "replace")
22 return u.encode(encoding, "replace")
23
23
24
24
25 def cast_unicode(s, encoding=None):
25 def cast_unicode(s, encoding=None):
26 if isinstance(s, bytes):
26 if isinstance(s, bytes):
27 return decode(s, encoding)
27 return decode(s, encoding)
28 return s
28 return s
29
29
30 def cast_bytes(s, encoding=None):
30 def cast_bytes(s, encoding=None):
31 if not isinstance(s, bytes):
31 if not isinstance(s, bytes):
32 return encode(s, encoding)
32 return encode(s, encoding)
33 return s
33 return s
34
34
35 def _modify_str_or_docstring(str_change_func):
35 def _modify_str_or_docstring(str_change_func):
36 @functools.wraps(str_change_func)
36 @functools.wraps(str_change_func)
37 def wrapper(func_or_str):
37 def wrapper(func_or_str):
38 if isinstance(func_or_str, string_types):
38 if isinstance(func_or_str, string_types):
39 func = None
39 func = None
40 doc = func_or_str
40 doc = func_or_str
41 else:
41 else:
42 func = func_or_str
42 func = func_or_str
43 doc = func.__doc__
43 doc = func.__doc__
44
44
45 doc = str_change_func(doc)
45 doc = str_change_func(doc)
46
46
47 if func:
47 if func:
48 func.__doc__ = doc
48 func.__doc__ = doc
49 return func
49 return func
50 return doc
50 return doc
51 return wrapper
51 return wrapper
52
52
53 def safe_unicode(e):
53 def safe_unicode(e):
54 """unicode(e) with various fallbacks. Used for exceptions, which may not be
54 """unicode(e) with various fallbacks. Used for exceptions, which may not be
55 safe to call unicode() on.
55 safe to call unicode() on.
56 """
56 """
57 try:
57 try:
58 return unicode_type(e)
58 return unicode_type(e)
59 except UnicodeError:
59 except UnicodeError:
60 pass
60 pass
61
61
62 try:
62 try:
63 return str_to_unicode(str(e))
63 return str_to_unicode(str(e))
64 except UnicodeError:
64 except UnicodeError:
65 pass
65 pass
66
66
67 try:
67 try:
68 return str_to_unicode(repr(e))
68 return str_to_unicode(repr(e))
69 except UnicodeError:
69 except UnicodeError:
70 pass
70 pass
71
71
72 return u'Unrecoverably corrupt evalue'
72 return u'Unrecoverably corrupt evalue'
73
73
74 if sys.version_info[0] >= 3:
74 if sys.version_info[0] >= 3:
75 PY3 = True
75 PY3 = True
76
76
77 input = input
77 input = input
78 builtin_mod_name = "builtins"
78 builtin_mod_name = "builtins"
79 import builtins as builtin_mod
79 import builtins as builtin_mod
80
80
81 str_to_unicode = no_code
81 str_to_unicode = no_code
82 unicode_to_str = no_code
82 unicode_to_str = no_code
83 str_to_bytes = encode
83 str_to_bytes = encode
84 bytes_to_str = decode
84 bytes_to_str = decode
85 cast_bytes_py2 = no_code
85 cast_bytes_py2 = no_code
86 cast_unicode_py2 = no_code
86
87
87 string_types = (str,)
88 string_types = (str,)
88 unicode_type = str
89 unicode_type = str
89
90
90 def isidentifier(s, dotted=False):
91 def isidentifier(s, dotted=False):
91 if dotted:
92 if dotted:
92 return all(isidentifier(a) for a in s.split("."))
93 return all(isidentifier(a) for a in s.split("."))
93 return s.isidentifier()
94 return s.isidentifier()
94
95
95 open = orig_open
96 open = orig_open
96 xrange = range
97 xrange = range
97 def iteritems(d): return iter(d.items())
98 def iteritems(d): return iter(d.items())
98 def itervalues(d): return iter(d.values())
99 def itervalues(d): return iter(d.values())
99 getcwd = os.getcwd
100 getcwd = os.getcwd
100
101
101 MethodType = types.MethodType
102 MethodType = types.MethodType
102
103
103 def execfile(fname, glob, loc=None):
104 def execfile(fname, glob, loc=None):
104 loc = loc if (loc is not None) else glob
105 loc = loc if (loc is not None) else glob
105 with open(fname, 'rb') as f:
106 with open(fname, 'rb') as f:
106 exec(compile(f.read(), fname, 'exec'), glob, loc)
107 exec(compile(f.read(), fname, 'exec'), glob, loc)
107
108
108 # Refactor print statements in doctests.
109 # Refactor print statements in doctests.
109 _print_statement_re = re.compile(r"\bprint (?P<expr>.*)$", re.MULTILINE)
110 _print_statement_re = re.compile(r"\bprint (?P<expr>.*)$", re.MULTILINE)
110 def _print_statement_sub(match):
111 def _print_statement_sub(match):
111 expr = match.groups('expr')
112 expr = match.groups('expr')
112 return "print(%s)" % expr
113 return "print(%s)" % expr
113
114
114 @_modify_str_or_docstring
115 @_modify_str_or_docstring
115 def doctest_refactor_print(doc):
116 def doctest_refactor_print(doc):
116 """Refactor 'print x' statements in a doctest to print(x) style. 2to3
117 """Refactor 'print x' statements in a doctest to print(x) style. 2to3
117 unfortunately doesn't pick up on our doctests.
118 unfortunately doesn't pick up on our doctests.
118
119
119 Can accept a string or a function, so it can be used as a decorator."""
120 Can accept a string or a function, so it can be used as a decorator."""
120 return _print_statement_re.sub(_print_statement_sub, doc)
121 return _print_statement_re.sub(_print_statement_sub, doc)
121
122
122 # Abstract u'abc' syntax:
123 # Abstract u'abc' syntax:
123 @_modify_str_or_docstring
124 @_modify_str_or_docstring
124 def u_format(s):
125 def u_format(s):
125 """"{u}'abc'" --> "'abc'" (Python 3)
126 """"{u}'abc'" --> "'abc'" (Python 3)
126
127
127 Accepts a string or a function, so it can be used as a decorator."""
128 Accepts a string or a function, so it can be used as a decorator."""
128 return s.format(u='')
129 return s.format(u='')
129
130
130 else:
131 else:
131 PY3 = False
132 PY3 = False
132
133
133 input = raw_input
134 input = raw_input
134 builtin_mod_name = "__builtin__"
135 builtin_mod_name = "__builtin__"
135 import __builtin__ as builtin_mod
136 import __builtin__ as builtin_mod
136
137
137 str_to_unicode = decode
138 str_to_unicode = decode
138 unicode_to_str = encode
139 unicode_to_str = encode
139 str_to_bytes = no_code
140 str_to_bytes = no_code
140 bytes_to_str = no_code
141 bytes_to_str = no_code
141 cast_bytes_py2 = cast_bytes
142 cast_bytes_py2 = cast_bytes
143 cast_unicode_py2 = cast_unicode
142
144
143 string_types = (str, unicode)
145 string_types = (str, unicode)
144 unicode_type = unicode
146 unicode_type = unicode
145
147
146 import re
148 import re
147 _name_re = re.compile(r"[a-zA-Z_][a-zA-Z0-9_]*$")
149 _name_re = re.compile(r"[a-zA-Z_][a-zA-Z0-9_]*$")
148 def isidentifier(s, dotted=False):
150 def isidentifier(s, dotted=False):
149 if dotted:
151 if dotted:
150 return all(isidentifier(a) for a in s.split("."))
152 return all(isidentifier(a) for a in s.split("."))
151 return bool(_name_re.match(s))
153 return bool(_name_re.match(s))
152
154
153 class open(object):
155 class open(object):
154 """Wrapper providing key part of Python 3 open() interface."""
156 """Wrapper providing key part of Python 3 open() interface."""
155 def __init__(self, fname, mode="r", encoding="utf-8"):
157 def __init__(self, fname, mode="r", encoding="utf-8"):
156 self.f = orig_open(fname, mode)
158 self.f = orig_open(fname, mode)
157 self.enc = encoding
159 self.enc = encoding
158
160
159 def write(self, s):
161 def write(self, s):
160 return self.f.write(s.encode(self.enc))
162 return self.f.write(s.encode(self.enc))
161
163
162 def read(self, size=-1):
164 def read(self, size=-1):
163 return self.f.read(size).decode(self.enc)
165 return self.f.read(size).decode(self.enc)
164
166
165 def close(self):
167 def close(self):
166 return self.f.close()
168 return self.f.close()
167
169
168 def __enter__(self):
170 def __enter__(self):
169 return self
171 return self
170
172
171 def __exit__(self, etype, value, traceback):
173 def __exit__(self, etype, value, traceback):
172 self.f.close()
174 self.f.close()
173
175
174 xrange = xrange
176 xrange = xrange
175 def iteritems(d): return d.iteritems()
177 def iteritems(d): return d.iteritems()
176 def itervalues(d): return d.itervalues()
178 def itervalues(d): return d.itervalues()
177 getcwd = os.getcwdu
179 getcwd = os.getcwdu
178
180
179 def MethodType(func, instance):
181 def MethodType(func, instance):
180 return types.MethodType(func, instance, type(instance))
182 return types.MethodType(func, instance, type(instance))
181
183
182 # don't override system execfile on 2.x:
184 # don't override system execfile on 2.x:
183 execfile = execfile
185 execfile = execfile
184
186
185 def doctest_refactor_print(func_or_str):
187 def doctest_refactor_print(func_or_str):
186 return func_or_str
188 return func_or_str
187
189
188
190
189 # Abstract u'abc' syntax:
191 # Abstract u'abc' syntax:
190 @_modify_str_or_docstring
192 @_modify_str_or_docstring
191 def u_format(s):
193 def u_format(s):
192 """"{u}'abc'" --> "u'abc'" (Python 2)
194 """"{u}'abc'" --> "u'abc'" (Python 2)
193
195
194 Accepts a string or a function, so it can be used as a decorator."""
196 Accepts a string or a function, so it can be used as a decorator."""
195 return s.format(u='u')
197 return s.format(u='u')
196
198
197 if sys.platform == 'win32':
199 if sys.platform == 'win32':
198 def execfile(fname, glob=None, loc=None):
200 def execfile(fname, glob=None, loc=None):
199 loc = loc if (loc is not None) else glob
201 loc = loc if (loc is not None) else glob
200 # The rstrip() is necessary b/c trailing whitespace in files will
202 # The rstrip() is necessary b/c trailing whitespace in files will
201 # cause an IndentationError in Python 2.6 (this was fixed in 2.7,
203 # cause an IndentationError in Python 2.6 (this was fixed in 2.7,
202 # but we still support 2.6). See issue 1027.
204 # but we still support 2.6). See issue 1027.
203 scripttext = builtin_mod.open(fname).read().rstrip() + '\n'
205 scripttext = builtin_mod.open(fname).read().rstrip() + '\n'
204 # compile converts unicode filename to str assuming
206 # compile converts unicode filename to str assuming
205 # ascii. Let's do the conversion before calling compile
207 # ascii. Let's do the conversion before calling compile
206 if isinstance(fname, unicode):
208 if isinstance(fname, unicode):
207 filename = unicode_to_str(fname)
209 filename = unicode_to_str(fname)
208 else:
210 else:
209 filename = fname
211 filename = fname
210 exec(compile(scripttext, filename, 'exec'), glob, loc)
212 exec(compile(scripttext, filename, 'exec'), glob, loc)
211 else:
213 else:
212 def execfile(fname, *where):
214 def execfile(fname, *where):
213 if isinstance(fname, unicode):
215 if isinstance(fname, unicode):
214 filename = fname.encode(sys.getfilesystemencoding())
216 filename = fname.encode(sys.getfilesystemencoding())
215 else:
217 else:
216 filename = fname
218 filename = fname
217 builtin_mod.execfile(filename, *where)
219 builtin_mod.execfile(filename, *where)
218
220
219 # Parts below taken from six:
221 # Parts below taken from six:
220 # Copyright (c) 2010-2013 Benjamin Peterson
222 # Copyright (c) 2010-2013 Benjamin Peterson
221 #
223 #
222 # Permission is hereby granted, free of charge, to any person obtaining a copy
224 # Permission is hereby granted, free of charge, to any person obtaining a copy
223 # of this software and associated documentation files (the "Software"), to deal
225 # of this software and associated documentation files (the "Software"), to deal
224 # in the Software without restriction, including without limitation the rights
226 # in the Software without restriction, including without limitation the rights
225 # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
227 # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
226 # copies of the Software, and to permit persons to whom the Software is
228 # copies of the Software, and to permit persons to whom the Software is
227 # furnished to do so, subject to the following conditions:
229 # furnished to do so, subject to the following conditions:
228 #
230 #
229 # The above copyright notice and this permission notice shall be included in all
231 # The above copyright notice and this permission notice shall be included in all
230 # copies or substantial portions of the Software.
232 # copies or substantial portions of the Software.
231 #
233 #
232 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
234 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
233 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
235 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
234 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
236 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
235 # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
237 # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
236 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
238 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
237 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
239 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
238 # SOFTWARE.
240 # SOFTWARE.
239
241
240 def with_metaclass(meta, *bases):
242 def with_metaclass(meta, *bases):
241 """Create a base class with a metaclass."""
243 """Create a base class with a metaclass."""
242 return meta("_NewBase", bases, {})
244 return meta("_NewBase", bases, {})
General Comments 0
You need to be logged in to leave comments. Login now