##// END OF EJS Templates
Merge pull request #1620 from ivanov/pyin-execution-count...
Fernando Perez -
r6549:79d7b1ca merge
parent child Browse files
Show More
@@ -1,657 +1,657 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
74 74 # Private interface
75 75
76 76 # Time to sleep after flushing the stdout/err buffers in each execute
77 77 # cycle. While this introduces a hard limit on the minimal latency of the
78 78 # execute cycle, it helps prevent output synchronization problems for
79 79 # clients.
80 80 # Units are in seconds. The minimum zmq latency on local host is probably
81 81 # ~150 microseconds, set this to 500us for now. We may need to increase it
82 82 # a little if it's not enough after more interactive testing.
83 83 _execute_sleep = Float(0.0005, config=True)
84 84
85 85 # Frequency of the kernel's event loop.
86 86 # Units are in seconds, kernel subclasses for GUI toolkits may need to
87 87 # adapt to milliseconds.
88 88 _poll_interval = Float(0.05, config=True)
89 89
90 90 # If the shutdown was requested over the network, we leave here the
91 91 # necessary reply message so it can be sent by our registered atexit
92 92 # handler. This ensures that the reply is only sent to clients truly at
93 93 # the end of our shutdown process (which happens after the underlying
94 94 # IPython shell's own shutdown).
95 95 _shutdown_message = None
96 96
97 97 # This is a dict of port number that the kernel is listening on. It is set
98 98 # by record_ports and used by connect_request.
99 99 _recorded_ports = Dict()
100 100
101 101
102 102
103 103 def __init__(self, **kwargs):
104 104 super(Kernel, self).__init__(**kwargs)
105 105
106 106 # Before we even start up the shell, register *first* our exit handlers
107 107 # so they come before the shell's
108 108 atexit.register(self._at_shutdown)
109 109
110 110 # Initialize the InteractiveShell subclass
111 111 self.shell = ZMQInteractiveShell.instance(config=self.config,
112 112 profile_dir = self.profile_dir,
113 113 )
114 114 self.shell.displayhook.session = self.session
115 115 self.shell.displayhook.pub_socket = self.iopub_socket
116 116 self.shell.display_pub.session = self.session
117 117 self.shell.display_pub.pub_socket = self.iopub_socket
118 118
119 119 # TMP - hack while developing
120 120 self.shell._reply_content = None
121 121
122 122 # Build dict of handlers for message types
123 123 msg_types = [ 'execute_request', 'complete_request',
124 124 'object_info_request', 'history_request',
125 125 'connect_request', 'shutdown_request']
126 126 self.handlers = {}
127 127 for msg_type in msg_types:
128 128 self.handlers[msg_type] = getattr(self, msg_type)
129 129
130 130 def do_one_iteration(self):
131 131 """Do one iteration of the kernel's evaluation loop.
132 132 """
133 133 try:
134 134 ident,msg = self.session.recv(self.shell_socket, zmq.NOBLOCK)
135 135 except Exception:
136 136 self.log.warn("Invalid Message:", exc_info=True)
137 137 return
138 138 if msg is None:
139 139 return
140 140
141 141 msg_type = msg['header']['msg_type']
142 142
143 143 # This assert will raise in versions of zeromq 2.0.7 and lesser.
144 144 # We now require 2.0.8 or above, so we can uncomment for safety.
145 145 # print(ident,msg, file=sys.__stdout__)
146 146 assert ident is not None, "Missing message part."
147 147
148 148 # Print some info about this message and leave a '--->' marker, so it's
149 149 # easier to trace visually the message chain when debugging. Each
150 150 # handler prints its message at the end.
151 151 self.log.debug('\n*** MESSAGE TYPE:'+str(msg_type)+'***')
152 152 self.log.debug(' Content: '+str(msg['content'])+'\n --->\n ')
153 153
154 154 # Find and call actual handler for message
155 155 handler = self.handlers.get(msg_type, None)
156 156 if handler is None:
157 157 self.log.error("UNKNOWN MESSAGE TYPE:" +str(msg))
158 158 else:
159 159 handler(ident, msg)
160 160
161 161 # Check whether we should exit, in case the incoming message set the
162 162 # exit flag on
163 163 if self.shell.exit_now:
164 164 self.log.debug('\nExiting IPython kernel...')
165 165 # We do a normal, clean exit, which allows any actions registered
166 166 # via atexit (such as history saving) to take place.
167 167 sys.exit(0)
168 168
169 169
170 170 def start(self):
171 171 """ Start the kernel main loop.
172 172 """
173 173 # a KeyboardInterrupt (SIGINT) can occur on any python statement, so
174 174 # let's ignore (SIG_IGN) them until we're in a place to handle them properly
175 175 signal(SIGINT,SIG_IGN)
176 176 poller = zmq.Poller()
177 177 poller.register(self.shell_socket, zmq.POLLIN)
178 178 # loop while self.eventloop has not been overridden
179 179 while self.eventloop is None:
180 180 try:
181 181 # scale by extra factor of 10, because there is no
182 182 # reason for this to be anything less than ~ 0.1s
183 183 # since it is a real poller and will respond
184 184 # to events immediately
185 185
186 186 # double nested try/except, to properly catch KeyboardInterrupt
187 187 # due to pyzmq Issue #130
188 188 try:
189 189 poller.poll(10*1000*self._poll_interval)
190 190 # restore raising of KeyboardInterrupt
191 191 signal(SIGINT, default_int_handler)
192 192 self.do_one_iteration()
193 193 except:
194 194 raise
195 195 finally:
196 196 # prevent raising of KeyboardInterrupt
197 197 signal(SIGINT,SIG_IGN)
198 198 except KeyboardInterrupt:
199 199 # Ctrl-C shouldn't crash the kernel
200 200 io.raw_print("KeyboardInterrupt caught in kernel")
201 201 # stop ignoring sigint, now that we are out of our own loop,
202 202 # we don't want to prevent future code from handling it
203 203 signal(SIGINT, default_int_handler)
204 204 while self.eventloop is not None:
205 205 try:
206 206 self.eventloop(self)
207 207 except KeyboardInterrupt:
208 208 # Ctrl-C shouldn't crash the kernel
209 209 io.raw_print("KeyboardInterrupt caught in kernel")
210 210 continue
211 211 else:
212 212 # eventloop exited cleanly, this means we should stop (right?)
213 213 self.eventloop = None
214 214 break
215 215
216 216
217 217 def record_ports(self, ports):
218 218 """Record the ports that this kernel is using.
219 219
220 220 The creator of the Kernel instance must call this methods if they
221 221 want the :meth:`connect_request` method to return the port numbers.
222 222 """
223 223 self._recorded_ports = ports
224 224
225 225 #---------------------------------------------------------------------------
226 226 # Kernel request handlers
227 227 #---------------------------------------------------------------------------
228 228
229 def _publish_pyin(self, code, parent):
229 def _publish_pyin(self, code, parent, execution_count):
230 230 """Publish the code request on the pyin stream."""
231 231
232 self.session.send(self.iopub_socket, u'pyin', {u'code':code},
233 parent=parent)
232 self.session.send(self.iopub_socket, u'pyin', {u'code':code,
233 u'execution_count': execution_count}, parent=parent)
234 234
235 235 def execute_request(self, ident, parent):
236 236
237 237 self.session.send(self.iopub_socket,
238 238 u'status',
239 239 {u'execution_state':u'busy'},
240 240 parent=parent )
241 241
242 242 try:
243 243 content = parent[u'content']
244 244 code = content[u'code']
245 245 silent = content[u'silent']
246 246 except:
247 247 self.log.error("Got bad msg: ")
248 248 self.log.error(str(Message(parent)))
249 249 return
250 250
251 251 shell = self.shell # we'll need this a lot here
252 252
253 253 # Replace raw_input. Note that is not sufficient to replace
254 254 # raw_input in the user namespace.
255 255 if content.get('allow_stdin', False):
256 256 raw_input = lambda prompt='': self._raw_input(prompt, ident, parent)
257 257 else:
258 258 raw_input = lambda prompt='' : self._no_raw_input()
259 259
260 260 if py3compat.PY3:
261 261 __builtin__.input = raw_input
262 262 else:
263 263 __builtin__.raw_input = raw_input
264 264
265 265 # Set the parent message of the display hook and out streams.
266 266 shell.displayhook.set_parent(parent)
267 267 shell.display_pub.set_parent(parent)
268 268 sys.stdout.set_parent(parent)
269 269 sys.stderr.set_parent(parent)
270 270
271 271 # Re-broadcast our input for the benefit of listening clients, and
272 272 # start computing output
273 273 if not silent:
274 self._publish_pyin(code, parent)
274 self._publish_pyin(code, parent, shell.execution_count)
275 275
276 276 reply_content = {}
277 277 try:
278 278 if silent:
279 279 # run_code uses 'exec' mode, so no displayhook will fire, and it
280 280 # doesn't call logging or history manipulations. Print
281 281 # statements in that code will obviously still execute.
282 282 shell.run_code(code)
283 283 else:
284 284 # FIXME: the shell calls the exception handler itself.
285 285 shell.run_cell(code, store_history=True)
286 286 except:
287 287 status = u'error'
288 288 # FIXME: this code right now isn't being used yet by default,
289 289 # because the run_cell() call above directly fires off exception
290 290 # reporting. This code, therefore, is only active in the scenario
291 291 # where runlines itself has an unhandled exception. We need to
292 292 # uniformize this, for all exception construction to come from a
293 293 # single location in the codbase.
294 294 etype, evalue, tb = sys.exc_info()
295 295 tb_list = traceback.format_exception(etype, evalue, tb)
296 296 reply_content.update(shell._showtraceback(etype, evalue, tb_list))
297 297 else:
298 298 status = u'ok'
299 299
300 300 reply_content[u'status'] = status
301 301
302 302 # Return the execution counter so clients can display prompts
303 303 reply_content['execution_count'] = shell.execution_count -1
304 304
305 305 # FIXME - fish exception info out of shell, possibly left there by
306 306 # runlines. We'll need to clean up this logic later.
307 307 if shell._reply_content is not None:
308 308 reply_content.update(shell._reply_content)
309 309 # reset after use
310 310 shell._reply_content = None
311 311
312 312 # At this point, we can tell whether the main code execution succeeded
313 313 # or not. If it did, we proceed to evaluate user_variables/expressions
314 314 if reply_content['status'] == 'ok':
315 315 reply_content[u'user_variables'] = \
316 316 shell.user_variables(content[u'user_variables'])
317 317 reply_content[u'user_expressions'] = \
318 318 shell.user_expressions(content[u'user_expressions'])
319 319 else:
320 320 # If there was an error, don't even try to compute variables or
321 321 # expressions
322 322 reply_content[u'user_variables'] = {}
323 323 reply_content[u'user_expressions'] = {}
324 324
325 325 # Payloads should be retrieved regardless of outcome, so we can both
326 326 # recover partial output (that could have been generated early in a
327 327 # block, before an error) and clear the payload system always.
328 328 reply_content[u'payload'] = shell.payload_manager.read_payload()
329 329 # Be agressive about clearing the payload because we don't want
330 330 # it to sit in memory until the next execute_request comes in.
331 331 shell.payload_manager.clear_payload()
332 332
333 333 # Flush output before sending the reply.
334 334 sys.stdout.flush()
335 335 sys.stderr.flush()
336 336 # FIXME: on rare occasions, the flush doesn't seem to make it to the
337 337 # clients... This seems to mitigate the problem, but we definitely need
338 338 # to better understand what's going on.
339 339 if self._execute_sleep:
340 340 time.sleep(self._execute_sleep)
341 341
342 342 # Send the reply.
343 343 reply_content = json_clean(reply_content)
344 344 reply_msg = self.session.send(self.shell_socket, u'execute_reply',
345 345 reply_content, parent, ident=ident)
346 346 self.log.debug(str(reply_msg))
347 347
348 348 if reply_msg['content']['status'] == u'error':
349 349 self._abort_queue()
350 350
351 351 self.session.send(self.iopub_socket,
352 352 u'status',
353 353 {u'execution_state':u'idle'},
354 354 parent=parent )
355 355
356 356 def complete_request(self, ident, parent):
357 357 txt, matches = self._complete(parent)
358 358 matches = {'matches' : matches,
359 359 'matched_text' : txt,
360 360 'status' : 'ok'}
361 361 matches = json_clean(matches)
362 362 completion_msg = self.session.send(self.shell_socket, 'complete_reply',
363 363 matches, parent, ident)
364 364 self.log.debug(str(completion_msg))
365 365
366 366 def object_info_request(self, ident, parent):
367 367 object_info = self.shell.object_inspect(parent['content']['oname'])
368 368 # Before we send this object over, we scrub it for JSON usage
369 369 oinfo = json_clean(object_info)
370 370 msg = self.session.send(self.shell_socket, 'object_info_reply',
371 371 oinfo, parent, ident)
372 372 self.log.debug(msg)
373 373
374 374 def history_request(self, ident, parent):
375 375 # We need to pull these out, as passing **kwargs doesn't work with
376 376 # unicode keys before Python 2.6.5.
377 377 hist_access_type = parent['content']['hist_access_type']
378 378 raw = parent['content']['raw']
379 379 output = parent['content']['output']
380 380 if hist_access_type == 'tail':
381 381 n = parent['content']['n']
382 382 hist = self.shell.history_manager.get_tail(n, raw=raw, output=output,
383 383 include_latest=True)
384 384
385 385 elif hist_access_type == 'range':
386 386 session = parent['content']['session']
387 387 start = parent['content']['start']
388 388 stop = parent['content']['stop']
389 389 hist = self.shell.history_manager.get_range(session, start, stop,
390 390 raw=raw, output=output)
391 391
392 392 elif hist_access_type == 'search':
393 393 pattern = parent['content']['pattern']
394 394 hist = self.shell.history_manager.search(pattern, raw=raw,
395 395 output=output)
396 396
397 397 else:
398 398 hist = []
399 399 hist = list(hist)
400 400 content = {'history' : hist}
401 401 content = json_clean(content)
402 402 msg = self.session.send(self.shell_socket, 'history_reply',
403 403 content, parent, ident)
404 404 self.log.debug("Sending history reply with %i entries", len(hist))
405 405
406 406 def connect_request(self, ident, parent):
407 407 if self._recorded_ports is not None:
408 408 content = self._recorded_ports.copy()
409 409 else:
410 410 content = {}
411 411 msg = self.session.send(self.shell_socket, 'connect_reply',
412 412 content, parent, ident)
413 413 self.log.debug(msg)
414 414
415 415 def shutdown_request(self, ident, parent):
416 416 self.shell.exit_now = True
417 417 self._shutdown_message = self.session.msg(u'shutdown_reply',
418 418 parent['content'], parent)
419 419 sys.exit(0)
420 420
421 421 #---------------------------------------------------------------------------
422 422 # Protected interface
423 423 #---------------------------------------------------------------------------
424 424
425 425 def _abort_queue(self):
426 426 while True:
427 427 try:
428 428 ident,msg = self.session.recv(self.shell_socket, zmq.NOBLOCK)
429 429 except Exception:
430 430 self.log.warn("Invalid Message:", exc_info=True)
431 431 continue
432 432 if msg is None:
433 433 break
434 434 else:
435 435 assert ident is not None, \
436 436 "Unexpected missing message part."
437 437
438 438 self.log.debug("Aborting:\n"+str(Message(msg)))
439 439 msg_type = msg['header']['msg_type']
440 440 reply_type = msg_type.split('_')[0] + '_reply'
441 441 reply_msg = self.session.send(self.shell_socket, reply_type,
442 442 {'status' : 'aborted'}, msg, ident=ident)
443 443 self.log.debug(reply_msg)
444 444 # We need to wait a bit for requests to come in. This can probably
445 445 # be set shorter for true asynchronous clients.
446 446 time.sleep(0.1)
447 447
448 448 def _no_raw_input(self):
449 449 """Raise StdinNotImplentedError if active frontend doesn't support
450 450 stdin."""
451 451 raise StdinNotImplementedError("raw_input was called, but this "
452 452 "frontend does not support stdin.")
453 453
454 454 def _raw_input(self, prompt, ident, parent):
455 455 # Flush output before making the request.
456 456 sys.stderr.flush()
457 457 sys.stdout.flush()
458 458
459 459 # Send the input request.
460 460 content = json_clean(dict(prompt=prompt))
461 461 self.session.send(self.stdin_socket, u'input_request', content, parent,
462 462 ident=ident)
463 463
464 464 # Await a response.
465 465 while True:
466 466 try:
467 467 ident, reply = self.session.recv(self.stdin_socket, 0)
468 468 except Exception:
469 469 self.log.warn("Invalid Message:", exc_info=True)
470 470 else:
471 471 break
472 472 try:
473 473 value = reply['content']['value']
474 474 except:
475 475 self.log.error("Got bad raw_input reply: ")
476 476 self.log.error(str(Message(parent)))
477 477 value = ''
478 478 if value == '\x04':
479 479 # EOF
480 480 raise EOFError
481 481 return value
482 482
483 483 def _complete(self, msg):
484 484 c = msg['content']
485 485 try:
486 486 cpos = int(c['cursor_pos'])
487 487 except:
488 488 # If we don't get something that we can convert to an integer, at
489 489 # least attempt the completion guessing the cursor is at the end of
490 490 # the text, if there's any, and otherwise of the line
491 491 cpos = len(c['text'])
492 492 if cpos==0:
493 493 cpos = len(c['line'])
494 494 return self.shell.complete(c['text'], c['line'], cpos)
495 495
496 496 def _object_info(self, context):
497 497 symbol, leftover = self._symbol_from_context(context)
498 498 if symbol is not None and not leftover:
499 499 doc = getattr(symbol, '__doc__', '')
500 500 else:
501 501 doc = ''
502 502 object_info = dict(docstring = doc)
503 503 return object_info
504 504
505 505 def _symbol_from_context(self, context):
506 506 if not context:
507 507 return None, context
508 508
509 509 base_symbol_string = context[0]
510 510 symbol = self.shell.user_ns.get(base_symbol_string, None)
511 511 if symbol is None:
512 512 symbol = __builtin__.__dict__.get(base_symbol_string, None)
513 513 if symbol is None:
514 514 return None, context
515 515
516 516 context = context[1:]
517 517 for i, name in enumerate(context):
518 518 new_symbol = getattr(symbol, name, None)
519 519 if new_symbol is None:
520 520 return symbol, context[i:]
521 521 else:
522 522 symbol = new_symbol
523 523
524 524 return symbol, []
525 525
526 526 def _at_shutdown(self):
527 527 """Actions taken at shutdown by the kernel, called by python's atexit.
528 528 """
529 529 # io.rprint("Kernel at_shutdown") # dbg
530 530 if self._shutdown_message is not None:
531 531 self.session.send(self.shell_socket, self._shutdown_message)
532 532 self.session.send(self.iopub_socket, self._shutdown_message)
533 533 self.log.debug(str(self._shutdown_message))
534 534 # A very short sleep to give zmq time to flush its message buffers
535 535 # before Python truly shuts down.
536 536 time.sleep(0.01)
537 537
538 538 #-----------------------------------------------------------------------------
539 539 # Aliases and Flags for the IPKernelApp
540 540 #-----------------------------------------------------------------------------
541 541
542 542 flags = dict(kernel_flags)
543 543 flags.update(shell_flags)
544 544
545 545 addflag = lambda *args: flags.update(boolean_flag(*args))
546 546
547 547 flags['pylab'] = (
548 548 {'IPKernelApp' : {'pylab' : 'auto'}},
549 549 """Pre-load matplotlib and numpy for interactive use with
550 550 the default matplotlib backend."""
551 551 )
552 552
553 553 aliases = dict(kernel_aliases)
554 554 aliases.update(shell_aliases)
555 555
556 556 # it's possible we don't want short aliases for *all* of these:
557 557 aliases.update(dict(
558 558 pylab='IPKernelApp.pylab',
559 559 ))
560 560
561 561 #-----------------------------------------------------------------------------
562 562 # The IPKernelApp class
563 563 #-----------------------------------------------------------------------------
564 564
565 565 class IPKernelApp(KernelApp, InteractiveShellApp):
566 566 name = 'ipkernel'
567 567
568 568 aliases = Dict(aliases)
569 569 flags = Dict(flags)
570 570 classes = [Kernel, ZMQInteractiveShell, ProfileDir, Session]
571 571 # configurables
572 572 pylab = CaselessStrEnum(['tk', 'qt', 'wx', 'gtk', 'osx', 'inline', 'auto'],
573 573 config=True,
574 574 help="""Pre-load matplotlib and numpy for interactive use,
575 575 selecting a particular matplotlib backend and loop integration.
576 576 """
577 577 )
578 578
579 579 @catch_config_error
580 580 def initialize(self, argv=None):
581 581 super(IPKernelApp, self).initialize(argv)
582 582 self.init_shell()
583 583 self.init_extensions()
584 584 self.init_code()
585 585
586 586 def init_kernel(self):
587 587
588 588 kernel = Kernel(config=self.config, session=self.session,
589 589 shell_socket=self.shell_socket,
590 590 iopub_socket=self.iopub_socket,
591 591 stdin_socket=self.stdin_socket,
592 592 log=self.log,
593 593 profile_dir=self.profile_dir,
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 648
649 649 def main():
650 650 """Run an IPKernel as an application"""
651 651 app = IPKernelApp.instance()
652 652 app.initialize()
653 653 app.start()
654 654
655 655
656 656 if __name__ == '__main__':
657 657 main()
@@ -1,949 +1,954 b''
1 1 .. _messaging:
2 2
3 3 ======================
4 4 Messaging in IPython
5 5 ======================
6 6
7 7
8 8 Introduction
9 9 ============
10 10
11 11 This document explains the basic communications design and messaging
12 12 specification for how the various IPython objects interact over a network
13 13 transport. The current implementation uses the ZeroMQ_ library for messaging
14 14 within and between hosts.
15 15
16 16 .. Note::
17 17
18 18 This document should be considered the authoritative description of the
19 19 IPython messaging protocol, and all developers are strongly encouraged to
20 20 keep it updated as the implementation evolves, so that we have a single
21 21 common reference for all protocol details.
22 22
23 23 The basic design is explained in the following diagram:
24 24
25 25 .. image:: figs/frontend-kernel.png
26 26 :width: 450px
27 27 :alt: IPython kernel/frontend messaging architecture.
28 28 :align: center
29 29 :target: ../_images/frontend-kernel.png
30 30
31 31 A single kernel can be simultaneously connected to one or more frontends. The
32 32 kernel has three sockets that serve the following functions:
33 33
34 34 1. stdin: this ROUTER socket is connected to all frontends, and it allows
35 35 the kernel to request input from the active frontend when :func:`raw_input` is called.
36 36 The frontend that executed the code has a DEALER socket that acts as a 'virtual keyboard'
37 37 for the kernel while this communication is happening (illustrated in the
38 38 figure by the black outline around the central keyboard). In practice,
39 39 frontends may display such kernel requests using a special input widget or
40 40 otherwise indicating that the user is to type input for the kernel instead
41 41 of normal commands in the frontend.
42 42
43 43 2. Shell: this single ROUTER socket allows multiple incoming connections from
44 44 frontends, and this is the socket where requests for code execution, object
45 45 information, prompts, etc. are made to the kernel by any frontend. The
46 46 communication on this socket is a sequence of request/reply actions from
47 47 each frontend and the kernel.
48 48
49 49 3. IOPub: this socket is the 'broadcast channel' where the kernel publishes all
50 50 side effects (stdout, stderr, etc.) as well as the requests coming from any
51 51 client over the shell socket and its own requests on the stdin socket. There
52 52 are a number of actions in Python which generate side effects: :func:`print`
53 53 writes to ``sys.stdout``, errors generate tracebacks, etc. Additionally, in
54 54 a multi-client scenario, we want all frontends to be able to know what each
55 55 other has sent to the kernel (this can be useful in collaborative scenarios,
56 56 for example). This socket allows both side effects and the information
57 57 about communications taking place with one client over the shell channel
58 58 to be made available to all clients in a uniform manner.
59 59
60 60 All messages are tagged with enough information (details below) for clients
61 61 to know which messages come from their own interaction with the kernel and
62 62 which ones are from other clients, so they can display each type
63 63 appropriately.
64 64
65 65 The actual format of the messages allowed on each of these channels is
66 66 specified below. Messages are dicts of dicts with string keys and values that
67 67 are reasonably representable in JSON. Our current implementation uses JSON
68 68 explicitly as its message format, but this shouldn't be considered a permanent
69 69 feature. As we've discovered that JSON has non-trivial performance issues due
70 70 to excessive copying, we may in the future move to a pure pickle-based raw
71 71 message format. However, it should be possible to easily convert from the raw
72 72 objects to JSON, since we may have non-python clients (e.g. a web frontend).
73 73 As long as it's easy to make a JSON version of the objects that is a faithful
74 74 representation of all the data, we can communicate with such clients.
75 75
76 76 .. Note::
77 77
78 78 Not all of these have yet been fully fleshed out, but the key ones are, see
79 79 kernel and frontend files for actual implementation details.
80 80
81 81
82 82 Python functional API
83 83 =====================
84 84
85 85 As messages are dicts, they map naturally to a ``func(**kw)`` call form. We
86 86 should develop, at a few key points, functional forms of all the requests that
87 87 take arguments in this manner and automatically construct the necessary dict
88 88 for sending.
89 89
90 90
91 91 General Message Format
92 92 ======================
93 93
94 94 All messages send or received by any IPython process should have the following
95 95 generic structure::
96 96
97 97 {
98 98 # The message header contains a pair of unique identifiers for the
99 99 # originating session and the actual message id, in addition to the
100 100 # username for the process that generated the message. This is useful in
101 101 # collaborative settings where multiple users may be interacting with the
102 102 # same kernel simultaneously, so that frontends can label the various
103 103 # messages in a meaningful way.
104 104 'header' : {
105 105 'msg_id' : uuid,
106 106 'username' : str,
107 107 'session' : uuid
108 108 # All recognized message type strings are listed below.
109 109 'msg_type' : str,
110 110 },
111 111 # The msg's unique identifier and type are stored in the header, but
112 112 # are also accessible at the top-level for convenience.
113 113 'msg_id' : uuid,
114 114 'msg_type' : str,
115 115
116 116 # In a chain of messages, the header from the parent is copied so that
117 117 # clients can track where messages come from.
118 118 'parent_header' : dict,
119 119
120 120 # The actual content of the message must be a dict, whose structure
121 121 # depends on the message type.x
122 122 'content' : dict,
123 123 }
124 124
125 125 For each message type, the actual content will differ and all existing message
126 126 types are specified in what follows of this document.
127 127
128 128
129 129 Messages on the shell ROUTER/DEALER sockets
130 130 ===========================================
131 131
132 132 .. _execute:
133 133
134 134 Execute
135 135 -------
136 136
137 137 This message type is used by frontends to ask the kernel to execute code on
138 138 behalf of the user, in a namespace reserved to the user's variables (and thus
139 139 separate from the kernel's own internal code and variables).
140 140
141 141 Message type: ``execute_request``::
142 142
143 143 content = {
144 144 # Source code to be executed by the kernel, one or more lines.
145 145 'code' : str,
146 146
147 147 # A boolean flag which, if True, signals the kernel to execute
148 148 # this code as quietly as possible. This means that the kernel
149 149 # will compile the code with 'exec' instead of 'single' (so
150 150 # sys.displayhook will not fire), and will *not*:
151 151 # - broadcast exceptions on the PUB socket
152 152 # - do any logging
153 153 # - populate any history
154 154 #
155 155 # The default is False.
156 156 'silent' : bool,
157 157
158 158 # A list of variable names from the user's namespace to be retrieved. What
159 159 # returns is a JSON string of the variable's repr(), not a python object.
160 160 'user_variables' : list,
161 161
162 162 # Similarly, a dict mapping names to expressions to be evaluated in the
163 163 # user's dict.
164 164 'user_expressions' : dict,
165 165
166 166 # Some frontends (e.g. the Notebook) do not support stdin requests. If
167 167 # raw_input is called from code executed from such a frontend, a
168 168 # StdinNotImplementedError will be raised.
169 169 'allow_stdin' : True,
170 170
171 171 }
172 172
173 173 The ``code`` field contains a single string (possibly multiline). The kernel
174 174 is responsible for splitting this into one or more independent execution blocks
175 175 and deciding whether to compile these in 'single' or 'exec' mode (see below for
176 176 detailed execution semantics).
177 177
178 178 The ``user_`` fields deserve a detailed explanation. In the past, IPython had
179 179 the notion of a prompt string that allowed arbitrary code to be evaluated, and
180 180 this was put to good use by many in creating prompts that displayed system
181 181 status, path information, and even more esoteric uses like remote instrument
182 182 status aqcuired over the network. But now that IPython has a clean separation
183 183 between the kernel and the clients, the kernel has no prompt knowledge; prompts
184 184 are a frontend-side feature, and it should be even possible for different
185 185 frontends to display different prompts while interacting with the same kernel.
186 186
187 187 The kernel now provides the ability to retrieve data from the user's namespace
188 188 after the execution of the main ``code``, thanks to two fields in the
189 189 ``execute_request`` message:
190 190
191 191 - ``user_variables``: If only variables from the user's namespace are needed, a
192 192 list of variable names can be passed and a dict with these names as keys and
193 193 their :func:`repr()` as values will be returned.
194 194
195 195 - ``user_expressions``: For more complex expressions that require function
196 196 evaluations, a dict can be provided with string keys and arbitrary python
197 197 expressions as values. The return message will contain also a dict with the
198 198 same keys and the :func:`repr()` of the evaluated expressions as value.
199 199
200 200 With this information, frontends can display any status information they wish
201 201 in the form that best suits each frontend (a status line, a popup, inline for a
202 202 terminal, etc).
203 203
204 204 .. Note::
205 205
206 206 In order to obtain the current execution counter for the purposes of
207 207 displaying input prompts, frontends simply make an execution request with an
208 208 empty code string and ``silent=True``.
209 209
210 210 Execution semantics
211 211 ~~~~~~~~~~~~~~~~~~~
212 212
213 213 When the silent flag is false, the execution of use code consists of the
214 214 following phases (in silent mode, only the ``code`` field is executed):
215 215
216 216 1. Run the ``pre_runcode_hook``.
217 217
218 218 2. Execute the ``code`` field, see below for details.
219 219
220 220 3. If #2 succeeds, compute ``user_variables`` and ``user_expressions`` are
221 221 computed. This ensures that any error in the latter don't harm the main
222 222 code execution.
223 223
224 224 4. Call any method registered with :meth:`register_post_execute`.
225 225
226 226 .. warning::
227 227
228 228 The API for running code before/after the main code block is likely to
229 229 change soon. Both the ``pre_runcode_hook`` and the
230 230 :meth:`register_post_execute` are susceptible to modification, as we find a
231 231 consistent model for both.
232 232
233 233 To understand how the ``code`` field is executed, one must know that Python
234 234 code can be compiled in one of three modes (controlled by the ``mode`` argument
235 235 to the :func:`compile` builtin):
236 236
237 237 *single*
238 238 Valid for a single interactive statement (though the source can contain
239 239 multiple lines, such as a for loop). When compiled in this mode, the
240 240 generated bytecode contains special instructions that trigger the calling of
241 241 :func:`sys.displayhook` for any expression in the block that returns a value.
242 242 This means that a single statement can actually produce multiple calls to
243 243 :func:`sys.displayhook`, if for example it contains a loop where each
244 244 iteration computes an unassigned expression would generate 10 calls::
245 245
246 246 for i in range(10):
247 247 i**2
248 248
249 249 *exec*
250 250 An arbitrary amount of source code, this is how modules are compiled.
251 251 :func:`sys.displayhook` is *never* implicitly called.
252 252
253 253 *eval*
254 254 A single expression that returns a value. :func:`sys.displayhook` is *never*
255 255 implicitly called.
256 256
257 257
258 258 The ``code`` field is split into individual blocks each of which is valid for
259 259 execution in 'single' mode, and then:
260 260
261 261 - If there is only a single block: it is executed in 'single' mode.
262 262
263 263 - If there is more than one block:
264 264
265 265 * if the last one is a single line long, run all but the last in 'exec' mode
266 266 and the very last one in 'single' mode. This makes it easy to type simple
267 267 expressions at the end to see computed values.
268 268
269 269 * if the last one is no more than two lines long, run all but the last in
270 270 'exec' mode and the very last one in 'single' mode. This makes it easy to
271 271 type simple expressions at the end to see computed values. - otherwise
272 272 (last one is also multiline), run all in 'exec' mode
273 273
274 274 * otherwise (last one is also multiline), run all in 'exec' mode as a single
275 275 unit.
276 276
277 277 Any error in retrieving the ``user_variables`` or evaluating the
278 278 ``user_expressions`` will result in a simple error message in the return fields
279 279 of the form::
280 280
281 281 [ERROR] ExceptionType: Exception message
282 282
283 283 The user can simply send the same variable name or expression for evaluation to
284 284 see a regular traceback.
285 285
286 286 Errors in any registered post_execute functions are also reported similarly,
287 287 and the failing function is removed from the post_execution set so that it does
288 288 not continue triggering failures.
289 289
290 290 Upon completion of the execution request, the kernel *always* sends a reply,
291 291 with a status code indicating what happened and additional data depending on
292 292 the outcome. See :ref:`below <execution_results>` for the possible return
293 293 codes and associated data.
294 294
295 295
296 296 Execution counter (old prompt number)
297 297 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
298 298
299 299 The kernel has a single, monotonically increasing counter of all execution
300 300 requests that are made with ``silent=False``. This counter is used to populate
301 301 the ``In[n]``, ``Out[n]`` and ``_n`` variables, so clients will likely want to
302 302 display it in some form to the user, which will typically (but not necessarily)
303 303 be done in the prompts. The value of this counter will be returned as the
304 304 ``execution_count`` field of all ``execute_reply`` messages.
305 305
306 306 .. _execution_results:
307 307
308 308 Execution results
309 309 ~~~~~~~~~~~~~~~~~
310 310
311 311 Message type: ``execute_reply``::
312 312
313 313 content = {
314 314 # One of: 'ok' OR 'error' OR 'abort'
315 315 'status' : str,
316 316
317 317 # The global kernel counter that increases by one with each non-silent
318 318 # executed request. This will typically be used by clients to display
319 319 # prompt numbers to the user. If the request was a silent one, this will
320 320 # be the current value of the counter in the kernel.
321 321 'execution_count' : int,
322 322 }
323 323
324 324 When status is 'ok', the following extra fields are present::
325 325
326 326 {
327 327 # The execution payload is a dict with string keys that may have been
328 328 # produced by the code being executed. It is retrieved by the kernel at
329 329 # the end of the execution and sent back to the front end, which can take
330 330 # action on it as needed. See main text for further details.
331 331 'payload' : dict,
332 332
333 333 # Results for the user_variables and user_expressions.
334 334 'user_variables' : dict,
335 335 'user_expressions' : dict,
336 336
337 337 # The kernel will often transform the input provided to it. If the
338 338 # '---->' transform had been applied, this is filled, otherwise it's the
339 339 # empty string. So transformations like magics don't appear here, only
340 340 # autocall ones.
341 341 'transformed_code' : str,
342 342 }
343 343
344 344 .. admonition:: Execution payloads
345 345
346 346 The notion of an 'execution payload' is different from a return value of a
347 347 given set of code, which normally is just displayed on the pyout stream
348 348 through the PUB socket. The idea of a payload is to allow special types of
349 349 code, typically magics, to populate a data container in the IPython kernel
350 350 that will be shipped back to the caller via this channel. The kernel will
351 351 have an API for this, probably something along the lines of::
352 352
353 353 ip.exec_payload_add(key, value)
354 354
355 355 though this API is still in the design stages. The data returned in this
356 356 payload will allow frontends to present special views of what just happened.
357 357
358 358
359 359 When status is 'error', the following extra fields are present::
360 360
361 361 {
362 362 'exc_name' : str, # Exception name, as a string
363 363 'exc_value' : str, # Exception value, as a string
364 364
365 365 # The traceback will contain a list of frames, represented each as a
366 366 # string. For now we'll stick to the existing design of ultraTB, which
367 367 # controls exception level of detail statefully. But eventually we'll
368 368 # want to grow into a model where more information is collected and
369 369 # packed into the traceback object, with clients deciding how little or
370 370 # how much of it to unpack. But for now, let's start with a simple list
371 371 # of strings, since that requires only minimal changes to ultratb as
372 372 # written.
373 373 'traceback' : list,
374 374 }
375 375
376 376
377 377 When status is 'abort', there are for now no additional data fields. This
378 378 happens when the kernel was interrupted by a signal.
379 379
380 380 Kernel attribute access
381 381 -----------------------
382 382
383 383 .. warning::
384 384
385 385 This part of the messaging spec is not actually implemented in the kernel
386 386 yet.
387 387
388 388 While this protocol does not specify full RPC access to arbitrary methods of
389 389 the kernel object, the kernel does allow read (and in some cases write) access
390 390 to certain attributes.
391 391
392 392 The policy for which attributes can be read is: any attribute of the kernel, or
393 393 its sub-objects, that belongs to a :class:`Configurable` object and has been
394 394 declared at the class-level with Traits validation, is in principle accessible
395 395 as long as its name does not begin with a leading underscore. The attribute
396 396 itself will have metadata indicating whether it allows remote read and/or write
397 397 access. The message spec follows for attribute read and write requests.
398 398
399 399 Message type: ``getattr_request``::
400 400
401 401 content = {
402 402 # The (possibly dotted) name of the attribute
403 403 'name' : str,
404 404 }
405 405
406 406 When a ``getattr_request`` fails, there are two possible error types:
407 407
408 408 - AttributeError: this type of error was raised when trying to access the
409 409 given name by the kernel itself. This means that the attribute likely
410 410 doesn't exist.
411 411
412 412 - AccessError: the attribute exists but its value is not readable remotely.
413 413
414 414
415 415 Message type: ``getattr_reply``::
416 416
417 417 content = {
418 418 # One of ['ok', 'AttributeError', 'AccessError'].
419 419 'status' : str,
420 420 # If status is 'ok', a JSON object.
421 421 'value' : object,
422 422 }
423 423
424 424 Message type: ``setattr_request``::
425 425
426 426 content = {
427 427 # The (possibly dotted) name of the attribute
428 428 'name' : str,
429 429
430 430 # A JSON-encoded object, that will be validated by the Traits
431 431 # information in the kernel
432 432 'value' : object,
433 433 }
434 434
435 435 When a ``setattr_request`` fails, there are also two possible error types with
436 436 similar meanings as those of the ``getattr_request`` case, but for writing.
437 437
438 438 Message type: ``setattr_reply``::
439 439
440 440 content = {
441 441 # One of ['ok', 'AttributeError', 'AccessError'].
442 442 'status' : str,
443 443 }
444 444
445 445
446 446
447 447 Object information
448 448 ------------------
449 449
450 450 One of IPython's most used capabilities is the introspection of Python objects
451 451 in the user's namespace, typically invoked via the ``?`` and ``??`` characters
452 452 (which in reality are shorthands for the ``%pinfo`` magic). This is used often
453 453 enough that it warrants an explicit message type, especially because frontends
454 454 may want to get object information in response to user keystrokes (like Tab or
455 455 F1) besides from the user explicitly typing code like ``x??``.
456 456
457 457 Message type: ``object_info_request``::
458 458
459 459 content = {
460 460 # The (possibly dotted) name of the object to be searched in all
461 461 # relevant namespaces
462 462 'name' : str,
463 463
464 464 # The level of detail desired. The default (0) is equivalent to typing
465 465 # 'x?' at the prompt, 1 is equivalent to 'x??'.
466 466 'detail_level' : int,
467 467 }
468 468
469 469 The returned information will be a dictionary with keys very similar to the
470 470 field names that IPython prints at the terminal.
471 471
472 472 Message type: ``object_info_reply``::
473 473
474 474 content = {
475 475 # The name the object was requested under
476 476 'name' : str,
477 477
478 478 # Boolean flag indicating whether the named object was found or not. If
479 479 # it's false, all other fields will be empty.
480 480 'found' : bool,
481 481
482 482 # Flags for magics and system aliases
483 483 'ismagic' : bool,
484 484 'isalias' : bool,
485 485
486 486 # The name of the namespace where the object was found ('builtin',
487 487 # 'magics', 'alias', 'interactive', etc.)
488 488 'namespace' : str,
489 489
490 490 # The type name will be type.__name__ for normal Python objects, but it
491 491 # can also be a string like 'Magic function' or 'System alias'
492 492 'type_name' : str,
493 493
494 494 # The string form of the object, possibly truncated for length if
495 495 # detail_level is 0
496 496 'string_form' : str,
497 497
498 498 # For objects with a __class__ attribute this will be set
499 499 'base_class' : str,
500 500
501 501 # For objects with a __len__ attribute this will be set
502 502 'length' : int,
503 503
504 504 # If the object is a function, class or method whose file we can find,
505 505 # we give its full path
506 506 'file' : str,
507 507
508 508 # For pure Python callable objects, we can reconstruct the object
509 509 # definition line which provides its call signature. For convenience this
510 510 # is returned as a single 'definition' field, but below the raw parts that
511 511 # compose it are also returned as the argspec field.
512 512 'definition' : str,
513 513
514 514 # The individual parts that together form the definition string. Clients
515 515 # with rich display capabilities may use this to provide a richer and more
516 516 # precise representation of the definition line (e.g. by highlighting
517 517 # arguments based on the user's cursor position). For non-callable
518 518 # objects, this field is empty.
519 519 'argspec' : { # The names of all the arguments
520 520 args : list,
521 521 # The name of the varargs (*args), if any
522 522 varargs : str,
523 523 # The name of the varkw (**kw), if any
524 524 varkw : str,
525 525 # The values (as strings) of all default arguments. Note
526 526 # that these must be matched *in reverse* with the 'args'
527 527 # list above, since the first positional args have no default
528 528 # value at all.
529 529 defaults : list,
530 530 },
531 531
532 532 # For instances, provide the constructor signature (the definition of
533 533 # the __init__ method):
534 534 'init_definition' : str,
535 535
536 536 # Docstrings: for any object (function, method, module, package) with a
537 537 # docstring, we show it. But in addition, we may provide additional
538 538 # docstrings. For example, for instances we will show the constructor
539 539 # and class docstrings as well, if available.
540 540 'docstring' : str,
541 541
542 542 # For instances, provide the constructor and class docstrings
543 543 'init_docstring' : str,
544 544 'class_docstring' : str,
545 545
546 546 # If it's a callable object whose call method has a separate docstring and
547 547 # definition line:
548 548 'call_def' : str,
549 549 'call_docstring' : str,
550 550
551 551 # If detail_level was 1, we also try to find the source code that
552 552 # defines the object, if possible. The string 'None' will indicate
553 553 # that no source was found.
554 554 'source' : str,
555 555 }
556 556 '
557 557
558 558 Complete
559 559 --------
560 560
561 561 Message type: ``complete_request``::
562 562
563 563 content = {
564 564 # The text to be completed, such as 'a.is'
565 565 'text' : str,
566 566
567 567 # The full line, such as 'print a.is'. This allows completers to
568 568 # make decisions that may require information about more than just the
569 569 # current word.
570 570 'line' : str,
571 571
572 572 # The entire block of text where the line is. This may be useful in the
573 573 # case of multiline completions where more context may be needed. Note: if
574 574 # in practice this field proves unnecessary, remove it to lighten the
575 575 # messages.
576 576
577 577 'block' : str,
578 578
579 579 # The position of the cursor where the user hit 'TAB' on the line.
580 580 'cursor_pos' : int,
581 581 }
582 582
583 583 Message type: ``complete_reply``::
584 584
585 585 content = {
586 586 # The list of all matches to the completion request, such as
587 587 # ['a.isalnum', 'a.isalpha'] for the above example.
588 588 'matches' : list
589 589 }
590 590
591 591
592 592 History
593 593 -------
594 594
595 595 For clients to explicitly request history from a kernel. The kernel has all
596 596 the actual execution history stored in a single location, so clients can
597 597 request it from the kernel when needed.
598 598
599 599 Message type: ``history_request``::
600 600
601 601 content = {
602 602
603 603 # If True, also return output history in the resulting dict.
604 604 'output' : bool,
605 605
606 606 # If True, return the raw input history, else the transformed input.
607 607 'raw' : bool,
608 608
609 609 # So far, this can be 'range', 'tail' or 'search'.
610 610 'hist_access_type' : str,
611 611
612 612 # If hist_access_type is 'range', get a range of input cells. session can
613 613 # be a positive session number, or a negative number to count back from
614 614 # the current session.
615 615 'session' : int,
616 616 # start and stop are line numbers within that session.
617 617 'start' : int,
618 618 'stop' : int,
619 619
620 620 # If hist_access_type is 'tail', get the last n cells.
621 621 'n' : int,
622 622
623 623 # If hist_access_type is 'search', get cells matching the specified glob
624 624 # pattern (with * and ? as wildcards).
625 625 'pattern' : str,
626 626
627 627 }
628 628
629 629 Message type: ``history_reply``::
630 630
631 631 content = {
632 632 # A list of 3 tuples, either:
633 633 # (session, line_number, input) or
634 634 # (session, line_number, (input, output)),
635 635 # depending on whether output was False or True, respectively.
636 636 'history' : list,
637 637 }
638 638
639 639
640 640 Connect
641 641 -------
642 642
643 643 When a client connects to the request/reply socket of the kernel, it can issue
644 644 a connect request to get basic information about the kernel, such as the ports
645 645 the other ZeroMQ sockets are listening on. This allows clients to only have
646 646 to know about a single port (the shell channel) to connect to a kernel.
647 647
648 648 Message type: ``connect_request``::
649 649
650 650 content = {
651 651 }
652 652
653 653 Message type: ``connect_reply``::
654 654
655 655 content = {
656 656 'shell_port' : int # The port the shell ROUTER socket is listening on.
657 657 'iopub_port' : int # The port the PUB socket is listening on.
658 658 'stdin_port' : int # The port the stdin ROUTER socket is listening on.
659 659 'hb_port' : int # The port the heartbeat socket is listening on.
660 660 }
661 661
662 662
663 663
664 664 Kernel shutdown
665 665 ---------------
666 666
667 667 The clients can request the kernel to shut itself down; this is used in
668 668 multiple cases:
669 669
670 670 - when the user chooses to close the client application via a menu or window
671 671 control.
672 672 - when the user types 'exit' or 'quit' (or their uppercase magic equivalents).
673 673 - when the user chooses a GUI method (like the 'Ctrl-C' shortcut in the
674 674 IPythonQt client) to force a kernel restart to get a clean kernel without
675 675 losing client-side state like history or inlined figures.
676 676
677 677 The client sends a shutdown request to the kernel, and once it receives the
678 678 reply message (which is otherwise empty), it can assume that the kernel has
679 679 completed shutdown safely.
680 680
681 681 Upon their own shutdown, client applications will typically execute a last
682 682 minute sanity check and forcefully terminate any kernel that is still alive, to
683 683 avoid leaving stray processes in the user's machine.
684 684
685 685 For both shutdown request and reply, there is no actual content that needs to
686 686 be sent, so the content dict is empty.
687 687
688 688 Message type: ``shutdown_request``::
689 689
690 690 content = {
691 691 'restart' : bool # whether the shutdown is final, or precedes a restart
692 692 }
693 693
694 694 Message type: ``shutdown_reply``::
695 695
696 696 content = {
697 697 'restart' : bool # whether the shutdown is final, or precedes a restart
698 698 }
699 699
700 700 .. Note::
701 701
702 702 When the clients detect a dead kernel thanks to inactivity on the heartbeat
703 703 socket, they simply send a forceful process termination signal, since a dead
704 704 process is unlikely to respond in any useful way to messages.
705 705
706 706
707 707 Messages on the PUB/SUB socket
708 708 ==============================
709 709
710 710 Streams (stdout, stderr, etc)
711 711 ------------------------------
712 712
713 713 Message type: ``stream``::
714 714
715 715 content = {
716 716 # The name of the stream is one of 'stdin', 'stdout', 'stderr'
717 717 'name' : str,
718 718
719 719 # The data is an arbitrary string to be written to that stream
720 720 'data' : str,
721 721 }
722 722
723 723 When a kernel receives a raw_input call, it should also broadcast it on the pub
724 724 socket with the names 'stdin' and 'stdin_reply'. This will allow other clients
725 725 to monitor/display kernel interactions and possibly replay them to their user
726 726 or otherwise expose them.
727 727
728 728 Display Data
729 729 ------------
730 730
731 731 This type of message is used to bring back data that should be diplayed (text,
732 732 html, svg, etc.) in the frontends. This data is published to all frontends.
733 733 Each message can have multiple representations of the data; it is up to the
734 734 frontend to decide which to use and how. A single message should contain all
735 735 possible representations of the same information. Each representation should
736 736 be a JSON'able data structure, and should be a valid MIME type.
737 737
738 738 Some questions remain about this design:
739 739
740 740 * Do we use this message type for pyout/displayhook? Probably not, because
741 741 the displayhook also has to handle the Out prompt display. On the other hand
742 742 we could put that information into the metadata secion.
743 743
744 744 Message type: ``display_data``::
745 745
746 746 content = {
747 747
748 748 # Who create the data
749 749 'source' : str,
750 750
751 751 # The data dict contains key/value pairs, where the kids are MIME
752 752 # types and the values are the raw data of the representation in that
753 753 # format. The data dict must minimally contain the ``text/plain``
754 754 # MIME type which is used as a backup representation.
755 755 'data' : dict,
756 756
757 757 # Any metadata that describes the data
758 758 'metadata' : dict
759 759 }
760 760
761 761 Python inputs
762 762 -------------
763 763
764 764 These messages are the re-broadcast of the ``execute_request``.
765 765
766 766 Message type: ``pyin``::
767 767
768 768 content = {
769 'code' : str # Source code to be executed, one or more lines
769 'code' : str, # Source code to be executed, one or more lines
770
771 # The counter for this execution is also provided so that clients can
772 # display it, since IPython automatically creates variables called _iN
773 # (for input prompt In[N]).
774 'execution_count' : int
770 775 }
771 776
772 777 Python outputs
773 778 --------------
774 779
775 780 When Python produces output from code that has been compiled in with the
776 781 'single' flag to :func:`compile`, any expression that produces a value (such as
777 782 ``1+1``) is passed to ``sys.displayhook``, which is a callable that can do with
778 783 this value whatever it wants. The default behavior of ``sys.displayhook`` in
779 784 the Python interactive prompt is to print to ``sys.stdout`` the :func:`repr` of
780 785 the value as long as it is not ``None`` (which isn't printed at all). In our
781 786 case, the kernel instantiates as ``sys.displayhook`` an object which has
782 787 similar behavior, but which instead of printing to stdout, broadcasts these
783 788 values as ``pyout`` messages for clients to display appropriately.
784 789
785 790 IPython's displayhook can handle multiple simultaneous formats depending on its
786 791 configuration. The default pretty-printed repr text is always given with the
787 792 ``data`` entry in this message. Any other formats are provided in the
788 793 ``extra_formats`` list. Frontends are free to display any or all of these
789 794 according to its capabilities. ``extra_formats`` list contains 3-tuples of an ID
790 795 string, a type string, and the data. The ID is unique to the formatter
791 796 implementation that created the data. Frontends will typically ignore the ID
792 797 unless if it has requested a particular formatter. The type string tells the
793 798 frontend how to interpret the data. It is often, but not always a MIME type.
794 799 Frontends should ignore types that it does not understand. The data itself is
795 800 any JSON object and depends on the format. It is often, but not always a string.
796 801
797 802 Message type: ``pyout``::
798 803
799 804 content = {
800 805
801 806 # The counter for this execution is also provided so that clients can
802 807 # display it, since IPython automatically creates variables called _N
803 808 # (for prompt N).
804 809 'execution_count' : int,
805 810
806 811 # The data dict contains key/value pairs, where the kids are MIME
807 812 # types and the values are the raw data of the representation in that
808 813 # format. The data dict must minimally contain the ``text/plain``
809 814 # MIME type which is used as a backup representation.
810 815 'data' : dict,
811 816
812 817 }
813 818
814 819 Python errors
815 820 -------------
816 821
817 822 When an error occurs during code execution
818 823
819 824 Message type: ``pyerr``::
820 825
821 826 content = {
822 827 # Similar content to the execute_reply messages for the 'error' case,
823 828 # except the 'status' field is omitted.
824 829 }
825 830
826 831 Kernel status
827 832 -------------
828 833
829 834 This message type is used by frontends to monitor the status of the kernel.
830 835
831 836 Message type: ``status``::
832 837
833 838 content = {
834 839 # When the kernel starts to execute code, it will enter the 'busy'
835 840 # state and when it finishes, it will enter the 'idle' state.
836 841 execution_state : ('busy', 'idle')
837 842 }
838 843
839 844 Kernel crashes
840 845 --------------
841 846
842 847 When the kernel has an unexpected exception, caught by the last-resort
843 848 sys.excepthook, we should broadcast the crash handler's output before exiting.
844 849 This will allow clients to notice that a kernel died, inform the user and
845 850 propose further actions.
846 851
847 852 Message type: ``crash``::
848 853
849 854 content = {
850 855 # Similarly to the 'error' case for execute_reply messages, this will
851 856 # contain exc_name, exc_type and traceback fields.
852 857
853 858 # An additional field with supplementary information such as where to
854 859 # send the crash message
855 860 'info' : str,
856 861 }
857 862
858 863
859 864 Future ideas
860 865 ------------
861 866
862 867 Other potential message types, currently unimplemented, listed below as ideas.
863 868
864 869 Message type: ``file``::
865 870
866 871 content = {
867 872 'path' : 'cool.jpg',
868 873 'mimetype' : str,
869 874 'data' : str,
870 875 }
871 876
872 877
873 878 Messages on the stdin ROUTER/DEALER sockets
874 879 ===========================================
875 880
876 881 This is a socket where the request/reply pattern goes in the opposite direction:
877 882 from the kernel to a *single* frontend, and its purpose is to allow
878 883 ``raw_input`` and similar operations that read from ``sys.stdin`` on the kernel
879 884 to be fulfilled by the client. The request should be made to the frontend that
880 885 made the execution request that prompted ``raw_input`` to be called. For now we
881 886 will keep these messages as simple as possible, since they only mean to convey
882 887 the ``raw_input(prompt)`` call.
883 888
884 889 Message type: ``input_request``::
885 890
886 891 content = { 'prompt' : str }
887 892
888 893 Message type: ``input_reply``::
889 894
890 895 content = { 'value' : str }
891 896
892 897 .. Note::
893 898
894 899 We do not explicitly try to forward the raw ``sys.stdin`` object, because in
895 900 practice the kernel should behave like an interactive program. When a
896 901 program is opened on the console, the keyboard effectively takes over the
897 902 ``stdin`` file descriptor, and it can't be used for raw reading anymore.
898 903 Since the IPython kernel effectively behaves like a console program (albeit
899 904 one whose "keyboard" is actually living in a separate process and
900 905 transported over the zmq connection), raw ``stdin`` isn't expected to be
901 906 available.
902 907
903 908
904 909 Heartbeat for kernels
905 910 =====================
906 911
907 912 Initially we had considered using messages like those above over ZMQ for a
908 913 kernel 'heartbeat' (a way to detect quickly and reliably whether a kernel is
909 914 alive at all, even if it may be busy executing user code). But this has the
910 915 problem that if the kernel is locked inside extension code, it wouldn't execute
911 916 the python heartbeat code. But it turns out that we can implement a basic
912 917 heartbeat with pure ZMQ, without using any Python messaging at all.
913 918
914 919 The monitor sends out a single zmq message (right now, it is a str of the
915 920 monitor's lifetime in seconds), and gets the same message right back, prefixed
916 921 with the zmq identity of the DEALER socket in the heartbeat process. This can be
917 922 a uuid, or even a full message, but there doesn't seem to be a need for packing
918 923 up a message when the sender and receiver are the exact same Python object.
919 924
920 925 The model is this::
921 926
922 927 monitor.send(str(self.lifetime)) # '1.2345678910'
923 928
924 929 and the monitor receives some number of messages of the form::
925 930
926 931 ['uuid-abcd-dead-beef', '1.2345678910']
927 932
928 933 where the first part is the zmq.IDENTITY of the heart's DEALER on the engine, and
929 934 the rest is the message sent by the monitor. No Python code ever has any
930 935 access to the message between the monitor's send, and the monitor's recv.
931 936
932 937
933 938 ToDo
934 939 ====
935 940
936 941 Missing things include:
937 942
938 943 * Important: finish thinking through the payload concept and API.
939 944
940 945 * Important: ensure that we have a good solution for magics like %edit. It's
941 946 likely that with the payload concept we can build a full solution, but not
942 947 100% clear yet.
943 948
944 949 * Finishing the details of the heartbeat protocol.
945 950
946 951 * Signal handling: specify what kind of information kernel should broadcast (or
947 952 not) when it receives signals.
948 953
949 954 .. include:: ../links.rst
General Comments 0
You need to be logged in to leave comments. Login now