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