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