##// END OF EJS Templates
embed_kernel: only import zmq when needed
Scott Tsai -
Show More
@@ -1,63 +1,76 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """
2 """
3 IPython: tools for interactive and parallel computing in Python.
3 IPython: tools for interactive and parallel computing in Python.
4
4
5 http://ipython.org
5 http://ipython.org
6 """
6 """
7 #-----------------------------------------------------------------------------
7 #-----------------------------------------------------------------------------
8 # Copyright (c) 2008-2011, IPython Development Team.
8 # Copyright (c) 2008-2011, IPython Development Team.
9 # Copyright (c) 2001-2007, Fernando Perez <fernando.perez@colorado.edu>
9 # Copyright (c) 2001-2007, Fernando Perez <fernando.perez@colorado.edu>
10 # Copyright (c) 2001, Janko Hauser <jhauser@zscout.de>
10 # Copyright (c) 2001, Janko Hauser <jhauser@zscout.de>
11 # Copyright (c) 2001, Nathaniel Gray <n8gray@caltech.edu>
11 # Copyright (c) 2001, Nathaniel Gray <n8gray@caltech.edu>
12 #
12 #
13 # Distributed under the terms of the Modified BSD License.
13 # Distributed under the terms of the Modified BSD License.
14 #
14 #
15 # The full license is in the file COPYING.txt, distributed with this software.
15 # The full license is in the file COPYING.txt, distributed with this software.
16 #-----------------------------------------------------------------------------
16 #-----------------------------------------------------------------------------
17
17
18 #-----------------------------------------------------------------------------
18 #-----------------------------------------------------------------------------
19 # Imports
19 # Imports
20 #-----------------------------------------------------------------------------
20 #-----------------------------------------------------------------------------
21 from __future__ import absolute_import
21 from __future__ import absolute_import
22
22
23 import os
23 import os
24 import sys
24 import sys
25
25
26 #-----------------------------------------------------------------------------
26 #-----------------------------------------------------------------------------
27 # Setup everything
27 # Setup everything
28 #-----------------------------------------------------------------------------
28 #-----------------------------------------------------------------------------
29
29
30 # Don't forget to also update setup.py when this changes!
30 # Don't forget to also update setup.py when this changes!
31 if sys.version[0:3] < '2.6':
31 if sys.version[0:3] < '2.6':
32 raise ImportError('Python Version 2.6 or above is required for IPython.')
32 raise ImportError('Python Version 2.6 or above is required for IPython.')
33
33
34 # Make it easy to import extensions - they are always directly on pythonpath.
34 # Make it easy to import extensions - they are always directly on pythonpath.
35 # Therefore, non-IPython modules can be added to extensions directory.
35 # Therefore, non-IPython modules can be added to extensions directory.
36 # This should probably be in ipapp.py.
36 # This should probably be in ipapp.py.
37 sys.path.append(os.path.join(os.path.dirname(__file__), "extensions"))
37 sys.path.append(os.path.join(os.path.dirname(__file__), "extensions"))
38
38
39 #-----------------------------------------------------------------------------
39 #-----------------------------------------------------------------------------
40 # Setup the top level names
40 # Setup the top level names
41 #-----------------------------------------------------------------------------
41 #-----------------------------------------------------------------------------
42
42
43 from .config.loader import Config
43 from .config.loader import Config
44 from .core import release
44 from .core import release
45 from .core.application import Application
45 from .core.application import Application
46 from .frontend.terminal.embed import embed
46 from .frontend.terminal.embed import embed
47 try:
48 from .zmq.ipkernel import embed_kernel
49 except ImportError:
50 def embed_kernel(*args, **kwargs):
51 raise ImportError("IPython.embed_kernel requires pyzmq >= 2.1.4")
52
47
53 from .core.error import TryNext
48 from .core.error import TryNext
54 from .core.interactiveshell import InteractiveShell
49 from .core.interactiveshell import InteractiveShell
55 from .testing import test
50 from .testing import test
56 from .utils.sysinfo import sys_info
51 from .utils.sysinfo import sys_info
57
52
58 # Release data
53 # Release data
59 __author__ = ''
54 __author__ = ''
60 for author, email in release.authors.itervalues():
55 for author, email in release.authors.itervalues():
61 __author__ += author + ' <' + email + '>\n'
56 __author__ += author + ' <' + email + '>\n'
62 __license__ = release.license
57 __license__ = release.license
63 __version__ = release.version
58 __version__ = release.version
59
60 def caller_module_and_locals():
61 """Returns (module, locals) of the caller"""
62 caller = sys._getframe(2)
63 global_ns = caller.f_globals
64 module = sys.modules[global_ns['__name__']]
65 return (module, caller.f_locals)
66
67 def embed_kernel(module=None, local_ns=None):
68 """Call this to embed an IPython kernel at the current point in your program. """
69 (caller_module, caller_locals) = caller_module_and_locals()
70 if module is None:
71 module = caller_module
72 if local_ns is None:
73 local_ns = caller_locals
74 # Only import .zmq when we really need it
75 from .zmq.ipkernel import embed_kernel as real_embed_kernel
76 real_embed_kernel(module, local_ns)
@@ -1,674 +1,661 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.jsonutil import json_clean
42 from IPython.utils.jsonutil import json_clean
43 from IPython.utils.traitlets import (
43 from IPython.utils.traitlets import (
44 Any, Instance, Float, Dict, CaselessStrEnum
44 Any, Instance, Float, Dict, CaselessStrEnum
45 )
45 )
46
46
47 from entry_point import base_launch_kernel
47 from entry_point import base_launch_kernel
48 from kernelapp import KernelApp, kernel_flags, kernel_aliases
48 from kernelapp import KernelApp, kernel_flags, kernel_aliases
49 from session import Session, Message
49 from session import Session, Message
50 from zmqshell import ZMQInteractiveShell
50 from zmqshell import ZMQInteractiveShell
51
51
52
52
53 #-----------------------------------------------------------------------------
53 #-----------------------------------------------------------------------------
54 # Main kernel class
54 # Main kernel class
55 #-----------------------------------------------------------------------------
55 #-----------------------------------------------------------------------------
56
56
57 class Kernel(Configurable):
57 class Kernel(Configurable):
58
58
59 #---------------------------------------------------------------------------
59 #---------------------------------------------------------------------------
60 # Kernel interface
60 # Kernel interface
61 #---------------------------------------------------------------------------
61 #---------------------------------------------------------------------------
62
62
63 # attribute to override with a GUI
63 # attribute to override with a GUI
64 eventloop = Any(None)
64 eventloop = Any(None)
65
65
66 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
66 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
67 session = Instance(Session)
67 session = Instance(Session)
68 profile_dir = Instance('IPython.core.profiledir.ProfileDir')
68 profile_dir = Instance('IPython.core.profiledir.ProfileDir')
69 shell_socket = Instance('zmq.Socket')
69 shell_socket = Instance('zmq.Socket')
70 iopub_socket = Instance('zmq.Socket')
70 iopub_socket = Instance('zmq.Socket')
71 stdin_socket = Instance('zmq.Socket')
71 stdin_socket = Instance('zmq.Socket')
72 log = Instance(logging.Logger)
72 log = Instance(logging.Logger)
73 user_module = Instance('types.ModuleType')
73 user_module = Instance('types.ModuleType')
74 user_ns = Dict(default_value=None)
74 user_ns = Dict(default_value=None)
75
75
76 # Private interface
76 # Private interface
77
77
78 # Time to sleep after flushing the stdout/err buffers in each execute
78 # Time to sleep after flushing the stdout/err buffers in each execute
79 # cycle. While this introduces a hard limit on the minimal latency of the
79 # cycle. While this introduces a hard limit on the minimal latency of the
80 # execute cycle, it helps prevent output synchronization problems for
80 # execute cycle, it helps prevent output synchronization problems for
81 # clients.
81 # clients.
82 # Units are in seconds. The minimum zmq latency on local host is probably
82 # Units are in seconds. The minimum zmq latency on local host is probably
83 # ~150 microseconds, set this to 500us for now. We may need to increase it
83 # ~150 microseconds, set this to 500us for now. We may need to increase it
84 # a little if it's not enough after more interactive testing.
84 # a little if it's not enough after more interactive testing.
85 _execute_sleep = Float(0.0005, config=True)
85 _execute_sleep = Float(0.0005, config=True)
86
86
87 # Frequency of the kernel's event loop.
87 # Frequency of the kernel's event loop.
88 # Units are in seconds, kernel subclasses for GUI toolkits may need to
88 # Units are in seconds, kernel subclasses for GUI toolkits may need to
89 # adapt to milliseconds.
89 # adapt to milliseconds.
90 _poll_interval = Float(0.05, config=True)
90 _poll_interval = Float(0.05, config=True)
91
91
92 # If the shutdown was requested over the network, we leave here the
92 # If the shutdown was requested over the network, we leave here the
93 # necessary reply message so it can be sent by our registered atexit
93 # necessary reply message so it can be sent by our registered atexit
94 # handler. This ensures that the reply is only sent to clients truly at
94 # handler. This ensures that the reply is only sent to clients truly at
95 # the end of our shutdown process (which happens after the underlying
95 # the end of our shutdown process (which happens after the underlying
96 # IPython shell's own shutdown).
96 # IPython shell's own shutdown).
97 _shutdown_message = None
97 _shutdown_message = None
98
98
99 # This is a dict of port number that the kernel is listening on. It is set
99 # This is a dict of port number that the kernel is listening on. It is set
100 # by record_ports and used by connect_request.
100 # by record_ports and used by connect_request.
101 _recorded_ports = Dict()
101 _recorded_ports = Dict()
102
102
103
103
104
104
105 def __init__(self, **kwargs):
105 def __init__(self, **kwargs):
106 super(Kernel, self).__init__(**kwargs)
106 super(Kernel, self).__init__(**kwargs)
107
107
108 # Before we even start up the shell, register *first* our exit handlers
108 # Before we even start up the shell, register *first* our exit handlers
109 # so they come before the shell's
109 # so they come before the shell's
110 atexit.register(self._at_shutdown)
110 atexit.register(self._at_shutdown)
111
111
112 # Initialize the InteractiveShell subclass
112 # Initialize the InteractiveShell subclass
113 self.shell = ZMQInteractiveShell.instance(config=self.config,
113 self.shell = ZMQInteractiveShell.instance(config=self.config,
114 profile_dir = self.profile_dir,
114 profile_dir = self.profile_dir,
115 user_module = self.user_module,
115 user_module = self.user_module,
116 user_ns = self.user_ns,
116 user_ns = self.user_ns,
117 )
117 )
118 self.shell.displayhook.session = self.session
118 self.shell.displayhook.session = self.session
119 self.shell.displayhook.pub_socket = self.iopub_socket
119 self.shell.displayhook.pub_socket = self.iopub_socket
120 self.shell.display_pub.session = self.session
120 self.shell.display_pub.session = self.session
121 self.shell.display_pub.pub_socket = self.iopub_socket
121 self.shell.display_pub.pub_socket = self.iopub_socket
122
122
123 # TMP - hack while developing
123 # TMP - hack while developing
124 self.shell._reply_content = None
124 self.shell._reply_content = None
125
125
126 # Build dict of handlers for message types
126 # Build dict of handlers for message types
127 msg_types = [ 'execute_request', 'complete_request',
127 msg_types = [ 'execute_request', 'complete_request',
128 'object_info_request', 'history_request',
128 'object_info_request', 'history_request',
129 'connect_request', 'shutdown_request']
129 'connect_request', 'shutdown_request']
130 self.handlers = {}
130 self.handlers = {}
131 for msg_type in msg_types:
131 for msg_type in msg_types:
132 self.handlers[msg_type] = getattr(self, msg_type)
132 self.handlers[msg_type] = getattr(self, msg_type)
133
133
134 def do_one_iteration(self):
134 def do_one_iteration(self):
135 """Do one iteration of the kernel's evaluation loop.
135 """Do one iteration of the kernel's evaluation loop.
136 """
136 """
137 try:
137 try:
138 ident,msg = self.session.recv(self.shell_socket, zmq.NOBLOCK)
138 ident,msg = self.session.recv(self.shell_socket, zmq.NOBLOCK)
139 except Exception:
139 except Exception:
140 self.log.warn("Invalid Message:", exc_info=True)
140 self.log.warn("Invalid Message:", exc_info=True)
141 return
141 return
142 if msg is None:
142 if msg is None:
143 return
143 return
144
144
145 msg_type = msg['header']['msg_type']
145 msg_type = msg['header']['msg_type']
146
146
147 # This assert will raise in versions of zeromq 2.0.7 and lesser.
147 # This assert will raise in versions of zeromq 2.0.7 and lesser.
148 # We now require 2.0.8 or above, so we can uncomment for safety.
148 # We now require 2.0.8 or above, so we can uncomment for safety.
149 # print(ident,msg, file=sys.__stdout__)
149 # print(ident,msg, file=sys.__stdout__)
150 assert ident is not None, "Missing message part."
150 assert ident is not None, "Missing message part."
151
151
152 # Print some info about this message and leave a '--->' marker, so it's
152 # Print some info about this message and leave a '--->' marker, so it's
153 # easier to trace visually the message chain when debugging. Each
153 # easier to trace visually the message chain when debugging. Each
154 # handler prints its message at the end.
154 # handler prints its message at the end.
155 self.log.debug('\n*** MESSAGE TYPE:'+str(msg_type)+'***')
155 self.log.debug('\n*** MESSAGE TYPE:'+str(msg_type)+'***')
156 self.log.debug(' Content: '+str(msg['content'])+'\n --->\n ')
156 self.log.debug(' Content: '+str(msg['content'])+'\n --->\n ')
157
157
158 # Find and call actual handler for message
158 # Find and call actual handler for message
159 handler = self.handlers.get(msg_type, None)
159 handler = self.handlers.get(msg_type, None)
160 if handler is None:
160 if handler is None:
161 self.log.error("UNKNOWN MESSAGE TYPE:" +str(msg))
161 self.log.error("UNKNOWN MESSAGE TYPE:" +str(msg))
162 else:
162 else:
163 handler(ident, msg)
163 handler(ident, msg)
164
164
165 # Check whether we should exit, in case the incoming message set the
165 # Check whether we should exit, in case the incoming message set the
166 # exit flag on
166 # exit flag on
167 if self.shell.exit_now:
167 if self.shell.exit_now:
168 self.log.debug('\nExiting IPython kernel...')
168 self.log.debug('\nExiting IPython kernel...')
169 # We do a normal, clean exit, which allows any actions registered
169 # We do a normal, clean exit, which allows any actions registered
170 # via atexit (such as history saving) to take place.
170 # via atexit (such as history saving) to take place.
171 sys.exit(0)
171 sys.exit(0)
172
172
173
173
174 def start(self):
174 def start(self):
175 """ Start the kernel main loop.
175 """ Start the kernel main loop.
176 """
176 """
177 # a KeyboardInterrupt (SIGINT) can occur on any python statement, so
177 # a KeyboardInterrupt (SIGINT) can occur on any python statement, so
178 # let's ignore (SIG_IGN) them until we're in a place to handle them properly
178 # let's ignore (SIG_IGN) them until we're in a place to handle them properly
179 signal(SIGINT,SIG_IGN)
179 signal(SIGINT,SIG_IGN)
180 poller = zmq.Poller()
180 poller = zmq.Poller()
181 poller.register(self.shell_socket, zmq.POLLIN)
181 poller.register(self.shell_socket, zmq.POLLIN)
182 # loop while self.eventloop has not been overridden
182 # loop while self.eventloop has not been overridden
183 while self.eventloop is None:
183 while self.eventloop is None:
184 try:
184 try:
185 # scale by extra factor of 10, because there is no
185 # scale by extra factor of 10, because there is no
186 # reason for this to be anything less than ~ 0.1s
186 # reason for this to be anything less than ~ 0.1s
187 # since it is a real poller and will respond
187 # since it is a real poller and will respond
188 # to events immediately
188 # to events immediately
189
189
190 # double nested try/except, to properly catch KeyboardInterrupt
190 # double nested try/except, to properly catch KeyboardInterrupt
191 # due to pyzmq Issue #130
191 # due to pyzmq Issue #130
192 try:
192 try:
193 poller.poll(10*1000*self._poll_interval)
193 poller.poll(10*1000*self._poll_interval)
194 # restore raising of KeyboardInterrupt
194 # restore raising of KeyboardInterrupt
195 signal(SIGINT, default_int_handler)
195 signal(SIGINT, default_int_handler)
196 self.do_one_iteration()
196 self.do_one_iteration()
197 except:
197 except:
198 raise
198 raise
199 finally:
199 finally:
200 # prevent raising of KeyboardInterrupt
200 # prevent raising of KeyboardInterrupt
201 signal(SIGINT,SIG_IGN)
201 signal(SIGINT,SIG_IGN)
202 except KeyboardInterrupt:
202 except KeyboardInterrupt:
203 # Ctrl-C shouldn't crash the kernel
203 # Ctrl-C shouldn't crash the kernel
204 io.raw_print("KeyboardInterrupt caught in kernel")
204 io.raw_print("KeyboardInterrupt caught in kernel")
205 # stop ignoring sigint, now that we are out of our own loop,
205 # stop ignoring sigint, now that we are out of our own loop,
206 # we don't want to prevent future code from handling it
206 # we don't want to prevent future code from handling it
207 signal(SIGINT, default_int_handler)
207 signal(SIGINT, default_int_handler)
208 if self.eventloop is not None:
208 if self.eventloop is not None:
209 try:
209 try:
210 self.eventloop(self)
210 self.eventloop(self)
211 except KeyboardInterrupt:
211 except KeyboardInterrupt:
212 # Ctrl-C shouldn't crash the kernel
212 # Ctrl-C shouldn't crash the kernel
213 io.raw_print("KeyboardInterrupt caught in kernel")
213 io.raw_print("KeyboardInterrupt caught in kernel")
214
214
215
215
216 def record_ports(self, ports):
216 def record_ports(self, ports):
217 """Record the ports that this kernel is using.
217 """Record the ports that this kernel is using.
218
218
219 The creator of the Kernel instance must call this methods if they
219 The creator of the Kernel instance must call this methods if they
220 want the :meth:`connect_request` method to return the port numbers.
220 want the :meth:`connect_request` method to return the port numbers.
221 """
221 """
222 self._recorded_ports = ports
222 self._recorded_ports = ports
223
223
224 #---------------------------------------------------------------------------
224 #---------------------------------------------------------------------------
225 # Kernel request handlers
225 # Kernel request handlers
226 #---------------------------------------------------------------------------
226 #---------------------------------------------------------------------------
227
227
228 def _publish_pyin(self, code, parent):
228 def _publish_pyin(self, code, parent):
229 """Publish the code request on the pyin stream."""
229 """Publish the code request on the pyin stream."""
230
230
231 self.session.send(self.iopub_socket, u'pyin', {u'code':code},
231 self.session.send(self.iopub_socket, u'pyin', {u'code':code},
232 parent=parent)
232 parent=parent)
233
233
234 def execute_request(self, ident, parent):
234 def execute_request(self, ident, parent):
235
235
236 self.session.send(self.iopub_socket,
236 self.session.send(self.iopub_socket,
237 u'status',
237 u'status',
238 {u'execution_state':u'busy'},
238 {u'execution_state':u'busy'},
239 parent=parent )
239 parent=parent )
240
240
241 try:
241 try:
242 content = parent[u'content']
242 content = parent[u'content']
243 code = content[u'code']
243 code = content[u'code']
244 silent = content[u'silent']
244 silent = content[u'silent']
245 except:
245 except:
246 self.log.error("Got bad msg: ")
246 self.log.error("Got bad msg: ")
247 self.log.error(str(Message(parent)))
247 self.log.error(str(Message(parent)))
248 return
248 return
249
249
250 shell = self.shell # we'll need this a lot here
250 shell = self.shell # we'll need this a lot here
251
251
252 # Replace raw_input. Note that is not sufficient to replace
252 # Replace raw_input. Note that is not sufficient to replace
253 # raw_input in the user namespace.
253 # raw_input in the user namespace.
254 if content.get('allow_stdin', False):
254 if content.get('allow_stdin', False):
255 raw_input = lambda prompt='': self._raw_input(prompt, ident, parent)
255 raw_input = lambda prompt='': self._raw_input(prompt, ident, parent)
256 else:
256 else:
257 raw_input = lambda prompt='' : self._no_raw_input()
257 raw_input = lambda prompt='' : self._no_raw_input()
258
258
259 if py3compat.PY3:
259 if py3compat.PY3:
260 __builtin__.input = raw_input
260 __builtin__.input = raw_input
261 else:
261 else:
262 __builtin__.raw_input = raw_input
262 __builtin__.raw_input = raw_input
263
263
264 # Set the parent message of the display hook and out streams.
264 # Set the parent message of the display hook and out streams.
265 shell.displayhook.set_parent(parent)
265 shell.displayhook.set_parent(parent)
266 shell.display_pub.set_parent(parent)
266 shell.display_pub.set_parent(parent)
267 sys.stdout.set_parent(parent)
267 sys.stdout.set_parent(parent)
268 sys.stderr.set_parent(parent)
268 sys.stderr.set_parent(parent)
269
269
270 # Re-broadcast our input for the benefit of listening clients, and
270 # Re-broadcast our input for the benefit of listening clients, and
271 # start computing output
271 # start computing output
272 if not silent:
272 if not silent:
273 self._publish_pyin(code, parent)
273 self._publish_pyin(code, parent)
274
274
275 reply_content = {}
275 reply_content = {}
276 try:
276 try:
277 if silent:
277 if silent:
278 # run_code uses 'exec' mode, so no displayhook will fire, and it
278 # run_code uses 'exec' mode, so no displayhook will fire, and it
279 # doesn't call logging or history manipulations. Print
279 # doesn't call logging or history manipulations. Print
280 # statements in that code will obviously still execute.
280 # statements in that code will obviously still execute.
281 shell.run_code(code)
281 shell.run_code(code)
282 else:
282 else:
283 # FIXME: the shell calls the exception handler itself.
283 # FIXME: the shell calls the exception handler itself.
284 shell.run_cell(code, store_history=True)
284 shell.run_cell(code, store_history=True)
285 except:
285 except:
286 status = u'error'
286 status = u'error'
287 # FIXME: this code right now isn't being used yet by default,
287 # FIXME: this code right now isn't being used yet by default,
288 # because the run_cell() call above directly fires off exception
288 # because the run_cell() call above directly fires off exception
289 # reporting. This code, therefore, is only active in the scenario
289 # reporting. This code, therefore, is only active in the scenario
290 # where runlines itself has an unhandled exception. We need to
290 # where runlines itself has an unhandled exception. We need to
291 # uniformize this, for all exception construction to come from a
291 # uniformize this, for all exception construction to come from a
292 # single location in the codbase.
292 # single location in the codbase.
293 etype, evalue, tb = sys.exc_info()
293 etype, evalue, tb = sys.exc_info()
294 tb_list = traceback.format_exception(etype, evalue, tb)
294 tb_list = traceback.format_exception(etype, evalue, tb)
295 reply_content.update(shell._showtraceback(etype, evalue, tb_list))
295 reply_content.update(shell._showtraceback(etype, evalue, tb_list))
296 else:
296 else:
297 status = u'ok'
297 status = u'ok'
298
298
299 reply_content[u'status'] = status
299 reply_content[u'status'] = status
300
300
301 # Return the execution counter so clients can display prompts
301 # Return the execution counter so clients can display prompts
302 reply_content['execution_count'] = shell.execution_count -1
302 reply_content['execution_count'] = shell.execution_count -1
303
303
304 # FIXME - fish exception info out of shell, possibly left there by
304 # FIXME - fish exception info out of shell, possibly left there by
305 # runlines. We'll need to clean up this logic later.
305 # runlines. We'll need to clean up this logic later.
306 if shell._reply_content is not None:
306 if shell._reply_content is not None:
307 reply_content.update(shell._reply_content)
307 reply_content.update(shell._reply_content)
308 # reset after use
308 # reset after use
309 shell._reply_content = None
309 shell._reply_content = None
310
310
311 # At this point, we can tell whether the main code execution succeeded
311 # At this point, we can tell whether the main code execution succeeded
312 # or not. If it did, we proceed to evaluate user_variables/expressions
312 # or not. If it did, we proceed to evaluate user_variables/expressions
313 if reply_content['status'] == 'ok':
313 if reply_content['status'] == 'ok':
314 reply_content[u'user_variables'] = \
314 reply_content[u'user_variables'] = \
315 shell.user_variables(content[u'user_variables'])
315 shell.user_variables(content[u'user_variables'])
316 reply_content[u'user_expressions'] = \
316 reply_content[u'user_expressions'] = \
317 shell.user_expressions(content[u'user_expressions'])
317 shell.user_expressions(content[u'user_expressions'])
318 else:
318 else:
319 # If there was an error, don't even try to compute variables or
319 # If there was an error, don't even try to compute variables or
320 # expressions
320 # expressions
321 reply_content[u'user_variables'] = {}
321 reply_content[u'user_variables'] = {}
322 reply_content[u'user_expressions'] = {}
322 reply_content[u'user_expressions'] = {}
323
323
324 # Payloads should be retrieved regardless of outcome, so we can both
324 # Payloads should be retrieved regardless of outcome, so we can both
325 # recover partial output (that could have been generated early in a
325 # recover partial output (that could have been generated early in a
326 # block, before an error) and clear the payload system always.
326 # block, before an error) and clear the payload system always.
327 reply_content[u'payload'] = shell.payload_manager.read_payload()
327 reply_content[u'payload'] = shell.payload_manager.read_payload()
328 # Be agressive about clearing the payload because we don't want
328 # Be agressive about clearing the payload because we don't want
329 # it to sit in memory until the next execute_request comes in.
329 # it to sit in memory until the next execute_request comes in.
330 shell.payload_manager.clear_payload()
330 shell.payload_manager.clear_payload()
331
331
332 # Flush output before sending the reply.
332 # Flush output before sending the reply.
333 sys.stdout.flush()
333 sys.stdout.flush()
334 sys.stderr.flush()
334 sys.stderr.flush()
335 # FIXME: on rare occasions, the flush doesn't seem to make it to the
335 # FIXME: on rare occasions, the flush doesn't seem to make it to the
336 # clients... This seems to mitigate the problem, but we definitely need
336 # clients... This seems to mitigate the problem, but we definitely need
337 # to better understand what's going on.
337 # to better understand what's going on.
338 if self._execute_sleep:
338 if self._execute_sleep:
339 time.sleep(self._execute_sleep)
339 time.sleep(self._execute_sleep)
340
340
341 # Send the reply.
341 # Send the reply.
342 reply_content = json_clean(reply_content)
342 reply_content = json_clean(reply_content)
343 reply_msg = self.session.send(self.shell_socket, u'execute_reply',
343 reply_msg = self.session.send(self.shell_socket, u'execute_reply',
344 reply_content, parent, ident=ident)
344 reply_content, parent, ident=ident)
345 self.log.debug(str(reply_msg))
345 self.log.debug(str(reply_msg))
346
346
347 if reply_msg['content']['status'] == u'error':
347 if reply_msg['content']['status'] == u'error':
348 self._abort_queue()
348 self._abort_queue()
349
349
350 self.session.send(self.iopub_socket,
350 self.session.send(self.iopub_socket,
351 u'status',
351 u'status',
352 {u'execution_state':u'idle'},
352 {u'execution_state':u'idle'},
353 parent=parent )
353 parent=parent )
354
354
355 def complete_request(self, ident, parent):
355 def complete_request(self, ident, parent):
356 txt, matches = self._complete(parent)
356 txt, matches = self._complete(parent)
357 matches = {'matches' : matches,
357 matches = {'matches' : matches,
358 'matched_text' : txt,
358 'matched_text' : txt,
359 'status' : 'ok'}
359 'status' : 'ok'}
360 matches = json_clean(matches)
360 matches = json_clean(matches)
361 completion_msg = self.session.send(self.shell_socket, 'complete_reply',
361 completion_msg = self.session.send(self.shell_socket, 'complete_reply',
362 matches, parent, ident)
362 matches, parent, ident)
363 self.log.debug(str(completion_msg))
363 self.log.debug(str(completion_msg))
364
364
365 def object_info_request(self, ident, parent):
365 def object_info_request(self, ident, parent):
366 object_info = self.shell.object_inspect(parent['content']['oname'])
366 object_info = self.shell.object_inspect(parent['content']['oname'])
367 # Before we send this object over, we scrub it for JSON usage
367 # Before we send this object over, we scrub it for JSON usage
368 oinfo = json_clean(object_info)
368 oinfo = json_clean(object_info)
369 msg = self.session.send(self.shell_socket, 'object_info_reply',
369 msg = self.session.send(self.shell_socket, 'object_info_reply',
370 oinfo, parent, ident)
370 oinfo, parent, ident)
371 self.log.debug(msg)
371 self.log.debug(msg)
372
372
373 def history_request(self, ident, parent):
373 def history_request(self, ident, parent):
374 # We need to pull these out, as passing **kwargs doesn't work with
374 # We need to pull these out, as passing **kwargs doesn't work with
375 # unicode keys before Python 2.6.5.
375 # unicode keys before Python 2.6.5.
376 hist_access_type = parent['content']['hist_access_type']
376 hist_access_type = parent['content']['hist_access_type']
377 raw = parent['content']['raw']
377 raw = parent['content']['raw']
378 output = parent['content']['output']
378 output = parent['content']['output']
379 if hist_access_type == 'tail':
379 if hist_access_type == 'tail':
380 n = parent['content']['n']
380 n = parent['content']['n']
381 hist = self.shell.history_manager.get_tail(n, raw=raw, output=output,
381 hist = self.shell.history_manager.get_tail(n, raw=raw, output=output,
382 include_latest=True)
382 include_latest=True)
383
383
384 elif hist_access_type == 'range':
384 elif hist_access_type == 'range':
385 session = parent['content']['session']
385 session = parent['content']['session']
386 start = parent['content']['start']
386 start = parent['content']['start']
387 stop = parent['content']['stop']
387 stop = parent['content']['stop']
388 hist = self.shell.history_manager.get_range(session, start, stop,
388 hist = self.shell.history_manager.get_range(session, start, stop,
389 raw=raw, output=output)
389 raw=raw, output=output)
390
390
391 elif hist_access_type == 'search':
391 elif hist_access_type == 'search':
392 pattern = parent['content']['pattern']
392 pattern = parent['content']['pattern']
393 hist = self.shell.history_manager.search(pattern, raw=raw,
393 hist = self.shell.history_manager.search(pattern, raw=raw,
394 output=output)
394 output=output)
395
395
396 else:
396 else:
397 hist = []
397 hist = []
398 content = {'history' : list(hist)}
398 content = {'history' : list(hist)}
399 content = json_clean(content)
399 content = json_clean(content)
400 msg = self.session.send(self.shell_socket, 'history_reply',
400 msg = self.session.send(self.shell_socket, 'history_reply',
401 content, parent, ident)
401 content, parent, ident)
402 self.log.debug(str(msg))
402 self.log.debug(str(msg))
403
403
404 def connect_request(self, ident, parent):
404 def connect_request(self, ident, parent):
405 if self._recorded_ports is not None:
405 if self._recorded_ports is not None:
406 content = self._recorded_ports.copy()
406 content = self._recorded_ports.copy()
407 else:
407 else:
408 content = {}
408 content = {}
409 msg = self.session.send(self.shell_socket, 'connect_reply',
409 msg = self.session.send(self.shell_socket, 'connect_reply',
410 content, parent, ident)
410 content, parent, ident)
411 self.log.debug(msg)
411 self.log.debug(msg)
412
412
413 def shutdown_request(self, ident, parent):
413 def shutdown_request(self, ident, parent):
414 self.shell.exit_now = True
414 self.shell.exit_now = True
415 self._shutdown_message = self.session.msg(u'shutdown_reply',
415 self._shutdown_message = self.session.msg(u'shutdown_reply',
416 parent['content'], parent)
416 parent['content'], parent)
417 sys.exit(0)
417 sys.exit(0)
418
418
419 #---------------------------------------------------------------------------
419 #---------------------------------------------------------------------------
420 # Protected interface
420 # Protected interface
421 #---------------------------------------------------------------------------
421 #---------------------------------------------------------------------------
422
422
423 def _abort_queue(self):
423 def _abort_queue(self):
424 while True:
424 while True:
425 try:
425 try:
426 ident,msg = self.session.recv(self.shell_socket, zmq.NOBLOCK)
426 ident,msg = self.session.recv(self.shell_socket, zmq.NOBLOCK)
427 except Exception:
427 except Exception:
428 self.log.warn("Invalid Message:", exc_info=True)
428 self.log.warn("Invalid Message:", exc_info=True)
429 continue
429 continue
430 if msg is None:
430 if msg is None:
431 break
431 break
432 else:
432 else:
433 assert ident is not None, \
433 assert ident is not None, \
434 "Unexpected missing message part."
434 "Unexpected missing message part."
435
435
436 self.log.debug("Aborting:\n"+str(Message(msg)))
436 self.log.debug("Aborting:\n"+str(Message(msg)))
437 msg_type = msg['header']['msg_type']
437 msg_type = msg['header']['msg_type']
438 reply_type = msg_type.split('_')[0] + '_reply'
438 reply_type = msg_type.split('_')[0] + '_reply'
439 reply_msg = self.session.send(self.shell_socket, reply_type,
439 reply_msg = self.session.send(self.shell_socket, reply_type,
440 {'status' : 'aborted'}, msg, ident=ident)
440 {'status' : 'aborted'}, msg, ident=ident)
441 self.log.debug(reply_msg)
441 self.log.debug(reply_msg)
442 # We need to wait a bit for requests to come in. This can probably
442 # We need to wait a bit for requests to come in. This can probably
443 # be set shorter for true asynchronous clients.
443 # be set shorter for true asynchronous clients.
444 time.sleep(0.1)
444 time.sleep(0.1)
445
445
446 def _no_raw_input(self):
446 def _no_raw_input(self):
447 """Raise StdinNotImplentedError if active frontend doesn't support
447 """Raise StdinNotImplentedError if active frontend doesn't support
448 stdin."""
448 stdin."""
449 raise StdinNotImplementedError("raw_input was called, but this "
449 raise StdinNotImplementedError("raw_input was called, but this "
450 "frontend does not support stdin.")
450 "frontend does not support stdin.")
451
451
452 def _raw_input(self, prompt, ident, parent):
452 def _raw_input(self, prompt, ident, parent):
453 # Flush output before making the request.
453 # Flush output before making the request.
454 sys.stderr.flush()
454 sys.stderr.flush()
455 sys.stdout.flush()
455 sys.stdout.flush()
456
456
457 # Send the input request.
457 # Send the input request.
458 content = json_clean(dict(prompt=prompt))
458 content = json_clean(dict(prompt=prompt))
459 self.session.send(self.stdin_socket, u'input_request', content, parent,
459 self.session.send(self.stdin_socket, u'input_request', content, parent,
460 ident=ident)
460 ident=ident)
461
461
462 # Await a response.
462 # Await a response.
463 while True:
463 while True:
464 try:
464 try:
465 ident, reply = self.session.recv(self.stdin_socket, 0)
465 ident, reply = self.session.recv(self.stdin_socket, 0)
466 except Exception:
466 except Exception:
467 self.log.warn("Invalid Message:", exc_info=True)
467 self.log.warn("Invalid Message:", exc_info=True)
468 else:
468 else:
469 break
469 break
470 try:
470 try:
471 value = reply['content']['value']
471 value = reply['content']['value']
472 except:
472 except:
473 self.log.error("Got bad raw_input reply: ")
473 self.log.error("Got bad raw_input reply: ")
474 self.log.error(str(Message(parent)))
474 self.log.error(str(Message(parent)))
475 value = ''
475 value = ''
476 if value == '\x04':
476 if value == '\x04':
477 # EOF
477 # EOF
478 raise EOFError
478 raise EOFError
479 return value
479 return value
480
480
481 def _complete(self, msg):
481 def _complete(self, msg):
482 c = msg['content']
482 c = msg['content']
483 try:
483 try:
484 cpos = int(c['cursor_pos'])
484 cpos = int(c['cursor_pos'])
485 except:
485 except:
486 # If we don't get something that we can convert to an integer, at
486 # If we don't get something that we can convert to an integer, at
487 # least attempt the completion guessing the cursor is at the end of
487 # least attempt the completion guessing the cursor is at the end of
488 # the text, if there's any, and otherwise of the line
488 # the text, if there's any, and otherwise of the line
489 cpos = len(c['text'])
489 cpos = len(c['text'])
490 if cpos==0:
490 if cpos==0:
491 cpos = len(c['line'])
491 cpos = len(c['line'])
492 return self.shell.complete(c['text'], c['line'], cpos)
492 return self.shell.complete(c['text'], c['line'], cpos)
493
493
494 def _object_info(self, context):
494 def _object_info(self, context):
495 symbol, leftover = self._symbol_from_context(context)
495 symbol, leftover = self._symbol_from_context(context)
496 if symbol is not None and not leftover:
496 if symbol is not None and not leftover:
497 doc = getattr(symbol, '__doc__', '')
497 doc = getattr(symbol, '__doc__', '')
498 else:
498 else:
499 doc = ''
499 doc = ''
500 object_info = dict(docstring = doc)
500 object_info = dict(docstring = doc)
501 return object_info
501 return object_info
502
502
503 def _symbol_from_context(self, context):
503 def _symbol_from_context(self, context):
504 if not context:
504 if not context:
505 return None, context
505 return None, context
506
506
507 base_symbol_string = context[0]
507 base_symbol_string = context[0]
508 symbol = self.shell.user_ns.get(base_symbol_string, None)
508 symbol = self.shell.user_ns.get(base_symbol_string, None)
509 if symbol is None:
509 if symbol is None:
510 symbol = __builtin__.__dict__.get(base_symbol_string, None)
510 symbol = __builtin__.__dict__.get(base_symbol_string, None)
511 if symbol is None:
511 if symbol is None:
512 return None, context
512 return None, context
513
513
514 context = context[1:]
514 context = context[1:]
515 for i, name in enumerate(context):
515 for i, name in enumerate(context):
516 new_symbol = getattr(symbol, name, None)
516 new_symbol = getattr(symbol, name, None)
517 if new_symbol is None:
517 if new_symbol is None:
518 return symbol, context[i:]
518 return symbol, context[i:]
519 else:
519 else:
520 symbol = new_symbol
520 symbol = new_symbol
521
521
522 return symbol, []
522 return symbol, []
523
523
524 def _at_shutdown(self):
524 def _at_shutdown(self):
525 """Actions taken at shutdown by the kernel, called by python's atexit.
525 """Actions taken at shutdown by the kernel, called by python's atexit.
526 """
526 """
527 # io.rprint("Kernel at_shutdown") # dbg
527 # io.rprint("Kernel at_shutdown") # dbg
528 if self._shutdown_message is not None:
528 if self._shutdown_message is not None:
529 self.session.send(self.shell_socket, self._shutdown_message)
529 self.session.send(self.shell_socket, self._shutdown_message)
530 self.session.send(self.iopub_socket, self._shutdown_message)
530 self.session.send(self.iopub_socket, self._shutdown_message)
531 self.log.debug(str(self._shutdown_message))
531 self.log.debug(str(self._shutdown_message))
532 # A very short sleep to give zmq time to flush its message buffers
532 # A very short sleep to give zmq time to flush its message buffers
533 # before Python truly shuts down.
533 # before Python truly shuts down.
534 time.sleep(0.01)
534 time.sleep(0.01)
535
535
536 #-----------------------------------------------------------------------------
536 #-----------------------------------------------------------------------------
537 # Aliases and Flags for the IPKernelApp
537 # Aliases and Flags for the IPKernelApp
538 #-----------------------------------------------------------------------------
538 #-----------------------------------------------------------------------------
539
539
540 flags = dict(kernel_flags)
540 flags = dict(kernel_flags)
541 flags.update(shell_flags)
541 flags.update(shell_flags)
542
542
543 addflag = lambda *args: flags.update(boolean_flag(*args))
543 addflag = lambda *args: flags.update(boolean_flag(*args))
544
544
545 flags['pylab'] = (
545 flags['pylab'] = (
546 {'IPKernelApp' : {'pylab' : 'auto'}},
546 {'IPKernelApp' : {'pylab' : 'auto'}},
547 """Pre-load matplotlib and numpy for interactive use with
547 """Pre-load matplotlib and numpy for interactive use with
548 the default matplotlib backend."""
548 the default matplotlib backend."""
549 )
549 )
550
550
551 aliases = dict(kernel_aliases)
551 aliases = dict(kernel_aliases)
552 aliases.update(shell_aliases)
552 aliases.update(shell_aliases)
553
553
554 # it's possible we don't want short aliases for *all* of these:
554 # it's possible we don't want short aliases for *all* of these:
555 aliases.update(dict(
555 aliases.update(dict(
556 pylab='IPKernelApp.pylab',
556 pylab='IPKernelApp.pylab',
557 ))
557 ))
558
558
559 #-----------------------------------------------------------------------------
559 #-----------------------------------------------------------------------------
560 # The IPKernelApp class
560 # The IPKernelApp class
561 #-----------------------------------------------------------------------------
561 #-----------------------------------------------------------------------------
562
562
563 class IPKernelApp(KernelApp, InteractiveShellApp):
563 class IPKernelApp(KernelApp, InteractiveShellApp):
564 name = 'ipkernel'
564 name = 'ipkernel'
565
565
566 aliases = Dict(aliases)
566 aliases = Dict(aliases)
567 flags = Dict(flags)
567 flags = Dict(flags)
568 classes = [Kernel, ZMQInteractiveShell, ProfileDir, Session]
568 classes = [Kernel, ZMQInteractiveShell, ProfileDir, Session]
569 # configurables
569 # configurables
570 pylab = CaselessStrEnum(['tk', 'qt', 'wx', 'gtk', 'osx', 'inline', 'auto'],
570 pylab = CaselessStrEnum(['tk', 'qt', 'wx', 'gtk', 'osx', 'inline', 'auto'],
571 config=True,
571 config=True,
572 help="""Pre-load matplotlib and numpy for interactive use,
572 help="""Pre-load matplotlib and numpy for interactive use,
573 selecting a particular matplotlib backend and loop integration.
573 selecting a particular matplotlib backend and loop integration.
574 """
574 """
575 )
575 )
576
576
577 @catch_config_error
577 @catch_config_error
578 def initialize(self, argv=None):
578 def initialize(self, argv=None):
579 super(IPKernelApp, self).initialize(argv)
579 super(IPKernelApp, self).initialize(argv)
580 self.init_shell()
580 self.init_shell()
581 self.init_extensions()
581 self.init_extensions()
582 self.init_code()
582 self.init_code()
583
583
584 def init_kernel(self):
584 def init_kernel(self):
585
585
586 kernel = Kernel(config=self.config, session=self.session,
586 kernel = Kernel(config=self.config, session=self.session,
587 shell_socket=self.shell_socket,
587 shell_socket=self.shell_socket,
588 iopub_socket=self.iopub_socket,
588 iopub_socket=self.iopub_socket,
589 stdin_socket=self.stdin_socket,
589 stdin_socket=self.stdin_socket,
590 log=self.log,
590 log=self.log,
591 profile_dir=self.profile_dir,
591 profile_dir=self.profile_dir,
592 user_module=self.user_module,
592 user_module=self.user_module,
593 user_ns=self.user_ns,
593 user_ns=self.user_ns,
594 )
594 )
595 self.kernel = kernel
595 self.kernel = kernel
596 kernel.record_ports(self.ports)
596 kernel.record_ports(self.ports)
597 shell = kernel.shell
597 shell = kernel.shell
598 if self.pylab:
598 if self.pylab:
599 try:
599 try:
600 gui, backend = pylabtools.find_gui_and_backend(self.pylab)
600 gui, backend = pylabtools.find_gui_and_backend(self.pylab)
601 shell.enable_pylab(gui, import_all=self.pylab_import_all)
601 shell.enable_pylab(gui, import_all=self.pylab_import_all)
602 except Exception:
602 except Exception:
603 self.log.error("Pylab initialization failed", exc_info=True)
603 self.log.error("Pylab initialization failed", exc_info=True)
604 # print exception straight to stdout, because normally
604 # print exception straight to stdout, because normally
605 # _showtraceback associates the reply with an execution,
605 # _showtraceback associates the reply with an execution,
606 # which means frontends will never draw it, as this exception
606 # which means frontends will never draw it, as this exception
607 # is not associated with any execute request.
607 # is not associated with any execute request.
608
608
609 # replace pyerr-sending traceback with stdout
609 # replace pyerr-sending traceback with stdout
610 _showtraceback = shell._showtraceback
610 _showtraceback = shell._showtraceback
611 def print_tb(etype, evalue, stb):
611 def print_tb(etype, evalue, stb):
612 print ("Error initializing pylab, pylab mode will not "
612 print ("Error initializing pylab, pylab mode will not "
613 "be active", file=io.stderr)
613 "be active", file=io.stderr)
614 print (shell.InteractiveTB.stb2text(stb), file=io.stdout)
614 print (shell.InteractiveTB.stb2text(stb), file=io.stdout)
615 shell._showtraceback = print_tb
615 shell._showtraceback = print_tb
616
616
617 # send the traceback over stdout
617 # send the traceback over stdout
618 shell.showtraceback(tb_offset=0)
618 shell.showtraceback(tb_offset=0)
619
619
620 # restore proper _showtraceback method
620 # restore proper _showtraceback method
621 shell._showtraceback = _showtraceback
621 shell._showtraceback = _showtraceback
622
622
623
623
624 def init_shell(self):
624 def init_shell(self):
625 self.shell = self.kernel.shell
625 self.shell = self.kernel.shell
626 self.shell.configurables.append(self)
626 self.shell.configurables.append(self)
627
627
628
628
629 #-----------------------------------------------------------------------------
629 #-----------------------------------------------------------------------------
630 # Kernel main and launch functions
630 # Kernel main and launch functions
631 #-----------------------------------------------------------------------------
631 #-----------------------------------------------------------------------------
632
632
633 def launch_kernel(*args, **kwargs):
633 def launch_kernel(*args, **kwargs):
634 """Launches a localhost IPython kernel, binding to the specified ports.
634 """Launches a localhost IPython kernel, binding to the specified ports.
635
635
636 This function simply calls entry_point.base_launch_kernel with the right
636 This function simply calls entry_point.base_launch_kernel with the right
637 first command to start an ipkernel. See base_launch_kernel for arguments.
637 first command to start an ipkernel. See base_launch_kernel for arguments.
638
638
639 Returns
639 Returns
640 -------
640 -------
641 A tuple of form:
641 A tuple of form:
642 (kernel_process, shell_port, iopub_port, stdin_port, hb_port)
642 (kernel_process, shell_port, iopub_port, stdin_port, hb_port)
643 where kernel_process is a Popen object and the ports are integers.
643 where kernel_process is a Popen object and the ports are integers.
644 """
644 """
645 return base_launch_kernel('from IPython.zmq.ipkernel import main; main()',
645 return base_launch_kernel('from IPython.zmq.ipkernel import main; main()',
646 *args, **kwargs)
646 *args, **kwargs)
647
647
648 def caller_module_and_locals():
648 def embed_kernel(module, local_ns):
649 """Returns (module, locals) of the caller"""
650 caller = sys._getframe(1).f_back
651 global_ns = caller.f_globals
652 module = sys.modules[global_ns['__name__']]
653 return (module, caller.f_locals)
654
655 def embed_kernel(module=None, local_ns=None):
656 """Call this to embed an IPython kernel at the current point in your program. """
657 (caller_module, caller_locals) = caller_module_and_locals()
658 if module is None:
659 module = caller_module
660 if local_ns is None:
661 local_ns = caller_locals
662 app = IPKernelApp.instance(user_module=module, user_ns=local_ns)
649 app = IPKernelApp.instance(user_module=module, user_ns=local_ns)
663 app.initialize([])
650 app.initialize([])
664 app.start()
651 app.start()
665
652
666 def main():
653 def main():
667 """Run an IPKernel as an application"""
654 """Run an IPKernel as an application"""
668 app = IPKernelApp.instance()
655 app = IPKernelApp.instance()
669 app.initialize()
656 app.initialize()
670 app.start()
657 app.start()
671
658
672
659
673 if __name__ == '__main__':
660 if __name__ == '__main__':
674 main()
661 main()
General Comments 0
You need to be logged in to leave comments. Login now