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