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