##// END OF EJS Templates
use shell namespaces in apply_request
MinRK -
Show More
@@ -1,880 +1,880 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 """A simple interactive kernel that talks to a frontend over 0MQ.
2 """A simple interactive kernel that talks to a frontend over 0MQ.
3
3
4 Things to do:
4 Things to do:
5
5
6 * Implement `set_parent` logic. Right before doing exec, the Kernel should
6 * Implement `set_parent` logic. Right before doing exec, the Kernel should
7 call set_parent on all the PUB objects with the message about to be executed.
7 call set_parent on all the PUB objects with the message about to be executed.
8 * Implement random port and security key logic.
8 * Implement random port and security key logic.
9 * Implement control messages.
9 * Implement control messages.
10 * Implement event loop and poll version.
10 * Implement event loop and poll version.
11 """
11 """
12
12
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14 # Imports
14 # Imports
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16 from __future__ import print_function
16 from __future__ import print_function
17
17
18 # Standard library imports
18 # Standard library imports
19 import __builtin__
19 import __builtin__
20 import atexit
20 import atexit
21 import sys
21 import sys
22 import time
22 import time
23 import traceback
23 import traceback
24 import logging
24 import logging
25 import uuid
25 import uuid
26
26
27 from datetime import datetime
27 from datetime import datetime
28 from signal import (
28 from signal import (
29 signal, getsignal, default_int_handler, SIGINT, SIG_IGN
29 signal, getsignal, default_int_handler, SIGINT, SIG_IGN
30 )
30 )
31
31
32 # System library imports
32 # System library imports
33 import zmq
33 import zmq
34 from zmq.eventloop import ioloop
34 from zmq.eventloop import ioloop
35 from zmq.eventloop.zmqstream import ZMQStream
35 from zmq.eventloop.zmqstream import ZMQStream
36
36
37 # Local imports
37 # Local imports
38 from IPython.core import pylabtools
38 from IPython.core import pylabtools
39 from IPython.config.configurable import Configurable
39 from IPython.config.configurable import Configurable
40 from IPython.config.application import boolean_flag, catch_config_error
40 from IPython.config.application import boolean_flag, catch_config_error
41 from IPython.core.application import ProfileDir
41 from IPython.core.application import ProfileDir
42 from IPython.core.error import StdinNotImplementedError
42 from IPython.core.error import StdinNotImplementedError
43 from IPython.core.shellapp import (
43 from IPython.core.shellapp import (
44 InteractiveShellApp, shell_flags, shell_aliases
44 InteractiveShellApp, shell_flags, shell_aliases
45 )
45 )
46 from IPython.utils import io
46 from IPython.utils import io
47 from IPython.utils import py3compat
47 from IPython.utils import py3compat
48 from IPython.utils.frame import extract_module_locals
48 from IPython.utils.frame import extract_module_locals
49 from IPython.utils.jsonutil import json_clean
49 from IPython.utils.jsonutil import json_clean
50 from IPython.utils.traitlets import (
50 from IPython.utils.traitlets import (
51 Any, Instance, Float, Dict, CaselessStrEnum, List, Set, Integer, Unicode
51 Any, Instance, Float, Dict, CaselessStrEnum, List, Set, Integer, Unicode
52 )
52 )
53
53
54 from entry_point import base_launch_kernel
54 from entry_point import base_launch_kernel
55 from kernelapp import KernelApp, kernel_flags, kernel_aliases
55 from kernelapp import KernelApp, kernel_flags, kernel_aliases
56 from serialize import serialize_object, unpack_apply_message
56 from serialize import serialize_object, unpack_apply_message
57 from session import Session, Message
57 from session import Session, Message
58 from zmqshell import ZMQInteractiveShell
58 from zmqshell import ZMQInteractiveShell
59
59
60
60
61 #-----------------------------------------------------------------------------
61 #-----------------------------------------------------------------------------
62 # Main kernel class
62 # Main kernel class
63 #-----------------------------------------------------------------------------
63 #-----------------------------------------------------------------------------
64
64
65 class Kernel(Configurable):
65 class Kernel(Configurable):
66
66
67 #---------------------------------------------------------------------------
67 #---------------------------------------------------------------------------
68 # Kernel interface
68 # Kernel interface
69 #---------------------------------------------------------------------------
69 #---------------------------------------------------------------------------
70
70
71 # attribute to override with a GUI
71 # attribute to override with a GUI
72 eventloop = Any(None)
72 eventloop = Any(None)
73 def _eventloop_changed(self, name, old, new):
73 def _eventloop_changed(self, name, old, new):
74 """schedule call to eventloop from IOLoop"""
74 """schedule call to eventloop from IOLoop"""
75 loop = ioloop.IOLoop.instance()
75 loop = ioloop.IOLoop.instance()
76 loop.add_timeout(time.time()+0.1, self.enter_eventloop)
76 loop.add_timeout(time.time()+0.1, self.enter_eventloop)
77
77
78 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
78 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
79 session = Instance(Session)
79 session = Instance(Session)
80 profile_dir = Instance('IPython.core.profiledir.ProfileDir')
80 profile_dir = Instance('IPython.core.profiledir.ProfileDir')
81 shell_streams = List()
81 shell_streams = List()
82 control_stream = Instance(ZMQStream)
82 control_stream = Instance(ZMQStream)
83 iopub_stream = Instance(ZMQStream)
83 iopub_stream = Instance(ZMQStream)
84 stdin_socket = Instance(zmq.Socket)
84 stdin_socket = Instance(zmq.Socket)
85 log = Instance(logging.Logger)
85 log = Instance(logging.Logger)
86
86
87 user_module = Instance('types.ModuleType')
87 user_module = Instance('types.ModuleType')
88 def _user_module_changed(self, name, old, new):
88 def _user_module_changed(self, name, old, new):
89 if self.shell is not None:
89 if self.shell is not None:
90 self.shell.user_module = new
90 self.shell.user_module = new
91
91
92 user_ns = Dict(default_value=None)
92 user_ns = Dict(default_value=None)
93 def _user_ns_changed(self, name, old, new):
93 def _user_ns_changed(self, name, old, new):
94 if self.shell is not None:
94 if self.shell is not None:
95 self.shell.user_ns = new
95 self.shell.user_ns = new
96 self.shell.init_user_ns()
96 self.shell.init_user_ns()
97
97
98 # identities:
98 # identities:
99 int_id = Integer(-1)
99 int_id = Integer(-1)
100 ident = Unicode()
100 ident = Unicode()
101
101
102 def _ident_default(self):
102 def _ident_default(self):
103 return unicode(uuid.uuid4())
103 return unicode(uuid.uuid4())
104
104
105
105
106 # Private interface
106 # Private interface
107
107
108 # Time to sleep after flushing the stdout/err buffers in each execute
108 # Time to sleep after flushing the stdout/err buffers in each execute
109 # cycle. While this introduces a hard limit on the minimal latency of the
109 # cycle. While this introduces a hard limit on the minimal latency of the
110 # execute cycle, it helps prevent output synchronization problems for
110 # execute cycle, it helps prevent output synchronization problems for
111 # clients.
111 # clients.
112 # Units are in seconds. The minimum zmq latency on local host is probably
112 # Units are in seconds. The minimum zmq latency on local host is probably
113 # ~150 microseconds, set this to 500us for now. We may need to increase it
113 # ~150 microseconds, set this to 500us for now. We may need to increase it
114 # a little if it's not enough after more interactive testing.
114 # a little if it's not enough after more interactive testing.
115 _execute_sleep = Float(0.0005, config=True)
115 _execute_sleep = Float(0.0005, config=True)
116
116
117 # Frequency of the kernel's event loop.
117 # Frequency of the kernel's event loop.
118 # Units are in seconds, kernel subclasses for GUI toolkits may need to
118 # Units are in seconds, kernel subclasses for GUI toolkits may need to
119 # adapt to milliseconds.
119 # adapt to milliseconds.
120 _poll_interval = Float(0.05, config=True)
120 _poll_interval = Float(0.05, config=True)
121
121
122 # If the shutdown was requested over the network, we leave here the
122 # If the shutdown was requested over the network, we leave here the
123 # necessary reply message so it can be sent by our registered atexit
123 # necessary reply message so it can be sent by our registered atexit
124 # handler. This ensures that the reply is only sent to clients truly at
124 # handler. This ensures that the reply is only sent to clients truly at
125 # the end of our shutdown process (which happens after the underlying
125 # the end of our shutdown process (which happens after the underlying
126 # IPython shell's own shutdown).
126 # IPython shell's own shutdown).
127 _shutdown_message = None
127 _shutdown_message = None
128
128
129 # This is a dict of port number that the kernel is listening on. It is set
129 # This is a dict of port number that the kernel is listening on. It is set
130 # by record_ports and used by connect_request.
130 # by record_ports and used by connect_request.
131 _recorded_ports = Dict()
131 _recorded_ports = Dict()
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 = ZMQInteractiveShell.instance(config=self.config,
141 self.shell = ZMQInteractiveShell.instance(config=self.config,
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 )
145 )
146 self.shell.displayhook.session = self.session
146 self.shell.displayhook.session = self.session
147 self.shell.displayhook.pub_socket = self.iopub_stream.socket
147 self.shell.displayhook.pub_socket = self.iopub_stream.socket
148 self.shell.display_pub.session = self.session
148 self.shell.display_pub.session = self.session
149 self.shell.display_pub.pub_socket = self.iopub_stream.socket
149 self.shell.display_pub.pub_socket = self.iopub_stream.socket
150
150
151 # TMP - hack while developing
151 # TMP - hack while developing
152 self.shell._reply_content = None
152 self.shell._reply_content = None
153
153
154 # Build dict of handlers for message types
154 # Build dict of handlers for message types
155 msg_types = [ 'execute_request', 'complete_request',
155 msg_types = [ 'execute_request', 'complete_request',
156 'object_info_request', 'history_request',
156 'object_info_request', 'history_request',
157 'connect_request', 'shutdown_request',
157 'connect_request', 'shutdown_request',
158 'apply_request',
158 'apply_request',
159 ]
159 ]
160 self.shell_handlers = {}
160 self.shell_handlers = {}
161 for msg_type in msg_types:
161 for msg_type in msg_types:
162 self.shell_handlers[msg_type] = getattr(self, msg_type)
162 self.shell_handlers[msg_type] = getattr(self, msg_type)
163
163
164 control_msg_types = [ 'clear_request', 'abort_request' ]
164 control_msg_types = [ 'clear_request', 'abort_request' ]
165 self.control_handlers = {}
165 self.control_handlers = {}
166 for msg_type in control_msg_types:
166 for msg_type in control_msg_types:
167 self.control_handlers[msg_type] = getattr(self, msg_type)
167 self.control_handlers[msg_type] = getattr(self, msg_type)
168
168
169 def dispatch_control(self, msg):
169 def dispatch_control(self, msg):
170 """dispatch control requests"""
170 """dispatch control requests"""
171 idents,msg = self.session.feed_identities(msg, copy=False)
171 idents,msg = self.session.feed_identities(msg, copy=False)
172 try:
172 try:
173 msg = self.session.unserialize(msg, content=True, copy=False)
173 msg = self.session.unserialize(msg, content=True, copy=False)
174 except:
174 except:
175 self.log.error("Invalid Control Message", exc_info=True)
175 self.log.error("Invalid Control Message", exc_info=True)
176 return
176 return
177
177
178 self.log.debug("Control received: %s", msg)
178 self.log.debug("Control received: %s", msg)
179
179
180 header = msg['header']
180 header = msg['header']
181 msg_id = header['msg_id']
181 msg_id = header['msg_id']
182 msg_type = header['msg_type']
182 msg_type = header['msg_type']
183
183
184 handler = self.control_handlers.get(msg_type, None)
184 handler = self.control_handlers.get(msg_type, None)
185 if handler is None:
185 if handler is None:
186 self.log.error("UNKNOWN CONTROL MESSAGE TYPE: %r", msg_type)
186 self.log.error("UNKNOWN CONTROL MESSAGE TYPE: %r", msg_type)
187 else:
187 else:
188 try:
188 try:
189 handler(self.control_stream, idents, msg)
189 handler(self.control_stream, idents, msg)
190 except Exception:
190 except Exception:
191 self.log.error("Exception in control handler:", exc_info=True)
191 self.log.error("Exception in control handler:", exc_info=True)
192
192
193 def dispatch_shell(self, stream, msg):
193 def dispatch_shell(self, stream, msg):
194 """dispatch shell requests"""
194 """dispatch shell requests"""
195 # flush control requests first
195 # flush control requests first
196 if self.control_stream:
196 if self.control_stream:
197 self.control_stream.flush()
197 self.control_stream.flush()
198
198
199 idents,msg = self.session.feed_identities(msg, copy=False)
199 idents,msg = self.session.feed_identities(msg, copy=False)
200 try:
200 try:
201 msg = self.session.unserialize(msg, content=True, copy=False)
201 msg = self.session.unserialize(msg, content=True, copy=False)
202 except:
202 except:
203 self.log.error("Invalid Message", exc_info=True)
203 self.log.error("Invalid Message", exc_info=True)
204 return
204 return
205
205
206 header = msg['header']
206 header = msg['header']
207 msg_id = header['msg_id']
207 msg_id = header['msg_id']
208 msg_type = msg['header']['msg_type']
208 msg_type = msg['header']['msg_type']
209
209
210 # Print some info about this message and leave a '--->' marker, so it's
210 # Print some info about this message and leave a '--->' marker, so it's
211 # easier to trace visually the message chain when debugging. Each
211 # easier to trace visually the message chain when debugging. Each
212 # handler prints its message at the end.
212 # handler prints its message at the end.
213 self.log.debug('\n*** MESSAGE TYPE:%s***', msg_type)
213 self.log.debug('\n*** MESSAGE TYPE:%s***', msg_type)
214 self.log.debug(' Content: %s\n --->\n ', msg['content'])
214 self.log.debug(' Content: %s\n --->\n ', msg['content'])
215
215
216 if msg_id in self.aborted:
216 if msg_id in self.aborted:
217 self.aborted.remove(msg_id)
217 self.aborted.remove(msg_id)
218 # is it safe to assume a msg_id will not be resubmitted?
218 # is it safe to assume a msg_id will not be resubmitted?
219 reply_type = msg_type.split('_')[0] + '_reply'
219 reply_type = msg_type.split('_')[0] + '_reply'
220 status = {'status' : 'aborted'}
220 status = {'status' : 'aborted'}
221 reply_msg = self.session.send(stream, reply_type, subheader=status,
221 reply_msg = self.session.send(stream, reply_type, subheader=status,
222 content=status, parent=msg, ident=idents)
222 content=status, parent=msg, ident=idents)
223 return
223 return
224
224
225 handler = self.shell_handlers.get(msg_type, None)
225 handler = self.shell_handlers.get(msg_type, None)
226 if handler is None:
226 if handler is None:
227 self.log.error("UNKNOWN MESSAGE TYPE: %r", msg_type)
227 self.log.error("UNKNOWN MESSAGE TYPE: %r", msg_type)
228 else:
228 else:
229 # ensure default_int_handler during handler call
229 # ensure default_int_handler during handler call
230 sig = signal(SIGINT, default_int_handler)
230 sig = signal(SIGINT, default_int_handler)
231 try:
231 try:
232 handler(stream, idents, msg)
232 handler(stream, idents, msg)
233 except Exception:
233 except Exception:
234 self.log.error("Exception in message handler:", exc_info=True)
234 self.log.error("Exception in message handler:", exc_info=True)
235 finally:
235 finally:
236 signal(SIGINT, sig)
236 signal(SIGINT, sig)
237
237
238 def enter_eventloop(self):
238 def enter_eventloop(self):
239 """enter eventloop"""
239 """enter eventloop"""
240 self.log.critical("entering eventloop")
240 self.log.critical("entering eventloop")
241 # restore default_int_handler
241 # restore default_int_handler
242 signal(SIGINT, default_int_handler)
242 signal(SIGINT, default_int_handler)
243 self.eventloop(self)
243 self.eventloop(self)
244 self.log.critical("exiting eventloop")
244 self.log.critical("exiting eventloop")
245 # if eventloop exits, IOLoop should stop
245 # if eventloop exits, IOLoop should stop
246 ioloop.IOLoop.instance().stop()
246 ioloop.IOLoop.instance().stop()
247
247
248 def start(self):
248 def start(self):
249 """register dispatchers for streams"""
249 """register dispatchers for streams"""
250 if self.control_stream:
250 if self.control_stream:
251 self.control_stream.on_recv(self.dispatch_control, copy=False)
251 self.control_stream.on_recv(self.dispatch_control, copy=False)
252
252
253 def make_dispatcher(stream):
253 def make_dispatcher(stream):
254 def dispatcher(msg):
254 def dispatcher(msg):
255 return self.dispatch_shell(stream, msg)
255 return self.dispatch_shell(stream, msg)
256 return dispatcher
256 return dispatcher
257
257
258 for s in self.shell_streams:
258 for s in self.shell_streams:
259 s.on_recv(make_dispatcher(s), copy=False)
259 s.on_recv(make_dispatcher(s), copy=False)
260
260
261 def do_one_iteration(self):
261 def do_one_iteration(self):
262 """step eventloop just once"""
262 """step eventloop just once"""
263 if self.control_stream:
263 if self.control_stream:
264 self.control_stream.flush()
264 self.control_stream.flush()
265 for stream in self.shell_streams:
265 for stream in self.shell_streams:
266 # handle at most one request per iteration
266 # handle at most one request per iteration
267 stream.flush(zmq.POLLIN, 1)
267 stream.flush(zmq.POLLIN, 1)
268 stream.flush(zmq.POLLOUT)
268 stream.flush(zmq.POLLOUT)
269 self.iopub_stream.flush()
269 self.iopub_stream.flush()
270
270
271
271
272 def record_ports(self, ports):
272 def record_ports(self, ports):
273 """Record the ports that this kernel is using.
273 """Record the ports that this kernel is using.
274
274
275 The creator of the Kernel instance must call this methods if they
275 The creator of the Kernel instance must call this methods if they
276 want the :meth:`connect_request` method to return the port numbers.
276 want the :meth:`connect_request` method to return the port numbers.
277 """
277 """
278 self._recorded_ports = ports
278 self._recorded_ports = ports
279
279
280 #---------------------------------------------------------------------------
280 #---------------------------------------------------------------------------
281 # Kernel request handlers
281 # Kernel request handlers
282 #---------------------------------------------------------------------------
282 #---------------------------------------------------------------------------
283
283
284 def _publish_pyin(self, code, parent, execution_count):
284 def _publish_pyin(self, code, parent, execution_count):
285 """Publish the code request on the pyin stream."""
285 """Publish the code request on the pyin stream."""
286
286
287 self.session.send(self.iopub_stream, u'pyin',
287 self.session.send(self.iopub_stream, u'pyin',
288 {u'code':code, u'execution_count': execution_count},
288 {u'code':code, u'execution_count': execution_count},
289 parent=parent, ident=self._topic('pyin')
289 parent=parent, ident=self._topic('pyin')
290 )
290 )
291
291
292 def execute_request(self, stream, ident, parent):
292 def execute_request(self, stream, ident, parent):
293
293
294 self.session.send(self.iopub_stream,
294 self.session.send(self.iopub_stream,
295 u'status',
295 u'status',
296 {u'execution_state':u'busy'},
296 {u'execution_state':u'busy'},
297 parent=parent,
297 parent=parent,
298 ident=self._topic('status'),
298 ident=self._topic('status'),
299 )
299 )
300
300
301 try:
301 try:
302 content = parent[u'content']
302 content = parent[u'content']
303 code = content[u'code']
303 code = content[u'code']
304 silent = content[u'silent']
304 silent = content[u'silent']
305 except:
305 except:
306 self.log.error("Got bad msg: ")
306 self.log.error("Got bad msg: ")
307 self.log.error("%s", parent)
307 self.log.error("%s", parent)
308 return
308 return
309
309
310 shell = self.shell # we'll need this a lot here
310 shell = self.shell # we'll need this a lot here
311
311
312 # Replace raw_input. Note that is not sufficient to replace
312 # Replace raw_input. Note that is not sufficient to replace
313 # raw_input in the user namespace.
313 # raw_input in the user namespace.
314 if content.get('allow_stdin', False):
314 if content.get('allow_stdin', False):
315 raw_input = lambda prompt='': self._raw_input(prompt, ident, parent)
315 raw_input = lambda prompt='': self._raw_input(prompt, ident, parent)
316 else:
316 else:
317 raw_input = lambda prompt='' : self._no_raw_input()
317 raw_input = lambda prompt='' : self._no_raw_input()
318
318
319 if py3compat.PY3:
319 if py3compat.PY3:
320 __builtin__.input = raw_input
320 __builtin__.input = raw_input
321 else:
321 else:
322 __builtin__.raw_input = raw_input
322 __builtin__.raw_input = raw_input
323
323
324 # Set the parent message of the display hook and out streams.
324 # Set the parent message of the display hook and out streams.
325 shell.displayhook.set_parent(parent)
325 shell.displayhook.set_parent(parent)
326 shell.display_pub.set_parent(parent)
326 shell.display_pub.set_parent(parent)
327 sys.stdout.set_parent(parent)
327 sys.stdout.set_parent(parent)
328 sys.stderr.set_parent(parent)
328 sys.stderr.set_parent(parent)
329
329
330 # Re-broadcast our input for the benefit of listening clients, and
330 # Re-broadcast our input for the benefit of listening clients, and
331 # start computing output
331 # start computing output
332 if not silent:
332 if not silent:
333 self._publish_pyin(code, parent, shell.execution_count)
333 self._publish_pyin(code, parent, shell.execution_count)
334
334
335 reply_content = {}
335 reply_content = {}
336 try:
336 try:
337 if silent:
337 if silent:
338 # run_code uses 'exec' mode, so no displayhook will fire, and it
338 # run_code uses 'exec' mode, so no displayhook will fire, and it
339 # doesn't call logging or history manipulations. Print
339 # doesn't call logging or history manipulations. Print
340 # statements in that code will obviously still execute.
340 # statements in that code will obviously still execute.
341 shell.run_code(code)
341 shell.run_code(code)
342 else:
342 else:
343 # FIXME: the shell calls the exception handler itself.
343 # FIXME: the shell calls the exception handler itself.
344 shell.run_cell(code, store_history=True)
344 shell.run_cell(code, store_history=True)
345 except:
345 except:
346 status = u'error'
346 status = u'error'
347 # FIXME: this code right now isn't being used yet by default,
347 # FIXME: this code right now isn't being used yet by default,
348 # because the run_cell() call above directly fires off exception
348 # because the run_cell() call above directly fires off exception
349 # reporting. This code, therefore, is only active in the scenario
349 # reporting. This code, therefore, is only active in the scenario
350 # where runlines itself has an unhandled exception. We need to
350 # where runlines itself has an unhandled exception. We need to
351 # uniformize this, for all exception construction to come from a
351 # uniformize this, for all exception construction to come from a
352 # single location in the codbase.
352 # single location in the codbase.
353 etype, evalue, tb = sys.exc_info()
353 etype, evalue, tb = sys.exc_info()
354 tb_list = traceback.format_exception(etype, evalue, tb)
354 tb_list = traceback.format_exception(etype, evalue, tb)
355 reply_content.update(shell._showtraceback(etype, evalue, tb_list))
355 reply_content.update(shell._showtraceback(etype, evalue, tb_list))
356 else:
356 else:
357 status = u'ok'
357 status = u'ok'
358
358
359 reply_content[u'status'] = status
359 reply_content[u'status'] = status
360
360
361 # Return the execution counter so clients can display prompts
361 # Return the execution counter so clients can display prompts
362 reply_content['execution_count'] = shell.execution_count -1
362 reply_content['execution_count'] = shell.execution_count -1
363
363
364 # FIXME - fish exception info out of shell, possibly left there by
364 # FIXME - fish exception info out of shell, possibly left there by
365 # runlines. We'll need to clean up this logic later.
365 # runlines. We'll need to clean up this logic later.
366 if shell._reply_content is not None:
366 if shell._reply_content is not None:
367 reply_content.update(shell._reply_content)
367 reply_content.update(shell._reply_content)
368 # reset after use
368 # reset after use
369 shell._reply_content = None
369 shell._reply_content = None
370
370
371 # At this point, we can tell whether the main code execution succeeded
371 # At this point, we can tell whether the main code execution succeeded
372 # or not. If it did, we proceed to evaluate user_variables/expressions
372 # or not. If it did, we proceed to evaluate user_variables/expressions
373 if reply_content['status'] == 'ok':
373 if reply_content['status'] == 'ok':
374 reply_content[u'user_variables'] = \
374 reply_content[u'user_variables'] = \
375 shell.user_variables(content.get(u'user_variables', []))
375 shell.user_variables(content.get(u'user_variables', []))
376 reply_content[u'user_expressions'] = \
376 reply_content[u'user_expressions'] = \
377 shell.user_expressions(content.get(u'user_expressions', {}))
377 shell.user_expressions(content.get(u'user_expressions', {}))
378 else:
378 else:
379 # If there was an error, don't even try to compute variables or
379 # If there was an error, don't even try to compute variables or
380 # expressions
380 # expressions
381 reply_content[u'user_variables'] = {}
381 reply_content[u'user_variables'] = {}
382 reply_content[u'user_expressions'] = {}
382 reply_content[u'user_expressions'] = {}
383
383
384 # Payloads should be retrieved regardless of outcome, so we can both
384 # Payloads should be retrieved regardless of outcome, so we can both
385 # recover partial output (that could have been generated early in a
385 # recover partial output (that could have been generated early in a
386 # block, before an error) and clear the payload system always.
386 # block, before an error) and clear the payload system always.
387 reply_content[u'payload'] = shell.payload_manager.read_payload()
387 reply_content[u'payload'] = shell.payload_manager.read_payload()
388 # Be agressive about clearing the payload because we don't want
388 # Be agressive about clearing the payload because we don't want
389 # it to sit in memory until the next execute_request comes in.
389 # it to sit in memory until the next execute_request comes in.
390 shell.payload_manager.clear_payload()
390 shell.payload_manager.clear_payload()
391
391
392 # Flush output before sending the reply.
392 # Flush output before sending the reply.
393 sys.stdout.flush()
393 sys.stdout.flush()
394 sys.stderr.flush()
394 sys.stderr.flush()
395 # FIXME: on rare occasions, the flush doesn't seem to make it to the
395 # FIXME: on rare occasions, the flush doesn't seem to make it to the
396 # clients... This seems to mitigate the problem, but we definitely need
396 # clients... This seems to mitigate the problem, but we definitely need
397 # to better understand what's going on.
397 # to better understand what's going on.
398 if self._execute_sleep:
398 if self._execute_sleep:
399 time.sleep(self._execute_sleep)
399 time.sleep(self._execute_sleep)
400
400
401 # Send the reply.
401 # Send the reply.
402 reply_content = json_clean(reply_content)
402 reply_content = json_clean(reply_content)
403 reply_msg = self.session.send(stream, u'execute_reply',
403 reply_msg = self.session.send(stream, u'execute_reply',
404 reply_content, parent, ident=ident)
404 reply_content, parent, ident=ident)
405 self.log.debug("%s", reply_msg)
405 self.log.debug("%s", reply_msg)
406
406
407 if reply_msg['content']['status'] == u'error':
407 if reply_msg['content']['status'] == u'error':
408 self._abort_queues()
408 self._abort_queues()
409
409
410 self.session.send(self.iopub_stream,
410 self.session.send(self.iopub_stream,
411 u'status',
411 u'status',
412 {u'execution_state':u'idle'},
412 {u'execution_state':u'idle'},
413 parent=parent,
413 parent=parent,
414 ident=self._topic('status'))
414 ident=self._topic('status'))
415
415
416 def complete_request(self, stream, ident, parent):
416 def complete_request(self, stream, ident, parent):
417 txt, matches = self._complete(parent)
417 txt, matches = self._complete(parent)
418 matches = {'matches' : matches,
418 matches = {'matches' : matches,
419 'matched_text' : txt,
419 'matched_text' : txt,
420 'status' : 'ok'}
420 'status' : 'ok'}
421 matches = json_clean(matches)
421 matches = json_clean(matches)
422 completion_msg = self.session.send(stream, 'complete_reply',
422 completion_msg = self.session.send(stream, 'complete_reply',
423 matches, parent, ident)
423 matches, parent, ident)
424 self.log.debug("%s", completion_msg)
424 self.log.debug("%s", completion_msg)
425
425
426 def object_info_request(self, stream, ident, parent):
426 def object_info_request(self, stream, ident, parent):
427 content = parent['content']
427 content = parent['content']
428 object_info = self.shell.object_inspect(content['oname'],
428 object_info = self.shell.object_inspect(content['oname'],
429 detail_level = content.get('detail_level', 0)
429 detail_level = content.get('detail_level', 0)
430 )
430 )
431 # Before we send this object over, we scrub it for JSON usage
431 # Before we send this object over, we scrub it for JSON usage
432 oinfo = json_clean(object_info)
432 oinfo = json_clean(object_info)
433 msg = self.session.send(stream, 'object_info_reply',
433 msg = self.session.send(stream, 'object_info_reply',
434 oinfo, parent, ident)
434 oinfo, parent, ident)
435 self.log.debug("%s", msg)
435 self.log.debug("%s", msg)
436
436
437 def history_request(self, stream, ident, parent):
437 def history_request(self, stream, ident, parent):
438 # We need to pull these out, as passing **kwargs doesn't work with
438 # We need to pull these out, as passing **kwargs doesn't work with
439 # unicode keys before Python 2.6.5.
439 # unicode keys before Python 2.6.5.
440 hist_access_type = parent['content']['hist_access_type']
440 hist_access_type = parent['content']['hist_access_type']
441 raw = parent['content']['raw']
441 raw = parent['content']['raw']
442 output = parent['content']['output']
442 output = parent['content']['output']
443 if hist_access_type == 'tail':
443 if hist_access_type == 'tail':
444 n = parent['content']['n']
444 n = parent['content']['n']
445 hist = self.shell.history_manager.get_tail(n, raw=raw, output=output,
445 hist = self.shell.history_manager.get_tail(n, raw=raw, output=output,
446 include_latest=True)
446 include_latest=True)
447
447
448 elif hist_access_type == 'range':
448 elif hist_access_type == 'range':
449 session = parent['content']['session']
449 session = parent['content']['session']
450 start = parent['content']['start']
450 start = parent['content']['start']
451 stop = parent['content']['stop']
451 stop = parent['content']['stop']
452 hist = self.shell.history_manager.get_range(session, start, stop,
452 hist = self.shell.history_manager.get_range(session, start, stop,
453 raw=raw, output=output)
453 raw=raw, output=output)
454
454
455 elif hist_access_type == 'search':
455 elif hist_access_type == 'search':
456 pattern = parent['content']['pattern']
456 pattern = parent['content']['pattern']
457 hist = self.shell.history_manager.search(pattern, raw=raw,
457 hist = self.shell.history_manager.search(pattern, raw=raw,
458 output=output)
458 output=output)
459
459
460 else:
460 else:
461 hist = []
461 hist = []
462 hist = list(hist)
462 hist = list(hist)
463 content = {'history' : hist}
463 content = {'history' : hist}
464 content = json_clean(content)
464 content = json_clean(content)
465 msg = self.session.send(stream, 'history_reply',
465 msg = self.session.send(stream, 'history_reply',
466 content, parent, ident)
466 content, parent, ident)
467 self.log.debug("Sending history reply with %i entries", len(hist))
467 self.log.debug("Sending history reply with %i entries", len(hist))
468
468
469 def connect_request(self, stream, ident, parent):
469 def connect_request(self, stream, ident, parent):
470 if self._recorded_ports is not None:
470 if self._recorded_ports is not None:
471 content = self._recorded_ports.copy()
471 content = self._recorded_ports.copy()
472 else:
472 else:
473 content = {}
473 content = {}
474 msg = self.session.send(stream, 'connect_reply',
474 msg = self.session.send(stream, 'connect_reply',
475 content, parent, ident)
475 content, parent, ident)
476 self.log.debug("%s", msg)
476 self.log.debug("%s", msg)
477
477
478 def shutdown_request(self, stream, ident, parent):
478 def shutdown_request(self, stream, ident, parent):
479 self.shell.exit_now = True
479 self.shell.exit_now = True
480 self._shutdown_message = self.session.msg(u'shutdown_reply',
480 self._shutdown_message = self.session.msg(u'shutdown_reply',
481 parent['content'], parent
481 parent['content'], parent
482 )
482 )
483 # self.session.send(stream, self._shutdown_message, ident=ident)
483 # self.session.send(stream, self._shutdown_message, ident=ident)
484
484
485 self._at_shutdown()
485 self._at_shutdown()
486 # call sys.exit after a short delay
486 # call sys.exit after a short delay
487 ioloop.IOLoop.instance().add_timeout(time.time()+0.05, lambda : sys.exit(0))
487 ioloop.IOLoop.instance().add_timeout(time.time()+0.05, lambda : sys.exit(0))
488
488
489 #---------------------------------------------------------------------------
489 #---------------------------------------------------------------------------
490 # Engine methods
490 # Engine methods
491 #---------------------------------------------------------------------------
491 #---------------------------------------------------------------------------
492
492
493 def apply_request(self, stream, ident, parent):
493 def apply_request(self, stream, ident, parent):
494 try:
494 try:
495 content = parent[u'content']
495 content = parent[u'content']
496 bufs = parent[u'buffers']
496 bufs = parent[u'buffers']
497 msg_id = parent['header']['msg_id']
497 msg_id = parent['header']['msg_id']
498 # bound = parent['header'].get('bound', False)
499 except:
498 except:
500 self.log.error("Got bad msg: %s", parent, exc_info=True)
499 self.log.error("Got bad msg: %s", parent, exc_info=True)
501 return
500 return
502 # pyin_msg = self.session.msg(u'pyin',{u'code':code}, parent=parent)
501 # pyin_msg = self.session.msg(u'pyin',{u'code':code}, parent=parent)
503 # self.iopub_stream.send(pyin_msg)
502 # self.iopub_stream.send(pyin_msg)
504 # self.session.send(self.iopub_stream, u'pyin', {u'code':code},parent=parent)
503 # self.session.send(self.iopub_stream, u'pyin', {u'code':code},parent=parent)
505 sub = {'dependencies_met' : True, 'engine' : self.ident,
504 sub = {'dependencies_met' : True, 'engine' : self.ident,
506 'started': datetime.now()}
505 'started': datetime.now()}
507 try:
506 try:
508 # allow for not overriding displayhook
507 # allow for not overriding displayhook
509 if hasattr(sys.displayhook, 'set_parent'):
508 if hasattr(sys.displayhook, 'set_parent'):
510 sys.displayhook.set_parent(parent)
509 sys.displayhook.set_parent(parent)
511 sys.stdout.set_parent(parent)
510 sys.stdout.set_parent(parent)
512 sys.stderr.set_parent(parent)
511 sys.stderr.set_parent(parent)
513 # exec "f(*args,**kwargs)" in self.user_ns, self.user_ns
512 working = self.shell.user_ns
514 working = self.user_ns
513
515 # suffix =
516 prefix = "_"+str(msg_id).replace("-","")+"_"
514 prefix = "_"+str(msg_id).replace("-","")+"_"
517
515
518 f,args,kwargs = unpack_apply_message(bufs, working, copy=False)
516 f,args,kwargs = unpack_apply_message(bufs, working, copy=False)
519 # if bound:
520 # bound_ns = Namespace(working)
521 # args = [bound_ns]+list(args)
522
517
523 fname = getattr(f, '__name__', 'f')
518 fname = getattr(f, '__name__', 'f')
524
519
525 fname = prefix+"f"
520 fname = prefix+"f"
526 argname = prefix+"args"
521 argname = prefix+"args"
527 kwargname = prefix+"kwargs"
522 kwargname = prefix+"kwargs"
528 resultname = prefix+"result"
523 resultname = prefix+"result"
529
524
530 ns = { fname : f, argname : args, kwargname : kwargs , resultname : None }
525 ns = { fname : f, argname : args, kwargname : kwargs , resultname : None }
531 # print ns
526 # print ns
532 working.update(ns)
527 working.update(ns)
533 code = "%s=%s(*%s,**%s)"%(resultname, fname, argname, kwargname)
528 code = "%s = %s(*%s,**%s)" % (resultname, fname, argname, kwargname)
534 try:
529 try:
535 exec code in working,working
530 exec code in self.shell.user_global_ns, self.shell.user_ns
536 result = working.get(resultname)
531 result = working.get(resultname)
537 finally:
532 finally:
538 for key in ns.iterkeys():
533 for key in ns.iterkeys():
539 working.pop(key)
534 working.pop(key)
540 # if bound:
541 # working.update(bound_ns)
542
535
543 packed_result,buf = serialize_object(result)
536 packed_result,buf = serialize_object(result)
544 result_buf = [packed_result]+buf
537 result_buf = [packed_result]+buf
545 except:
538 except:
546 exc_content = self._wrap_exception('apply')
539 exc_content = self._wrap_exception('apply')
547 # exc_msg = self.session.msg(u'pyerr', exc_content, parent)
540 # exc_msg = self.session.msg(u'pyerr', exc_content, parent)
548 self.session.send(self.iopub_stream, u'pyerr', exc_content, parent=parent,
541 self.session.send(self.iopub_stream, u'pyerr', exc_content, parent=parent,
549 ident=self._topic('pyerr'))
542 ident=self._topic('pyerr'))
550 reply_content = exc_content
543 reply_content = exc_content
551 result_buf = []
544 result_buf = []
552
545
553 if exc_content['ename'] == 'UnmetDependency':
546 if exc_content['ename'] == 'UnmetDependency':
554 sub['dependencies_met'] = False
547 sub['dependencies_met'] = False
555 else:
548 else:
556 reply_content = {'status' : 'ok'}
549 reply_content = {'status' : 'ok'}
557
550
558 # put 'ok'/'error' status in header, for scheduler introspection:
551 # put 'ok'/'error' status in header, for scheduler introspection:
559 sub['status'] = reply_content['status']
552 sub['status'] = reply_content['status']
560
553
561 # flush i/o
554 # flush i/o
562 sys.stdout.flush()
555 sys.stdout.flush()
563 sys.stderr.flush()
556 sys.stderr.flush()
564
557
565 reply_msg = self.session.send(stream, u'apply_reply', reply_content,
558 reply_msg = self.session.send(stream, u'apply_reply', reply_content,
566 parent=parent, ident=ident,buffers=result_buf, subheader=sub)
559 parent=parent, ident=ident,buffers=result_buf, subheader=sub)
567
560
568 #---------------------------------------------------------------------------
561 #---------------------------------------------------------------------------
569 # Control messages
562 # Control messages
570 #---------------------------------------------------------------------------
563 #---------------------------------------------------------------------------
571
564
572 def abort_request(self, stream, ident, parent):
565 def abort_request(self, stream, ident, parent):
573 """abort a specifig msg by id"""
566 """abort a specifig msg by id"""
574 msg_ids = parent['content'].get('msg_ids', None)
567 msg_ids = parent['content'].get('msg_ids', None)
575 if isinstance(msg_ids, basestring):
568 if isinstance(msg_ids, basestring):
576 msg_ids = [msg_ids]
569 msg_ids = [msg_ids]
577 if not msg_ids:
570 if not msg_ids:
578 self.abort_queues()
571 self.abort_queues()
579 for mid in msg_ids:
572 for mid in msg_ids:
580 self.aborted.add(str(mid))
573 self.aborted.add(str(mid))
581
574
582 content = dict(status='ok')
575 content = dict(status='ok')
583 reply_msg = self.session.send(stream, 'abort_reply', content=content,
576 reply_msg = self.session.send(stream, 'abort_reply', content=content,
584 parent=parent, ident=ident)
577 parent=parent, ident=ident)
585 self.log.debug("%s", reply_msg)
578 self.log.debug("%s", reply_msg)
586
579
587 def clear_request(self, stream, idents, parent):
580 def clear_request(self, stream, idents, parent):
588 """Clear our namespace."""
581 """Clear our namespace."""
589 self.user_ns = {}
582 self.shell.reset(False)
590 msg = self.session.send(stream, 'clear_reply', ident=idents, parent=parent,
583 msg = self.session.send(stream, 'clear_reply', ident=idents, parent=parent,
591 content = dict(status='ok'))
584 content = dict(status='ok'))
592 self._initial_exec_lines()
593
585
594
586
595 #---------------------------------------------------------------------------
587 #---------------------------------------------------------------------------
596 # Protected interface
588 # Protected interface
597 #---------------------------------------------------------------------------
589 #---------------------------------------------------------------------------
598
590
599
591
592 def _wrap_exception(self, method=None):
593 # import here, because _wrap_exception is only used in parallel,
594 # and parallel has higher min pyzmq version
595 from IPython.parallel.error import wrap_exception
596 e_info = dict(engine_uuid=self.ident, engine_id=self.int_id, method=method)
597 content = wrap_exception(e_info)
598 return content
599
600 def _topic(self, topic):
600 def _topic(self, topic):
601 """prefixed topic for IOPub messages"""
601 """prefixed topic for IOPub messages"""
602 if self.int_id >= 0:
602 if self.int_id >= 0:
603 base = "engine.%i" % self.int_id
603 base = "engine.%i" % self.int_id
604 else:
604 else:
605 base = "kernel.%s" % self.ident
605 base = "kernel.%s" % self.ident
606
606
607 return py3compat.cast_bytes("%s.%s" % (base, topic))
607 return py3compat.cast_bytes("%s.%s" % (base, topic))
608
608
609 def _abort_queues(self):
609 def _abort_queues(self):
610 for stream in self.shell_streams:
610 for stream in self.shell_streams:
611 if stream:
611 if stream:
612 self._abort_queue(stream)
612 self._abort_queue(stream)
613
613
614 def _abort_queue(self, stream):
614 def _abort_queue(self, stream):
615 while True:
615 while True:
616 idents,msg = self.session.recv(stream, zmq.NOBLOCK, content=True)
616 idents,msg = self.session.recv(stream, zmq.NOBLOCK, content=True)
617 if msg is None:
617 if msg is None:
618 return
618 return
619
619
620 self.log.info("Aborting:")
620 self.log.info("Aborting:")
621 self.log.info("%s", msg)
621 self.log.info("%s", msg)
622 msg_type = msg['header']['msg_type']
622 msg_type = msg['header']['msg_type']
623 reply_type = msg_type.split('_')[0] + '_reply'
623 reply_type = msg_type.split('_')[0] + '_reply'
624 # reply_msg = self.session.msg(reply_type, {'status' : 'aborted'}, msg)
624 # reply_msg = self.session.msg(reply_type, {'status' : 'aborted'}, msg)
625 # self.reply_stream.send(ident,zmq.SNDMORE)
625 # self.reply_stream.send(ident,zmq.SNDMORE)
626 # self.reply_stream.send_json(reply_msg)
626 # self.reply_stream.send_json(reply_msg)
627 reply_msg = self.session.send(stream, reply_type,
627 reply_msg = self.session.send(stream, reply_type,
628 content={'status' : 'aborted'}, parent=msg, ident=idents)
628 content={'status' : 'aborted'}, parent=msg, ident=idents)
629 self.log.debug("%s", reply_msg)
629 self.log.debug("%s", reply_msg)
630 # We need to wait a bit for requests to come in. This can probably
630 # We need to wait a bit for requests to come in. This can probably
631 # be set shorter for true asynchronous clients.
631 # be set shorter for true asynchronous clients.
632 time.sleep(0.05)
632 time.sleep(0.05)
633
633
634
634
635 def _no_raw_input(self):
635 def _no_raw_input(self):
636 """Raise StdinNotImplentedError if active frontend doesn't support
636 """Raise StdinNotImplentedError if active frontend doesn't support
637 stdin."""
637 stdin."""
638 raise StdinNotImplementedError("raw_input was called, but this "
638 raise StdinNotImplementedError("raw_input was called, but this "
639 "frontend does not support stdin.")
639 "frontend does not support stdin.")
640
640
641 def _raw_input(self, prompt, ident, parent):
641 def _raw_input(self, prompt, ident, parent):
642 # Flush output before making the request.
642 # Flush output before making the request.
643 sys.stderr.flush()
643 sys.stderr.flush()
644 sys.stdout.flush()
644 sys.stdout.flush()
645
645
646 # Send the input request.
646 # Send the input request.
647 content = json_clean(dict(prompt=prompt))
647 content = json_clean(dict(prompt=prompt))
648 self.session.send(self.stdin_socket, u'input_request', content, parent,
648 self.session.send(self.stdin_socket, u'input_request', content, parent,
649 ident=ident)
649 ident=ident)
650
650
651 # Await a response.
651 # Await a response.
652 while True:
652 while True:
653 try:
653 try:
654 ident, reply = self.session.recv(self.stdin_socket, 0)
654 ident, reply = self.session.recv(self.stdin_socket, 0)
655 except Exception:
655 except Exception:
656 self.log.warn("Invalid Message:", exc_info=True)
656 self.log.warn("Invalid Message:", exc_info=True)
657 else:
657 else:
658 break
658 break
659 try:
659 try:
660 value = reply['content']['value']
660 value = reply['content']['value']
661 except:
661 except:
662 self.log.error("Got bad raw_input reply: ")
662 self.log.error("Got bad raw_input reply: ")
663 self.log.error("%s", parent)
663 self.log.error("%s", parent)
664 value = ''
664 value = ''
665 if value == '\x04':
665 if value == '\x04':
666 # EOF
666 # EOF
667 raise EOFError
667 raise EOFError
668 return value
668 return value
669
669
670 def _complete(self, msg):
670 def _complete(self, msg):
671 c = msg['content']
671 c = msg['content']
672 try:
672 try:
673 cpos = int(c['cursor_pos'])
673 cpos = int(c['cursor_pos'])
674 except:
674 except:
675 # If we don't get something that we can convert to an integer, at
675 # If we don't get something that we can convert to an integer, at
676 # least attempt the completion guessing the cursor is at the end of
676 # least attempt the completion guessing the cursor is at the end of
677 # the text, if there's any, and otherwise of the line
677 # the text, if there's any, and otherwise of the line
678 cpos = len(c['text'])
678 cpos = len(c['text'])
679 if cpos==0:
679 if cpos==0:
680 cpos = len(c['line'])
680 cpos = len(c['line'])
681 return self.shell.complete(c['text'], c['line'], cpos)
681 return self.shell.complete(c['text'], c['line'], cpos)
682
682
683 def _object_info(self, context):
683 def _object_info(self, context):
684 symbol, leftover = self._symbol_from_context(context)
684 symbol, leftover = self._symbol_from_context(context)
685 if symbol is not None and not leftover:
685 if symbol is not None and not leftover:
686 doc = getattr(symbol, '__doc__', '')
686 doc = getattr(symbol, '__doc__', '')
687 else:
687 else:
688 doc = ''
688 doc = ''
689 object_info = dict(docstring = doc)
689 object_info = dict(docstring = doc)
690 return object_info
690 return object_info
691
691
692 def _symbol_from_context(self, context):
692 def _symbol_from_context(self, context):
693 if not context:
693 if not context:
694 return None, context
694 return None, context
695
695
696 base_symbol_string = context[0]
696 base_symbol_string = context[0]
697 symbol = self.shell.user_ns.get(base_symbol_string, None)
697 symbol = self.shell.user_ns.get(base_symbol_string, None)
698 if symbol is None:
698 if symbol is None:
699 symbol = __builtin__.__dict__.get(base_symbol_string, None)
699 symbol = __builtin__.__dict__.get(base_symbol_string, None)
700 if symbol is None:
700 if symbol is None:
701 return None, context
701 return None, context
702
702
703 context = context[1:]
703 context = context[1:]
704 for i, name in enumerate(context):
704 for i, name in enumerate(context):
705 new_symbol = getattr(symbol, name, None)
705 new_symbol = getattr(symbol, name, None)
706 if new_symbol is None:
706 if new_symbol is None:
707 return symbol, context[i:]
707 return symbol, context[i:]
708 else:
708 else:
709 symbol = new_symbol
709 symbol = new_symbol
710
710
711 return symbol, []
711 return symbol, []
712
712
713 def _at_shutdown(self):
713 def _at_shutdown(self):
714 """Actions taken at shutdown by the kernel, called by python's atexit.
714 """Actions taken at shutdown by the kernel, called by python's atexit.
715 """
715 """
716 # io.rprint("Kernel at_shutdown") # dbg
716 # io.rprint("Kernel at_shutdown") # dbg
717 if self._shutdown_message is not None:
717 if self._shutdown_message is not None:
718 self.session.send(self.iopub_stream, self._shutdown_message, ident=self._topic('shutdown'))
718 self.session.send(self.iopub_stream, self._shutdown_message, ident=self._topic('shutdown'))
719 self.log.debug("%s", self._shutdown_message)
719 self.log.debug("%s", self._shutdown_message)
720 [ s.flush(zmq.POLLOUT) for s in self.shell_streams + [self.iopub_stream] ]
720 [ s.flush(zmq.POLLOUT) for s in self.shell_streams + [self.iopub_stream] ]
721
721
722 #-----------------------------------------------------------------------------
722 #-----------------------------------------------------------------------------
723 # Aliases and Flags for the IPKernelApp
723 # Aliases and Flags for the IPKernelApp
724 #-----------------------------------------------------------------------------
724 #-----------------------------------------------------------------------------
725
725
726 flags = dict(kernel_flags)
726 flags = dict(kernel_flags)
727 flags.update(shell_flags)
727 flags.update(shell_flags)
728
728
729 addflag = lambda *args: flags.update(boolean_flag(*args))
729 addflag = lambda *args: flags.update(boolean_flag(*args))
730
730
731 flags['pylab'] = (
731 flags['pylab'] = (
732 {'IPKernelApp' : {'pylab' : 'auto'}},
732 {'IPKernelApp' : {'pylab' : 'auto'}},
733 """Pre-load matplotlib and numpy for interactive use with
733 """Pre-load matplotlib and numpy for interactive use with
734 the default matplotlib backend."""
734 the default matplotlib backend."""
735 )
735 )
736
736
737 aliases = dict(kernel_aliases)
737 aliases = dict(kernel_aliases)
738 aliases.update(shell_aliases)
738 aliases.update(shell_aliases)
739
739
740 # it's possible we don't want short aliases for *all* of these:
740 # it's possible we don't want short aliases for *all* of these:
741 aliases.update(dict(
741 aliases.update(dict(
742 pylab='IPKernelApp.pylab',
742 pylab='IPKernelApp.pylab',
743 ))
743 ))
744
744
745 #-----------------------------------------------------------------------------
745 #-----------------------------------------------------------------------------
746 # The IPKernelApp class
746 # The IPKernelApp class
747 #-----------------------------------------------------------------------------
747 #-----------------------------------------------------------------------------
748
748
749 class IPKernelApp(KernelApp, InteractiveShellApp):
749 class IPKernelApp(KernelApp, InteractiveShellApp):
750 name = 'ipkernel'
750 name = 'ipkernel'
751
751
752 aliases = Dict(aliases)
752 aliases = Dict(aliases)
753 flags = Dict(flags)
753 flags = Dict(flags)
754 classes = [Kernel, ZMQInteractiveShell, ProfileDir, Session]
754 classes = [Kernel, ZMQInteractiveShell, ProfileDir, Session]
755
755
756 # configurables
756 # configurables
757 pylab = CaselessStrEnum(['tk', 'qt', 'wx', 'gtk', 'osx', 'inline', 'auto'],
757 pylab = CaselessStrEnum(['tk', 'qt', 'wx', 'gtk', 'osx', 'inline', 'auto'],
758 config=True,
758 config=True,
759 help="""Pre-load matplotlib and numpy for interactive use,
759 help="""Pre-load matplotlib and numpy for interactive use,
760 selecting a particular matplotlib backend and loop integration.
760 selecting a particular matplotlib backend and loop integration.
761 """
761 """
762 )
762 )
763
763
764 @catch_config_error
764 @catch_config_error
765 def initialize(self, argv=None):
765 def initialize(self, argv=None):
766 super(IPKernelApp, self).initialize(argv)
766 super(IPKernelApp, self).initialize(argv)
767 self.init_path()
767 self.init_path()
768 self.init_shell()
768 self.init_shell()
769 self.init_extensions()
769 self.init_extensions()
770 self.init_code()
770 self.init_code()
771
771
772 def init_kernel(self):
772 def init_kernel(self):
773
773
774 shell_stream = ZMQStream(self.shell_socket)
774 shell_stream = ZMQStream(self.shell_socket)
775 iopub_stream = ZMQStream(self.iopub_socket)
775 iopub_stream = ZMQStream(self.iopub_socket)
776
776
777 kernel = Kernel(config=self.config, session=self.session,
777 kernel = Kernel(config=self.config, session=self.session,
778 shell_streams=[shell_stream],
778 shell_streams=[shell_stream],
779 iopub_stream=iopub_stream,
779 iopub_stream=iopub_stream,
780 stdin_socket=self.stdin_socket,
780 stdin_socket=self.stdin_socket,
781 log=self.log,
781 log=self.log,
782 profile_dir=self.profile_dir,
782 profile_dir=self.profile_dir,
783 )
783 )
784 self.kernel = kernel
784 self.kernel = kernel
785 kernel.record_ports(self.ports)
785 kernel.record_ports(self.ports)
786 shell = kernel.shell
786 shell = kernel.shell
787 if self.pylab:
787 if self.pylab:
788 try:
788 try:
789 gui, backend = pylabtools.find_gui_and_backend(self.pylab)
789 gui, backend = pylabtools.find_gui_and_backend(self.pylab)
790 shell.enable_pylab(gui, import_all=self.pylab_import_all)
790 shell.enable_pylab(gui, import_all=self.pylab_import_all)
791 except Exception:
791 except Exception:
792 self.log.error("Pylab initialization failed", exc_info=True)
792 self.log.error("Pylab initialization failed", exc_info=True)
793 # print exception straight to stdout, because normally
793 # print exception straight to stdout, because normally
794 # _showtraceback associates the reply with an execution,
794 # _showtraceback associates the reply with an execution,
795 # which means frontends will never draw it, as this exception
795 # which means frontends will never draw it, as this exception
796 # is not associated with any execute request.
796 # is not associated with any execute request.
797
797
798 # replace pyerr-sending traceback with stdout
798 # replace pyerr-sending traceback with stdout
799 _showtraceback = shell._showtraceback
799 _showtraceback = shell._showtraceback
800 def print_tb(etype, evalue, stb):
800 def print_tb(etype, evalue, stb):
801 print ("Error initializing pylab, pylab mode will not "
801 print ("Error initializing pylab, pylab mode will not "
802 "be active", file=io.stderr)
802 "be active", file=io.stderr)
803 print (shell.InteractiveTB.stb2text(stb), file=io.stdout)
803 print (shell.InteractiveTB.stb2text(stb), file=io.stdout)
804 shell._showtraceback = print_tb
804 shell._showtraceback = print_tb
805
805
806 # send the traceback over stdout
806 # send the traceback over stdout
807 shell.showtraceback(tb_offset=0)
807 shell.showtraceback(tb_offset=0)
808
808
809 # restore proper _showtraceback method
809 # restore proper _showtraceback method
810 shell._showtraceback = _showtraceback
810 shell._showtraceback = _showtraceback
811
811
812
812
813 def init_shell(self):
813 def init_shell(self):
814 self.shell = self.kernel.shell
814 self.shell = self.kernel.shell
815 self.shell.configurables.append(self)
815 self.shell.configurables.append(self)
816
816
817
817
818 #-----------------------------------------------------------------------------
818 #-----------------------------------------------------------------------------
819 # Kernel main and launch functions
819 # Kernel main and launch functions
820 #-----------------------------------------------------------------------------
820 #-----------------------------------------------------------------------------
821
821
822 def launch_kernel(*args, **kwargs):
822 def launch_kernel(*args, **kwargs):
823 """Launches a localhost IPython kernel, binding to the specified ports.
823 """Launches a localhost IPython kernel, binding to the specified ports.
824
824
825 This function simply calls entry_point.base_launch_kernel with the right
825 This function simply calls entry_point.base_launch_kernel with the right
826 first command to start an ipkernel. See base_launch_kernel for arguments.
826 first command to start an ipkernel. See base_launch_kernel for arguments.
827
827
828 Returns
828 Returns
829 -------
829 -------
830 A tuple of form:
830 A tuple of form:
831 (kernel_process, shell_port, iopub_port, stdin_port, hb_port)
831 (kernel_process, shell_port, iopub_port, stdin_port, hb_port)
832 where kernel_process is a Popen object and the ports are integers.
832 where kernel_process is a Popen object and the ports are integers.
833 """
833 """
834 return base_launch_kernel('from IPython.zmq.ipkernel import main; main()',
834 return base_launch_kernel('from IPython.zmq.ipkernel import main; main()',
835 *args, **kwargs)
835 *args, **kwargs)
836
836
837
837
838 def embed_kernel(module=None, local_ns=None, **kwargs):
838 def embed_kernel(module=None, local_ns=None, **kwargs):
839 """Embed and start an IPython kernel in a given scope.
839 """Embed and start an IPython kernel in a given scope.
840
840
841 Parameters
841 Parameters
842 ----------
842 ----------
843 module : ModuleType, optional
843 module : ModuleType, optional
844 The module to load into IPython globals (default: caller)
844 The module to load into IPython globals (default: caller)
845 local_ns : dict, optional
845 local_ns : dict, optional
846 The namespace to load into IPython user namespace (default: caller)
846 The namespace to load into IPython user namespace (default: caller)
847
847
848 kwargs : various, optional
848 kwargs : various, optional
849 Further keyword args are relayed to the KernelApp constructor,
849 Further keyword args are relayed to the KernelApp constructor,
850 allowing configuration of the Kernel. Will only have an effect
850 allowing configuration of the Kernel. Will only have an effect
851 on the first embed_kernel call for a given process.
851 on the first embed_kernel call for a given process.
852
852
853 """
853 """
854 # get the app if it exists, or set it up if it doesn't
854 # get the app if it exists, or set it up if it doesn't
855 if IPKernelApp.initialized():
855 if IPKernelApp.initialized():
856 app = IPKernelApp.instance()
856 app = IPKernelApp.instance()
857 else:
857 else:
858 app = IPKernelApp.instance(**kwargs)
858 app = IPKernelApp.instance(**kwargs)
859 app.initialize([])
859 app.initialize([])
860
860
861 # load the calling scope if not given
861 # load the calling scope if not given
862 (caller_module, caller_locals) = extract_module_locals(1)
862 (caller_module, caller_locals) = extract_module_locals(1)
863 if module is None:
863 if module is None:
864 module = caller_module
864 module = caller_module
865 if local_ns is None:
865 if local_ns is None:
866 local_ns = caller_locals
866 local_ns = caller_locals
867
867
868 app.kernel.user_module = module
868 app.kernel.user_module = module
869 app.kernel.user_ns = local_ns
869 app.kernel.user_ns = local_ns
870 app.start()
870 app.start()
871
871
872 def main():
872 def main():
873 """Run an IPKernel as an application"""
873 """Run an IPKernel as an application"""
874 app = IPKernelApp.instance()
874 app = IPKernelApp.instance()
875 app.initialize()
875 app.initialize()
876 app.start()
876 app.start()
877
877
878
878
879 if __name__ == '__main__':
879 if __name__ == '__main__':
880 main()
880 main()
General Comments 0
You need to be logged in to leave comments. Login now