##// END OF EJS Templates
Merge pull request #7005 from minrk/payloads-3.0...
Thomas Kluyver -
r19052:e38dcec4 merge
parent child Browse files
Show More
@@ -1,49 +1,48 b''
1 1 # encoding: utf-8
2 2 """A payload based version of page."""
3 3
4 4 # Copyright (c) IPython Development Team.
5 5 # Distributed under the terms of the Modified BSD License.
6 6
7 7 from IPython.core.getipython import get_ipython
8 8
9 9 #-----------------------------------------------------------------------------
10 10 # Classes and functions
11 11 #-----------------------------------------------------------------------------
12 12
13 13 def page(strng, start=0, screen_lines=0, pager_cmd=None):
14 14 """Print a string, piping through a pager.
15 15
16 16 This version ignores the screen_lines and pager_cmd arguments and uses
17 17 IPython's payload system instead.
18 18
19 19 Parameters
20 20 ----------
21 21 strng : str or mime-dict
22 22 Text to page, or a mime-type keyed dict of already formatted data.
23 23
24 24 start : int
25 25 Starting line at which to place the display.
26 26 """
27 27
28 28 # Some routines may auto-compute start offsets incorrectly and pass a
29 29 # negative value. Offset to 0 for robustness.
30 30 start = max(0, start)
31 31 shell = get_ipython()
32 32
33 33 if isinstance(strng, dict):
34 34 data = strng
35 35 else:
36 36 data = {'text/plain' : strng}
37 37 payload = dict(
38 38 source='page',
39 39 data=data,
40 40 start=start,
41 screen_lines=screen_lines,
42 41 )
43 42 shell.payload_manager.write_payload(payload)
44 43
45 44
46 45 def install_payload_page():
47 46 """Install this version of page as IPython.core.page.page."""
48 47 from IPython.core import page as corepage
49 48 corepage.page = page
@@ -1,567 +1,487 b''
1 1 """A ZMQ-based subclass of InteractiveShell.
2 2
3 3 This code is meant to ease the refactoring of the base InteractiveShell into
4 4 something with a cleaner architecture for 2-process use, without actually
5 5 breaking InteractiveShell itself. So we're doing something a bit ugly, where
6 6 we subclass and override what we want to fix. Once this is working well, we
7 7 can go back to the base class and refactor the code for a cleaner inheritance
8 8 implementation that doesn't rely on so much monkeypatching.
9 9
10 10 But this lets us maintain a fully working IPython as we develop the new
11 11 machinery. This should thus be thought of as scaffolding.
12 12 """
13 13
14 14 # Copyright (c) IPython Development Team.
15 15 # Distributed under the terms of the Modified BSD License.
16 16
17 17 from __future__ import print_function
18 18
19 19 import os
20 20 import sys
21 21 import time
22 22
23 23 from zmq.eventloop import ioloop
24 24
25 25 from IPython.core.interactiveshell import (
26 26 InteractiveShell, InteractiveShellABC
27 27 )
28 28 from IPython.core import page
29 29 from IPython.core.autocall import ZMQExitAutocall
30 30 from IPython.core.displaypub import DisplayPublisher
31 31 from IPython.core.error import UsageError
32 32 from IPython.core.magics import MacroToEdit, CodeMagics
33 33 from IPython.core.magic import magics_class, line_magic, Magics
34 34 from IPython.core.payloadpage import install_payload_page
35 35 from IPython.core.usage import default_gui_banner
36 36 from IPython.display import display, Javascript
37 37 from IPython.kernel.inprocess.socket import SocketABC
38 38 from IPython.kernel import (
39 39 get_connection_file, get_connection_info, connect_qtconsole
40 40 )
41 41 from IPython.testing.skipdoctest import skip_doctest
42 42 from IPython.utils import openpy
43 43 from IPython.utils.jsonutil import json_clean, encode_images
44 44 from IPython.utils.process import arg_split
45 45 from IPython.utils import py3compat
46 46 from IPython.utils.py3compat import unicode_type
47 47 from IPython.utils.traitlets import Instance, Type, Dict, CBool, CBytes, Any
48 48 from IPython.utils.warn import error
49 49 from IPython.kernel.zmq.displayhook import ZMQShellDisplayHook
50 50 from IPython.kernel.zmq.datapub import ZMQDataPublisher
51 51 from IPython.kernel.zmq.session import extract_header
52 52 from .session import Session
53 53
54 54 #-----------------------------------------------------------------------------
55 55 # Functions and classes
56 56 #-----------------------------------------------------------------------------
57 57
58 58 class ZMQDisplayPublisher(DisplayPublisher):
59 59 """A display publisher that publishes data using a ZeroMQ PUB socket."""
60 60
61 61 session = Instance(Session)
62 62 pub_socket = Instance(SocketABC)
63 63 parent_header = Dict({})
64 64 topic = CBytes(b'display_data')
65 65
66 66 def set_parent(self, parent):
67 67 """Set the parent for outbound messages."""
68 68 self.parent_header = extract_header(parent)
69 69
70 70 def _flush_streams(self):
71 71 """flush IO Streams prior to display"""
72 72 sys.stdout.flush()
73 73 sys.stderr.flush()
74 74
75 75 def publish(self, data, metadata=None, source=None):
76 76 self._flush_streams()
77 77 if metadata is None:
78 78 metadata = {}
79 79 self._validate_data(data, metadata)
80 80 content = {}
81 81 content['data'] = encode_images(data)
82 82 content['metadata'] = metadata
83 83 self.session.send(
84 84 self.pub_socket, u'display_data', json_clean(content),
85 85 parent=self.parent_header, ident=self.topic,
86 86 )
87 87
88 88 def clear_output(self, wait=False):
89 89 content = dict(wait=wait)
90 90 self._flush_streams()
91 91 self.session.send(
92 92 self.pub_socket, u'clear_output', content,
93 93 parent=self.parent_header, ident=self.topic,
94 94 )
95 95
96 96 @magics_class
97 97 class KernelMagics(Magics):
98 98 #------------------------------------------------------------------------
99 99 # Magic overrides
100 100 #------------------------------------------------------------------------
101 101 # Once the base class stops inheriting from magic, this code needs to be
102 102 # moved into a separate machinery as well. For now, at least isolate here
103 103 # the magics which this class needs to implement differently from the base
104 104 # class, or that are unique to it.
105
106 @line_magic
107 def doctest_mode(self, parameter_s=''):
108 """Toggle doctest mode on and off.
109
110 This mode is intended to make IPython behave as much as possible like a
111 plain Python shell, from the perspective of how its prompts, exceptions
112 and output look. This makes it easy to copy and paste parts of a
113 session into doctests. It does so by:
114
115 - Changing the prompts to the classic ``>>>`` ones.
116 - Changing the exception reporting mode to 'Plain'.
117 - Disabling pretty-printing of output.
118
119 Note that IPython also supports the pasting of code snippets that have
120 leading '>>>' and '...' prompts in them. This means that you can paste
121 doctests from files or docstrings (even if they have leading
122 whitespace), and the code will execute correctly. You can then use
123 '%history -t' to see the translated history; this will give you the
124 input after removal of all the leading prompts and whitespace, which
125 can be pasted back into an editor.
126
127 With these features, you can switch into this mode easily whenever you
128 need to do testing and changes to doctests, without having to leave
129 your existing IPython session.
130 """
131
132 from IPython.utils.ipstruct import Struct
133
134 # Shorthands
135 shell = self.shell
136 disp_formatter = self.shell.display_formatter
137 ptformatter = disp_formatter.formatters['text/plain']
138 # dstore is a data store kept in the instance metadata bag to track any
139 # changes we make, so we can undo them later.
140 dstore = shell.meta.setdefault('doctest_mode', Struct())
141 save_dstore = dstore.setdefault
142
143 # save a few values we'll need to recover later
144 mode = save_dstore('mode', False)
145 save_dstore('rc_pprint', ptformatter.pprint)
146 save_dstore('rc_active_types',disp_formatter.active_types)
147 save_dstore('xmode', shell.InteractiveTB.mode)
148
149 if mode == False:
150 # turn on
151 ptformatter.pprint = False
152 disp_formatter.active_types = ['text/plain']
153 shell.magic('xmode Plain')
154 else:
155 # turn off
156 ptformatter.pprint = dstore.rc_pprint
157 disp_formatter.active_types = dstore.rc_active_types
158 shell.magic("xmode " + dstore.xmode)
159
160 # Store new mode and inform on console
161 dstore.mode = bool(1-int(mode))
162 mode_label = ['OFF','ON'][dstore.mode]
163 print('Doctest mode is:', mode_label)
164
165 # Send the payload back so that clients can modify their prompt display
166 payload = dict(
167 source='doctest_mode',
168 mode=dstore.mode)
169 shell.payload_manager.write_payload(payload)
170
171 105
172 106 _find_edit_target = CodeMagics._find_edit_target
173 107
174 108 @skip_doctest
175 109 @line_magic
176 110 def edit(self, parameter_s='', last_call=['','']):
177 111 """Bring up an editor and execute the resulting code.
178 112
179 113 Usage:
180 114 %edit [options] [args]
181 115
182 116 %edit runs an external text editor. You will need to set the command for
183 117 this editor via the ``TerminalInteractiveShell.editor`` option in your
184 118 configuration file before it will work.
185 119
186 120 This command allows you to conveniently edit multi-line code right in
187 121 your IPython session.
188 122
189 123 If called without arguments, %edit opens up an empty editor with a
190 124 temporary file and will execute the contents of this file when you
191 125 close it (don't forget to save it!).
192 126
193 127 Options:
194 128
195 129 -n <number>
196 130 Open the editor at a specified line number. By default, the IPython
197 131 editor hook uses the unix syntax 'editor +N filename', but you can
198 132 configure this by providing your own modified hook if your favorite
199 133 editor supports line-number specifications with a different syntax.
200 134
201 135 -p
202 136 Call the editor with the same data as the previous time it was used,
203 137 regardless of how long ago (in your current session) it was.
204 138
205 139 -r
206 140 Use 'raw' input. This option only applies to input taken from the
207 141 user's history. By default, the 'processed' history is used, so that
208 142 magics are loaded in their transformed version to valid Python. If
209 143 this option is given, the raw input as typed as the command line is
210 144 used instead. When you exit the editor, it will be executed by
211 145 IPython's own processor.
212 146
213 147 Arguments:
214 148
215 149 If arguments are given, the following possibilites exist:
216 150
217 151 - The arguments are numbers or pairs of colon-separated numbers (like
218 152 1 4:8 9). These are interpreted as lines of previous input to be
219 153 loaded into the editor. The syntax is the same of the %macro command.
220 154
221 155 - If the argument doesn't start with a number, it is evaluated as a
222 156 variable and its contents loaded into the editor. You can thus edit
223 157 any string which contains python code (including the result of
224 158 previous edits).
225 159
226 160 - If the argument is the name of an object (other than a string),
227 161 IPython will try to locate the file where it was defined and open the
228 162 editor at the point where it is defined. You can use ``%edit function``
229 163 to load an editor exactly at the point where 'function' is defined,
230 164 edit it and have the file be executed automatically.
231 165
232 166 If the object is a macro (see %macro for details), this opens up your
233 167 specified editor with a temporary file containing the macro's data.
234 168 Upon exit, the macro is reloaded with the contents of the file.
235 169
236 170 Note: opening at an exact line is only supported under Unix, and some
237 171 editors (like kedit and gedit up to Gnome 2.8) do not understand the
238 172 '+NUMBER' parameter necessary for this feature. Good editors like
239 173 (X)Emacs, vi, jed, pico and joe all do.
240 174
241 175 - If the argument is not found as a variable, IPython will look for a
242 176 file with that name (adding .py if necessary) and load it into the
243 177 editor. It will execute its contents with execfile() when you exit,
244 178 loading any code in the file into your interactive namespace.
245 179
246 180 Unlike in the terminal, this is designed to use a GUI editor, and we do
247 181 not know when it has closed. So the file you edit will not be
248 182 automatically executed or printed.
249 183
250 184 Note that %edit is also available through the alias %ed.
251 185 """
252 186
253 187 opts,args = self.parse_options(parameter_s,'prn:')
254 188
255 189 try:
256 190 filename, lineno, _ = CodeMagics._find_edit_target(self.shell, args, opts, last_call)
257 191 except MacroToEdit as e:
258 192 # TODO: Implement macro editing over 2 processes.
259 193 print("Macro editing not yet implemented in 2-process model.")
260 194 return
261 195
262 196 # Make sure we send to the client an absolute path, in case the working
263 197 # directory of client and kernel don't match
264 198 filename = os.path.abspath(filename)
265 199
266 200 payload = {
267 201 'source' : 'edit_magic',
268 202 'filename' : filename,
269 203 'line_number' : lineno
270 204 }
271 205 self.shell.payload_manager.write_payload(payload)
272 206
273 207 # A few magics that are adapted to the specifics of using pexpect and a
274 208 # remote terminal
275 209
276 210 @line_magic
277 211 def clear(self, arg_s):
278 212 """Clear the terminal."""
279 213 if os.name == 'posix':
280 214 self.shell.system("clear")
281 215 else:
282 216 self.shell.system("cls")
283 217
284 218 if os.name == 'nt':
285 219 # This is the usual name in windows
286 220 cls = line_magic('cls')(clear)
287 221
288 222 # Terminal pagers won't work over pexpect, but we do have our own pager
289 223
290 224 @line_magic
291 225 def less(self, arg_s):
292 226 """Show a file through the pager.
293 227
294 228 Files ending in .py are syntax-highlighted."""
295 229 if not arg_s:
296 230 raise UsageError('Missing filename.')
297 231
298 232 cont = open(arg_s).read()
299 233 if arg_s.endswith('.py'):
300 234 cont = self.shell.pycolorize(openpy.read_py_file(arg_s, skip_encoding_cookie=False))
301 235 else:
302 236 cont = open(arg_s).read()
303 237 page.page(cont)
304 238
305 239 more = line_magic('more')(less)
306 240
307 241 # Man calls a pager, so we also need to redefine it
308 242 if os.name == 'posix':
309 243 @line_magic
310 244 def man(self, arg_s):
311 245 """Find the man page for the given command and display in pager."""
312 246 page.page(self.shell.getoutput('man %s | col -b' % arg_s,
313 247 split=False))
314 248
315 249 @line_magic
316 250 def connect_info(self, arg_s):
317 251 """Print information for connecting other clients to this kernel
318 252
319 253 It will print the contents of this session's connection file, as well as
320 254 shortcuts for local clients.
321 255
322 256 In the simplest case, when called from the most recently launched kernel,
323 257 secondary clients can be connected, simply with:
324 258
325 259 $> ipython <app> --existing
326 260
327 261 """
328 262
329 263 from IPython.core.application import BaseIPythonApplication as BaseIPApp
330 264
331 265 if BaseIPApp.initialized():
332 266 app = BaseIPApp.instance()
333 267 security_dir = app.profile_dir.security_dir
334 268 profile = app.profile
335 269 else:
336 270 profile = 'default'
337 271 security_dir = ''
338 272
339 273 try:
340 274 connection_file = get_connection_file()
341 275 info = get_connection_info(unpack=False)
342 276 except Exception as e:
343 277 error("Could not get connection info: %r" % e)
344 278 return
345 279
346 280 # add profile flag for non-default profile
347 281 profile_flag = "--profile %s" % profile if profile != 'default' else ""
348 282
349 283 # if it's in the security dir, truncate to basename
350 284 if security_dir == os.path.dirname(connection_file):
351 285 connection_file = os.path.basename(connection_file)
352 286
353 287
354 288 print (info + '\n')
355 289 print ("Paste the above JSON into a file, and connect with:\n"
356 290 " $> ipython <app> --existing <file>\n"
357 291 "or, if you are local, you can connect with just:\n"
358 292 " $> ipython <app> --existing {0} {1}\n"
359 293 "or even just:\n"
360 294 " $> ipython <app> --existing {1}\n"
361 295 "if this is the most recent IPython session you have started.".format(
362 296 connection_file, profile_flag
363 297 )
364 298 )
365 299
366 300 @line_magic
367 301 def qtconsole(self, arg_s):
368 302 """Open a qtconsole connected to this kernel.
369 303
370 304 Useful for connecting a qtconsole to running notebooks, for better
371 305 debugging.
372 306 """
373 307
374 308 # %qtconsole should imply bind_kernel for engines:
375 309 try:
376 310 from IPython.parallel import bind_kernel
377 311 except ImportError:
378 312 # technically possible, because parallel has higher pyzmq min-version
379 313 pass
380 314 else:
381 315 bind_kernel()
382 316
383 317 try:
384 318 p = connect_qtconsole(argv=arg_split(arg_s, os.name=='posix'))
385 319 except Exception as e:
386 320 error("Could not start qtconsole: %r" % e)
387 321 return
388 322
389 323 @line_magic
390 324 def autosave(self, arg_s):
391 325 """Set the autosave interval in the notebook (in seconds).
392 326
393 327 The default value is 120, or two minutes.
394 328 ``%autosave 0`` will disable autosave.
395 329
396 330 This magic only has an effect when called from the notebook interface.
397 331 It has no effect when called in a startup file.
398 332 """
399 333
400 334 try:
401 335 interval = int(arg_s)
402 336 except ValueError:
403 337 raise UsageError("%%autosave requires an integer, got %r" % arg_s)
404 338
405 339 # javascript wants milliseconds
406 340 milliseconds = 1000 * interval
407 341 display(Javascript("IPython.notebook.set_autosave_interval(%i)" % milliseconds),
408 342 include=['application/javascript']
409 343 )
410 344 if interval:
411 345 print("Autosaving every %i seconds" % interval)
412 346 else:
413 347 print("Autosave disabled")
414 348
415 349
416 350 class ZMQInteractiveShell(InteractiveShell):
417 351 """A subclass of InteractiveShell for ZMQ."""
418 352
419 353 displayhook_class = Type(ZMQShellDisplayHook)
420 354 display_pub_class = Type(ZMQDisplayPublisher)
421 355 data_pub_class = Type(ZMQDataPublisher)
422 356 kernel = Any()
423 357 parent_header = Any()
424 358
425 359 def _banner1_default(self):
426 360 return default_gui_banner
427 361
428 362 # Override the traitlet in the parent class, because there's no point using
429 363 # readline for the kernel. Can be removed when the readline code is moved
430 364 # to the terminal frontend.
431 365 colors_force = CBool(True)
432 366 readline_use = CBool(False)
433 367 # autoindent has no meaning in a zmqshell, and attempting to enable it
434 368 # will print a warning in the absence of readline.
435 369 autoindent = CBool(False)
436 370
437 371 exiter = Instance(ZMQExitAutocall)
438 372 def _exiter_default(self):
439 373 return ZMQExitAutocall(self)
440 374
441 375 def _exit_now_changed(self, name, old, new):
442 376 """stop eventloop when exit_now fires"""
443 377 if new:
444 378 loop = ioloop.IOLoop.instance()
445 379 loop.add_timeout(time.time()+0.1, loop.stop)
446 380
447 381 keepkernel_on_exit = None
448 382
449 383 # Over ZeroMQ, GUI control isn't done with PyOS_InputHook as there is no
450 384 # interactive input being read; we provide event loop support in ipkernel
451 385 @staticmethod
452 386 def enable_gui(gui):
453 387 from .eventloops import enable_gui as real_enable_gui
454 388 try:
455 389 real_enable_gui(gui)
456 390 except ValueError as e:
457 391 raise UsageError("%s" % e)
458 392
459 393 def init_environment(self):
460 394 """Configure the user's environment.
461 395
462 396 """
463 397 env = os.environ
464 398 # These two ensure 'ls' produces nice coloring on BSD-derived systems
465 399 env['TERM'] = 'xterm-color'
466 400 env['CLICOLOR'] = '1'
467 401 # Since normal pagers don't work at all (over pexpect we don't have
468 402 # single-key control of the subprocess), try to disable paging in
469 403 # subprocesses as much as possible.
470 404 env['PAGER'] = 'cat'
471 405 env['GIT_PAGER'] = 'cat'
472 406
473 407 # And install the payload version of page.
474 408 install_payload_page()
475 409
476 def auto_rewrite_input(self, cmd):
477 """Called to show the auto-rewritten input for autocall and friends.
478
479 FIXME: this payload is currently not correctly processed by the
480 frontend.
481 """
482 new = self.prompt_manager.render('rewrite') + cmd
483 payload = dict(
484 source='auto_rewrite_input',
485 transformed_input=new,
486 )
487 self.payload_manager.write_payload(payload)
488
489 410 def ask_exit(self):
490 411 """Engage the exit actions."""
491 412 self.exit_now = (not self.keepkernel_on_exit)
492 413 payload = dict(
493 414 source='ask_exit',
494 exit=True,
495 415 keepkernel=self.keepkernel_on_exit,
496 416 )
497 417 self.payload_manager.write_payload(payload)
498 418
499 419 def _showtraceback(self, etype, evalue, stb):
500 420 # try to preserve ordering of tracebacks and print statements
501 421 sys.stdout.flush()
502 422 sys.stderr.flush()
503 423
504 424 exc_content = {
505 425 u'traceback' : stb,
506 426 u'ename' : unicode_type(etype.__name__),
507 427 u'evalue' : py3compat.safe_unicode(evalue),
508 428 }
509 429
510 430 dh = self.displayhook
511 431 # Send exception info over pub socket for other clients than the caller
512 432 # to pick up
513 433 topic = None
514 434 if dh.topic:
515 435 topic = dh.topic.replace(b'execute_result', b'error')
516 436
517 437 exc_msg = dh.session.send(dh.pub_socket, u'error', json_clean(exc_content), dh.parent_header, ident=topic)
518 438
519 439 # FIXME - Hack: store exception info in shell object. Right now, the
520 440 # caller is reading this info after the fact, we need to fix this logic
521 441 # to remove this hack. Even uglier, we need to store the error status
522 442 # here, because in the main loop, the logic that sets it is being
523 443 # skipped because runlines swallows the exceptions.
524 444 exc_content[u'status'] = u'error'
525 445 self._reply_content = exc_content
526 446 # /FIXME
527 447
528 448 return exc_content
529 449
530 450 def set_next_input(self, text):
531 451 """Send the specified text to the frontend to be presented at the next
532 452 input cell."""
533 453 payload = dict(
534 454 source='set_next_input',
535 455 text=text
536 456 )
537 457 self.payload_manager.write_payload(payload)
538 458
539 459 def set_parent(self, parent):
540 460 """Set the parent header for associating output with its triggering input"""
541 461 self.parent_header = parent
542 462 self.displayhook.set_parent(parent)
543 463 self.display_pub.set_parent(parent)
544 464 self.data_pub.set_parent(parent)
545 465 try:
546 466 sys.stdout.set_parent(parent)
547 467 except AttributeError:
548 468 pass
549 469 try:
550 470 sys.stderr.set_parent(parent)
551 471 except AttributeError:
552 472 pass
553 473
554 474 def get_parent(self):
555 475 return self.parent_header
556 476
557 477 #-------------------------------------------------------------------------
558 478 # Things related to magics
559 479 #-------------------------------------------------------------------------
560 480
561 481 def init_magics(self):
562 482 super(ZMQInteractiveShell, self).init_magics()
563 483 self.register_magics(KernelMagics)
564 484 self.magics_manager.register_alias('ed', 'edit')
565 485
566 486
567 487 InteractiveShellABC.register(ZMQInteractiveShell)
@@ -1,599 +1,599 b''
1 1 """A FrontendWidget that emulates the interface of the console IPython.
2 2
3 3 This supports the additional functionality provided by the IPython kernel.
4 4 """
5 5
6 6 # Copyright (c) IPython Development Team.
7 7 # Distributed under the terms of the Modified BSD License.
8 8
9 9 from collections import namedtuple
10 10 import os.path
11 11 import re
12 12 from subprocess import Popen
13 13 import sys
14 14 import time
15 15 from textwrap import dedent
16 16
17 17 from IPython.external.qt import QtCore, QtGui
18 18
19 19 from IPython.core.inputsplitter import IPythonInputSplitter
20 20 from IPython.core.release import version
21 21 from IPython.core.inputtransformer import ipy_prompt
22 22 from IPython.utils.traitlets import Bool, Unicode
23 23 from .frontend_widget import FrontendWidget
24 24 from . import styles
25 25
26 26 #-----------------------------------------------------------------------------
27 27 # Constants
28 28 #-----------------------------------------------------------------------------
29 29
30 30 # Default strings to build and display input and output prompts (and separators
31 31 # in between)
32 32 default_in_prompt = 'In [<span class="in-prompt-number">%i</span>]: '
33 33 default_out_prompt = 'Out[<span class="out-prompt-number">%i</span>]: '
34 34 default_input_sep = '\n'
35 35 default_output_sep = ''
36 36 default_output_sep2 = ''
37 37
38 38 # Base path for most payload sources.
39 39 zmq_shell_source = 'IPython.kernel.zmq.zmqshell.ZMQInteractiveShell'
40 40
41 41 if sys.platform.startswith('win'):
42 42 default_editor = 'notepad'
43 43 else:
44 44 default_editor = ''
45 45
46 46 #-----------------------------------------------------------------------------
47 47 # IPythonWidget class
48 48 #-----------------------------------------------------------------------------
49 49
50 50 class IPythonWidget(FrontendWidget):
51 51 """ A FrontendWidget for an IPython kernel.
52 52 """
53 53
54 54 # If set, the 'custom_edit_requested(str, int)' signal will be emitted when
55 55 # an editor is needed for a file. This overrides 'editor' and 'editor_line'
56 56 # settings.
57 57 custom_edit = Bool(False)
58 58 custom_edit_requested = QtCore.Signal(object, object)
59 59
60 60 editor = Unicode(default_editor, config=True,
61 61 help="""
62 62 A command for invoking a system text editor. If the string contains a
63 63 {filename} format specifier, it will be used. Otherwise, the filename
64 64 will be appended to the end the command.
65 65 """)
66 66
67 67 editor_line = Unicode(config=True,
68 68 help="""
69 69 The editor command to use when a specific line number is requested. The
70 70 string should contain two format specifiers: {line} and {filename}. If
71 71 this parameter is not specified, the line number option to the %edit
72 72 magic will be ignored.
73 73 """)
74 74
75 75 style_sheet = Unicode(config=True,
76 76 help="""
77 77 A CSS stylesheet. The stylesheet can contain classes for:
78 78 1. Qt: QPlainTextEdit, QFrame, QWidget, etc
79 79 2. Pygments: .c, .k, .o, etc. (see PygmentsHighlighter)
80 80 3. IPython: .error, .in-prompt, .out-prompt, etc
81 81 """)
82 82
83 83 syntax_style = Unicode(config=True,
84 84 help="""
85 85 If not empty, use this Pygments style for syntax highlighting.
86 86 Otherwise, the style sheet is queried for Pygments style
87 87 information.
88 88 """)
89 89
90 90 # Prompts.
91 91 in_prompt = Unicode(default_in_prompt, config=True)
92 92 out_prompt = Unicode(default_out_prompt, config=True)
93 93 input_sep = Unicode(default_input_sep, config=True)
94 94 output_sep = Unicode(default_output_sep, config=True)
95 95 output_sep2 = Unicode(default_output_sep2, config=True)
96 96
97 97 # FrontendWidget protected class variables.
98 98 _input_splitter_class = IPythonInputSplitter
99 99 _prompt_transformer = IPythonInputSplitter(physical_line_transforms=[ipy_prompt()],
100 100 logical_line_transforms=[],
101 101 python_line_transforms=[],
102 102 )
103 103
104 104 # IPythonWidget protected class variables.
105 105 _PromptBlock = namedtuple('_PromptBlock', ['block', 'length', 'number'])
106 _payload_source_edit = 'edit_magic'
106 _payload_source_edit = 'edit'
107 107 _payload_source_exit = 'ask_exit'
108 108 _payload_source_next_input = 'set_next_input'
109 109 _payload_source_page = 'page'
110 110 _retrying_history_request = False
111 111 _starting = False
112 112
113 113 #---------------------------------------------------------------------------
114 114 # 'object' interface
115 115 #---------------------------------------------------------------------------
116 116
117 117 def __init__(self, *args, **kw):
118 118 super(IPythonWidget, self).__init__(*args, **kw)
119 119
120 120 # IPythonWidget protected variables.
121 121 self._payload_handlers = {
122 122 self._payload_source_edit : self._handle_payload_edit,
123 123 self._payload_source_exit : self._handle_payload_exit,
124 124 self._payload_source_page : self._handle_payload_page,
125 125 self._payload_source_next_input : self._handle_payload_next_input }
126 126 self._previous_prompt_obj = None
127 127 self._keep_kernel_on_exit = None
128 128
129 129 # Initialize widget styling.
130 130 if self.style_sheet:
131 131 self._style_sheet_changed()
132 132 self._syntax_style_changed()
133 133 else:
134 134 self.set_default_style()
135 135
136 136 self._guiref_loaded = False
137 137
138 138 #---------------------------------------------------------------------------
139 139 # 'BaseFrontendMixin' abstract interface
140 140 #---------------------------------------------------------------------------
141 141 def _handle_complete_reply(self, rep):
142 142 """ Reimplemented to support IPython's improved completion machinery.
143 143 """
144 144 self.log.debug("complete: %s", rep.get('content', ''))
145 145 cursor = self._get_cursor()
146 146 info = self._request_info.get('complete')
147 147 if info and info.id == rep['parent_header']['msg_id'] and \
148 148 info.pos == cursor.position():
149 149 content = rep['content']
150 150 matches = content['matches']
151 151 start = content['cursor_start']
152 152 end = content['cursor_end']
153 153
154 154 start = max(start, 0)
155 155 end = max(end, start)
156 156
157 157 # Move the control's cursor to the desired end point
158 158 cursor_pos = self._get_input_buffer_cursor_pos()
159 159 if end < cursor_pos:
160 160 cursor.movePosition(QtGui.QTextCursor.Left,
161 161 n=(cursor_pos - end))
162 162 elif end > cursor_pos:
163 163 cursor.movePosition(QtGui.QTextCursor.Right,
164 164 n=(end - cursor_pos))
165 165 # This line actually applies the move to control's cursor
166 166 self._control.setTextCursor(cursor)
167 167
168 168 offset = end - start
169 169 # Move the local cursor object to the start of the match and
170 170 # complete.
171 171 cursor.movePosition(QtGui.QTextCursor.Left, n=offset)
172 172 self._complete_with_items(cursor, matches)
173 173
174 174 def _handle_execute_reply(self, msg):
175 175 """ Reimplemented to support prompt requests.
176 176 """
177 177 msg_id = msg['parent_header'].get('msg_id')
178 178 info = self._request_info['execute'].get(msg_id)
179 179 if info and info.kind == 'prompt':
180 180 content = msg['content']
181 181 if content['status'] == 'aborted':
182 182 self._show_interpreter_prompt()
183 183 else:
184 184 number = content['execution_count'] + 1
185 185 self._show_interpreter_prompt(number)
186 186 self._request_info['execute'].pop(msg_id)
187 187 else:
188 188 super(IPythonWidget, self)._handle_execute_reply(msg)
189 189
190 190 def _handle_history_reply(self, msg):
191 191 """ Implemented to handle history tail replies, which are only supported
192 192 by the IPython kernel.
193 193 """
194 194 content = msg['content']
195 195 if 'history' not in content:
196 196 self.log.error("History request failed: %r"%content)
197 197 if content.get('status', '') == 'aborted' and \
198 198 not self._retrying_history_request:
199 199 # a *different* action caused this request to be aborted, so
200 200 # we should try again.
201 201 self.log.error("Retrying aborted history request")
202 202 # prevent multiple retries of aborted requests:
203 203 self._retrying_history_request = True
204 204 # wait out the kernel's queue flush, which is currently timed at 0.1s
205 205 time.sleep(0.25)
206 206 self.kernel_client.shell_channel.history(hist_access_type='tail',n=1000)
207 207 else:
208 208 self._retrying_history_request = False
209 209 return
210 210 # reset retry flag
211 211 self._retrying_history_request = False
212 212 history_items = content['history']
213 213 self.log.debug("Received history reply with %i entries", len(history_items))
214 214 items = []
215 215 last_cell = u""
216 216 for _, _, cell in history_items:
217 217 cell = cell.rstrip()
218 218 if cell != last_cell:
219 219 items.append(cell)
220 220 last_cell = cell
221 221 self._set_history(items)
222 222
223 223 def _insert_other_input(self, cursor, content):
224 224 """Insert function for input from other frontends"""
225 225 cursor.beginEditBlock()
226 226 start = cursor.position()
227 227 n = content.get('execution_count', 0)
228 228 cursor.insertText('\n')
229 229 self._insert_html(cursor, self._make_in_prompt(n))
230 230 cursor.insertText(content['code'])
231 231 self._highlighter.rehighlightBlock(cursor.block())
232 232 cursor.endEditBlock()
233 233
234 234 def _handle_execute_input(self, msg):
235 235 """Handle an execute_input message"""
236 236 self.log.debug("execute_input: %s", msg.get('content', ''))
237 237 if self.include_output(msg):
238 238 self._append_custom(self._insert_other_input, msg['content'], before_prompt=True)
239 239
240 240
241 241 def _handle_execute_result(self, msg):
242 242 """ Reimplemented for IPython-style "display hook".
243 243 """
244 244 self.log.debug("execute_result: %s", msg.get('content', ''))
245 245 if self.include_output(msg):
246 246 self.flush_clearoutput()
247 247 content = msg['content']
248 248 prompt_number = content.get('execution_count', 0)
249 249 data = content['data']
250 250 if 'text/plain' in data:
251 251 self._append_plain_text(self.output_sep, True)
252 252 self._append_html(self._make_out_prompt(prompt_number), True)
253 253 text = data['text/plain']
254 254 # If the repr is multiline, make sure we start on a new line,
255 255 # so that its lines are aligned.
256 256 if "\n" in text and not self.output_sep.endswith("\n"):
257 257 self._append_plain_text('\n', True)
258 258 self._append_plain_text(text + self.output_sep2, True)
259 259
260 260 def _handle_display_data(self, msg):
261 261 """ The base handler for the ``display_data`` message.
262 262 """
263 263 self.log.debug("display: %s", msg.get('content', ''))
264 264 # For now, we don't display data from other frontends, but we
265 265 # eventually will as this allows all frontends to monitor the display
266 266 # data. But we need to figure out how to handle this in the GUI.
267 267 if self.include_output(msg):
268 268 self.flush_clearoutput()
269 269 data = msg['content']['data']
270 270 metadata = msg['content']['metadata']
271 271 # In the regular IPythonWidget, we simply print the plain text
272 272 # representation.
273 273 if 'text/plain' in data:
274 274 text = data['text/plain']
275 275 self._append_plain_text(text, True)
276 276 # This newline seems to be needed for text and html output.
277 277 self._append_plain_text(u'\n', True)
278 278
279 279 def _handle_kernel_info_reply(self, rep):
280 280 """Handle kernel info replies."""
281 281 content = rep['content']
282 282 if not self._guiref_loaded:
283 283 if content.get('language') == 'python':
284 284 self._load_guiref_magic()
285 285 self._guiref_loaded = True
286 286
287 287 self.kernel_banner = content.get('banner', '')
288 288 if self._starting:
289 289 # finish handling started channels
290 290 self._starting = False
291 291 super(IPythonWidget, self)._started_channels()
292 292
293 293 def _started_channels(self):
294 294 """Reimplemented to make a history request and load %guiref."""
295 295 self._starting = True
296 296 # The reply will trigger %guiref load provided language=='python'
297 297 self.kernel_client.kernel_info()
298 298
299 299 self.kernel_client.shell_channel.history(hist_access_type='tail',
300 300 n=1000)
301 301
302 302 def _load_guiref_magic(self):
303 303 """Load %guiref magic."""
304 304 self.kernel_client.shell_channel.execute('\n'.join([
305 305 "try:",
306 306 " _usage",
307 307 "except:",
308 308 " from IPython.core import usage as _usage",
309 309 " get_ipython().register_magic_function(_usage.page_guiref, 'line', 'guiref')",
310 310 " del _usage",
311 311 ]), silent=True)
312 312
313 313 #---------------------------------------------------------------------------
314 314 # 'ConsoleWidget' public interface
315 315 #---------------------------------------------------------------------------
316 316
317 317 #---------------------------------------------------------------------------
318 318 # 'FrontendWidget' public interface
319 319 #---------------------------------------------------------------------------
320 320
321 321 def execute_file(self, path, hidden=False):
322 322 """ Reimplemented to use the 'run' magic.
323 323 """
324 324 # Use forward slashes on Windows to avoid escaping each separator.
325 325 if sys.platform == 'win32':
326 326 path = os.path.normpath(path).replace('\\', '/')
327 327
328 328 # Perhaps we should not be using %run directly, but while we
329 329 # are, it is necessary to quote or escape filenames containing spaces
330 330 # or quotes.
331 331
332 332 # In earlier code here, to minimize escaping, we sometimes quoted the
333 333 # filename with single quotes. But to do this, this code must be
334 334 # platform-aware, because run uses shlex rather than python string
335 335 # parsing, so that:
336 336 # * In Win: single quotes can be used in the filename without quoting,
337 337 # and we cannot use single quotes to quote the filename.
338 338 # * In *nix: we can escape double quotes in a double quoted filename,
339 339 # but can't escape single quotes in a single quoted filename.
340 340
341 341 # So to keep this code non-platform-specific and simple, we now only
342 342 # use double quotes to quote filenames, and escape when needed:
343 343 if ' ' in path or "'" in path or '"' in path:
344 344 path = '"%s"' % path.replace('"', '\\"')
345 345 self.execute('%%run %s' % path, hidden=hidden)
346 346
347 347 #---------------------------------------------------------------------------
348 348 # 'FrontendWidget' protected interface
349 349 #---------------------------------------------------------------------------
350 350
351 351 def _process_execute_error(self, msg):
352 352 """ Reimplemented for IPython-style traceback formatting.
353 353 """
354 354 content = msg['content']
355 355 traceback = '\n'.join(content['traceback']) + '\n'
356 356 if False:
357 357 # FIXME: For now, tracebacks come as plain text, so we can't use
358 358 # the html renderer yet. Once we refactor ultratb to produce
359 359 # properly styled tracebacks, this branch should be the default
360 360 traceback = traceback.replace(' ', '&nbsp;')
361 361 traceback = traceback.replace('\n', '<br/>')
362 362
363 363 ename = content['ename']
364 364 ename_styled = '<span class="error">%s</span>' % ename
365 365 traceback = traceback.replace(ename, ename_styled)
366 366
367 367 self._append_html(traceback)
368 368 else:
369 369 # This is the fallback for now, using plain text with ansi escapes
370 370 self._append_plain_text(traceback)
371 371
372 372 def _process_execute_payload(self, item):
373 373 """ Reimplemented to dispatch payloads to handler methods.
374 374 """
375 375 handler = self._payload_handlers.get(item['source'])
376 376 if handler is None:
377 377 # We have no handler for this type of payload, simply ignore it
378 378 return False
379 379 else:
380 380 handler(item)
381 381 return True
382 382
383 383 def _show_interpreter_prompt(self, number=None):
384 384 """ Reimplemented for IPython-style prompts.
385 385 """
386 386 # If a number was not specified, make a prompt number request.
387 387 if number is None:
388 388 msg_id = self.kernel_client.shell_channel.execute('', silent=True)
389 389 info = self._ExecutionRequest(msg_id, 'prompt')
390 390 self._request_info['execute'][msg_id] = info
391 391 return
392 392
393 393 # Show a new prompt and save information about it so that it can be
394 394 # updated later if the prompt number turns out to be wrong.
395 395 self._prompt_sep = self.input_sep
396 396 self._show_prompt(self._make_in_prompt(number), html=True)
397 397 block = self._control.document().lastBlock()
398 398 length = len(self._prompt)
399 399 self._previous_prompt_obj = self._PromptBlock(block, length, number)
400 400
401 401 # Update continuation prompt to reflect (possibly) new prompt length.
402 402 self._set_continuation_prompt(
403 403 self._make_continuation_prompt(self._prompt), html=True)
404 404
405 405 def _show_interpreter_prompt_for_reply(self, msg):
406 406 """ Reimplemented for IPython-style prompts.
407 407 """
408 408 # Update the old prompt number if necessary.
409 409 content = msg['content']
410 410 # abort replies do not have any keys:
411 411 if content['status'] == 'aborted':
412 412 if self._previous_prompt_obj:
413 413 previous_prompt_number = self._previous_prompt_obj.number
414 414 else:
415 415 previous_prompt_number = 0
416 416 else:
417 417 previous_prompt_number = content['execution_count']
418 418 if self._previous_prompt_obj and \
419 419 self._previous_prompt_obj.number != previous_prompt_number:
420 420 block = self._previous_prompt_obj.block
421 421
422 422 # Make sure the prompt block has not been erased.
423 423 if block.isValid() and block.text():
424 424
425 425 # Remove the old prompt and insert a new prompt.
426 426 cursor = QtGui.QTextCursor(block)
427 427 cursor.movePosition(QtGui.QTextCursor.Right,
428 428 QtGui.QTextCursor.KeepAnchor,
429 429 self._previous_prompt_obj.length)
430 430 prompt = self._make_in_prompt(previous_prompt_number)
431 431 self._prompt = self._insert_html_fetching_plain_text(
432 432 cursor, prompt)
433 433
434 434 # When the HTML is inserted, Qt blows away the syntax
435 435 # highlighting for the line, so we need to rehighlight it.
436 436 self._highlighter.rehighlightBlock(cursor.block())
437 437
438 438 self._previous_prompt_obj = None
439 439
440 440 # Show a new prompt with the kernel's estimated prompt number.
441 441 self._show_interpreter_prompt(previous_prompt_number + 1)
442 442
443 443 #---------------------------------------------------------------------------
444 444 # 'IPythonWidget' interface
445 445 #---------------------------------------------------------------------------
446 446
447 447 def set_default_style(self, colors='lightbg'):
448 448 """ Sets the widget style to the class defaults.
449 449
450 450 Parameters
451 451 ----------
452 452 colors : str, optional (default lightbg)
453 453 Whether to use the default IPython light background or dark
454 454 background or B&W style.
455 455 """
456 456 colors = colors.lower()
457 457 if colors=='lightbg':
458 458 self.style_sheet = styles.default_light_style_sheet
459 459 self.syntax_style = styles.default_light_syntax_style
460 460 elif colors=='linux':
461 461 self.style_sheet = styles.default_dark_style_sheet
462 462 self.syntax_style = styles.default_dark_syntax_style
463 463 elif colors=='nocolor':
464 464 self.style_sheet = styles.default_bw_style_sheet
465 465 self.syntax_style = styles.default_bw_syntax_style
466 466 else:
467 467 raise KeyError("No such color scheme: %s"%colors)
468 468
469 469 #---------------------------------------------------------------------------
470 470 # 'IPythonWidget' protected interface
471 471 #---------------------------------------------------------------------------
472 472
473 473 def _edit(self, filename, line=None):
474 474 """ Opens a Python script for editing.
475 475
476 476 Parameters
477 477 ----------
478 478 filename : str
479 479 A path to a local system file.
480 480
481 481 line : int, optional
482 482 A line of interest in the file.
483 483 """
484 484 if self.custom_edit:
485 485 self.custom_edit_requested.emit(filename, line)
486 486 elif not self.editor:
487 487 self._append_plain_text('No default editor available.\n'
488 488 'Specify a GUI text editor in the `IPythonWidget.editor` '
489 489 'configurable to enable the %edit magic')
490 490 else:
491 491 try:
492 492 filename = '"%s"' % filename
493 493 if line and self.editor_line:
494 494 command = self.editor_line.format(filename=filename,
495 495 line=line)
496 496 else:
497 497 try:
498 498 command = self.editor.format()
499 499 except KeyError:
500 500 command = self.editor.format(filename=filename)
501 501 else:
502 502 command += ' ' + filename
503 503 except KeyError:
504 504 self._append_plain_text('Invalid editor command.\n')
505 505 else:
506 506 try:
507 507 Popen(command, shell=True)
508 508 except OSError:
509 509 msg = 'Opening editor with command "%s" failed.\n'
510 510 self._append_plain_text(msg % command)
511 511
512 512 def _make_in_prompt(self, number):
513 513 """ Given a prompt number, returns an HTML In prompt.
514 514 """
515 515 try:
516 516 body = self.in_prompt % number
517 517 except TypeError:
518 518 # allow in_prompt to leave out number, e.g. '>>> '
519 519 from xml.sax.saxutils import escape
520 520 body = escape(self.in_prompt)
521 521 return '<span class="in-prompt">%s</span>' % body
522 522
523 523 def _make_continuation_prompt(self, prompt):
524 524 """ Given a plain text version of an In prompt, returns an HTML
525 525 continuation prompt.
526 526 """
527 527 end_chars = '...: '
528 528 space_count = len(prompt.lstrip('\n')) - len(end_chars)
529 529 body = '&nbsp;' * space_count + end_chars
530 530 return '<span class="in-prompt">%s</span>' % body
531 531
532 532 def _make_out_prompt(self, number):
533 533 """ Given a prompt number, returns an HTML Out prompt.
534 534 """
535 535 try:
536 536 body = self.out_prompt % number
537 537 except TypeError:
538 538 # allow out_prompt to leave out number, e.g. '<<< '
539 539 from xml.sax.saxutils import escape
540 540 body = escape(self.out_prompt)
541 541 return '<span class="out-prompt">%s</span>' % body
542 542
543 543 #------ Payload handlers --------------------------------------------------
544 544
545 545 # Payload handlers with a generic interface: each takes the opaque payload
546 546 # dict, unpacks it and calls the underlying functions with the necessary
547 547 # arguments.
548 548
549 549 def _handle_payload_edit(self, item):
550 550 self._edit(item['filename'], item['line_number'])
551 551
552 552 def _handle_payload_exit(self, item):
553 553 self._keep_kernel_on_exit = item['keepkernel']
554 554 self.exit_requested.emit(self)
555 555
556 556 def _handle_payload_next_input(self, item):
557 557 self.input_buffer = item['text']
558 558
559 559 def _handle_payload_page(self, item):
560 560 # Since the plain text widget supports only a very small subset of HTML
561 561 # and we have no control over the HTML source, we only page HTML
562 562 # payloads in the rich text widget.
563 563 data = item['data']
564 564 if 'text/html' in data and self.kind == 'rich':
565 565 self._page(data['text/html'], html=True)
566 566 else:
567 567 self._page(data['text/plain'], html=False)
568 568
569 569 #------ Trait change handlers --------------------------------------------
570 570
571 571 def _style_sheet_changed(self):
572 572 """ Set the style sheets of the underlying widgets.
573 573 """
574 574 self.setStyleSheet(self.style_sheet)
575 575 if self._control is not None:
576 576 self._control.document().setDefaultStyleSheet(self.style_sheet)
577 577 bg_color = self._control.palette().window().color()
578 578 self._ansi_processor.set_background_color(bg_color)
579 579
580 580 if self._page_control is not None:
581 581 self._page_control.document().setDefaultStyleSheet(self.style_sheet)
582 582
583 583
584 584
585 585 def _syntax_style_changed(self):
586 586 """ Set the style for the syntax highlighter.
587 587 """
588 588 if self._highlighter is None:
589 589 # ignore premature calls
590 590 return
591 591 if self.syntax_style:
592 592 self._highlighter.set_style(self.syntax_style)
593 593 else:
594 594 self._highlighter.set_style_sheet(self.style_sheet)
595 595
596 596 #------ Trait default initializers -----------------------------------------
597 597
598 598 def _banner_default(self):
599 599 return "IPython QtConsole {version}\n".format(version=version)
@@ -1,1138 +1,1184 b''
1 1 .. _messaging:
2 2
3 3 ======================
4 4 Messaging in IPython
5 5 ======================
6 6
7 7
8 8 Versioning
9 9 ==========
10 10
11 11 The IPython message specification is versioned independently of IPython.
12 12 The current version of the specification is 5.0.
13 13
14 14
15 15 Introduction
16 16 ============
17 17
18 18 This document explains the basic communications design and messaging
19 19 specification for how the various IPython objects interact over a network
20 20 transport. The current implementation uses the ZeroMQ_ library for messaging
21 21 within and between hosts.
22 22
23 23 .. Note::
24 24
25 25 This document should be considered the authoritative description of the
26 26 IPython messaging protocol, and all developers are strongly encouraged to
27 27 keep it updated as the implementation evolves, so that we have a single
28 28 common reference for all protocol details.
29 29
30 30 The basic design is explained in the following diagram:
31 31
32 32 .. image:: figs/frontend-kernel.png
33 33 :width: 450px
34 34 :alt: IPython kernel/frontend messaging architecture.
35 35 :align: center
36 36 :target: ../_images/frontend-kernel.png
37 37
38 38 A single kernel can be simultaneously connected to one or more frontends. The
39 39 kernel has three sockets that serve the following functions:
40 40
41 41 1. Shell: this single ROUTER socket allows multiple incoming connections from
42 42 frontends, and this is the socket where requests for code execution, object
43 43 information, prompts, etc. are made to the kernel by any frontend. The
44 44 communication on this socket is a sequence of request/reply actions from
45 45 each frontend and the kernel.
46 46
47 47 2. IOPub: this socket is the 'broadcast channel' where the kernel publishes all
48 48 side effects (stdout, stderr, etc.) as well as the requests coming from any
49 49 client over the shell socket and its own requests on the stdin socket. There
50 50 are a number of actions in Python which generate side effects: :func:`print`
51 51 writes to ``sys.stdout``, errors generate tracebacks, etc. Additionally, in
52 52 a multi-client scenario, we want all frontends to be able to know what each
53 53 other has sent to the kernel (this can be useful in collaborative scenarios,
54 54 for example). This socket allows both side effects and the information
55 55 about communications taking place with one client over the shell channel
56 56 to be made available to all clients in a uniform manner.
57 57
58 58 3. stdin: this ROUTER socket is connected to all frontends, and it allows
59 59 the kernel to request input from the active frontend when :func:`raw_input` is called.
60 60 The frontend that executed the code has a DEALER socket that acts as a 'virtual keyboard'
61 61 for the kernel while this communication is happening (illustrated in the
62 62 figure by the black outline around the central keyboard). In practice,
63 63 frontends may display such kernel requests using a special input widget or
64 64 otherwise indicating that the user is to type input for the kernel instead
65 65 of normal commands in the frontend.
66 66
67 67 All messages are tagged with enough information (details below) for clients
68 68 to know which messages come from their own interaction with the kernel and
69 69 which ones are from other clients, so they can display each type
70 70 appropriately.
71 71
72 72 4. Control: This channel is identical to Shell, but operates on a separate socket,
73 73 to allow important messages to avoid queueing behind execution requests (e.g. shutdown or abort).
74 74
75 75 The actual format of the messages allowed on each of these channels is
76 76 specified below. Messages are dicts of dicts with string keys and values that
77 77 are reasonably representable in JSON. Our current implementation uses JSON
78 78 explicitly as its message format, but this shouldn't be considered a permanent
79 79 feature. As we've discovered that JSON has non-trivial performance issues due
80 80 to excessive copying, we may in the future move to a pure pickle-based raw
81 81 message format. However, it should be possible to easily convert from the raw
82 82 objects to JSON, since we may have non-python clients (e.g. a web frontend).
83 83 As long as it's easy to make a JSON version of the objects that is a faithful
84 84 representation of all the data, we can communicate with such clients.
85 85
86 86 .. Note::
87 87
88 88 Not all of these have yet been fully fleshed out, but the key ones are, see
89 89 kernel and frontend files for actual implementation details.
90 90
91 91 General Message Format
92 92 ======================
93 93
94 94 A message is defined by the following four-dictionary structure::
95 95
96 96 {
97 97 # The message header contains a pair of unique identifiers for the
98 98 # originating session and the actual message id, in addition to the
99 99 # username for the process that generated the message. This is useful in
100 100 # collaborative settings where multiple users may be interacting with the
101 101 # same kernel simultaneously, so that frontends can label the various
102 102 # messages in a meaningful way.
103 103 'header' : {
104 104 'msg_id' : uuid,
105 105 'username' : str,
106 106 'session' : uuid,
107 107 # All recognized message type strings are listed below.
108 108 'msg_type' : str,
109 109 # the message protocol version
110 110 'version' : '5.0',
111 111 },
112 112
113 113 # In a chain of messages, the header from the parent is copied so that
114 114 # clients can track where messages come from.
115 115 'parent_header' : dict,
116 116
117 117 # Any metadata associated with the message.
118 118 'metadata' : dict,
119 119
120 120 # The actual content of the message must be a dict, whose structure
121 121 # depends on the message type.
122 122 'content' : dict,
123 123 }
124 124
125 125 .. versionchanged:: 5.0
126 126
127 127 ``version`` key added to the header.
128 128
129 129 .. _wire_protocol:
130 130
131 131 The Wire Protocol
132 132 =================
133 133
134 134
135 135 This message format exists at a high level,
136 136 but does not describe the actual *implementation* at the wire level in zeromq.
137 137 The canonical implementation of the message spec is our :class:`~IPython.kernel.zmq.session.Session` class.
138 138
139 139 .. note::
140 140
141 141 This section should only be relevant to non-Python consumers of the protocol.
142 142 Python consumers should simply import and use IPython's own implementation of the wire protocol
143 143 in the :class:`IPython.kernel.zmq.session.Session` object.
144 144
145 145 Every message is serialized to a sequence of at least six blobs of bytes:
146 146
147 147 .. sourcecode:: python
148 148
149 149 [
150 150 b'u-u-i-d', # zmq identity(ies)
151 151 b'<IDS|MSG>', # delimiter
152 152 b'baddad42', # HMAC signature
153 153 b'{header}', # serialized header dict
154 154 b'{parent_header}', # serialized parent header dict
155 155 b'{metadata}', # serialized metadata dict
156 156 b'{content}, # serialized content dict
157 157 b'blob', # extra raw data buffer(s)
158 158 ...
159 159 ]
160 160
161 161 The front of the message is the ZeroMQ routing prefix,
162 162 which can be zero or more socket identities.
163 163 This is every piece of the message prior to the delimiter key ``<IDS|MSG>``.
164 164 In the case of IOPub, there should be just one prefix component,
165 165 which is the topic for IOPub subscribers, e.g. ``execute_result``, ``display_data``.
166 166
167 167 .. note::
168 168
169 169 In most cases, the IOPub topics are irrelevant and completely ignored,
170 170 because frontends just subscribe to all topics.
171 171 The convention used in the IPython kernel is to use the msg_type as the topic,
172 172 and possibly extra information about the message, e.g. ``execute_result`` or ``stream.stdout``
173 173
174 174 After the delimiter is the `HMAC`_ signature of the message, used for authentication.
175 175 If authentication is disabled, this should be an empty string.
176 176 By default, the hashing function used for computing these signatures is sha256.
177 177
178 178 .. _HMAC: http://en.wikipedia.org/wiki/HMAC
179 179
180 180 .. note::
181 181
182 182 To disable authentication and signature checking,
183 183 set the `key` field of a connection file to an empty string.
184 184
185 185 The signature is the HMAC hex digest of the concatenation of:
186 186
187 187 - A shared key (typically the ``key`` field of a connection file)
188 188 - The serialized header dict
189 189 - The serialized parent header dict
190 190 - The serialized metadata dict
191 191 - The serialized content dict
192 192
193 193 In Python, this is implemented via:
194 194
195 195 .. sourcecode:: python
196 196
197 197 # once:
198 198 digester = HMAC(key, digestmod=hashlib.sha256)
199 199
200 200 # for each message
201 201 d = digester.copy()
202 202 for serialized_dict in (header, parent, metadata, content):
203 203 d.update(serialized_dict)
204 204 signature = d.hexdigest()
205 205
206 206 After the signature is the actual message, always in four frames of bytes.
207 207 The four dictionaries that compose a message are serialized separately,
208 208 in the order of header, parent header, metadata, and content.
209 209 These can be serialized by any function that turns a dict into bytes.
210 210 The default and most common serialization is JSON, but msgpack and pickle
211 211 are common alternatives.
212 212
213 213 After the serialized dicts are zero to many raw data buffers,
214 214 which can be used by message types that support binary data (mainly apply and data_pub).
215 215
216 216
217 217 Python functional API
218 218 =====================
219 219
220 220 As messages are dicts, they map naturally to a ``func(**kw)`` call form. We
221 221 should develop, at a few key points, functional forms of all the requests that
222 222 take arguments in this manner and automatically construct the necessary dict
223 223 for sending.
224 224
225 225 In addition, the Python implementation of the message specification extends
226 226 messages upon deserialization to the following form for convenience::
227 227
228 228 {
229 229 'header' : dict,
230 230 # The msg's unique identifier and type are always stored in the header,
231 231 # but the Python implementation copies them to the top level.
232 232 'msg_id' : uuid,
233 233 'msg_type' : str,
234 234 'parent_header' : dict,
235 235 'content' : dict,
236 236 'metadata' : dict,
237 237 }
238 238
239 239 All messages sent to or received by any IPython process should have this
240 240 extended structure.
241 241
242 242
243 243 Messages on the shell ROUTER/DEALER sockets
244 244 ===========================================
245 245
246 246 .. _execute:
247 247
248 248 Execute
249 249 -------
250 250
251 251 This message type is used by frontends to ask the kernel to execute code on
252 252 behalf of the user, in a namespace reserved to the user's variables (and thus
253 253 separate from the kernel's own internal code and variables).
254 254
255 255 Message type: ``execute_request``::
256 256
257 257 content = {
258 258 # Source code to be executed by the kernel, one or more lines.
259 259 'code' : str,
260 260
261 261 # A boolean flag which, if True, signals the kernel to execute
262 262 # this code as quietly as possible.
263 263 # silent=True forces store_history to be False,
264 264 # and will *not*:
265 265 # - broadcast output on the IOPUB channel
266 266 # - have an execute_result
267 267 # The default is False.
268 268 'silent' : bool,
269 269
270 270 # A boolean flag which, if True, signals the kernel to populate history
271 271 # The default is True if silent is False. If silent is True, store_history
272 272 # is forced to be False.
273 273 'store_history' : bool,
274 274
275 275 # A dict mapping names to expressions to be evaluated in the
276 276 # user's dict. The rich display-data representation of each will be evaluated after execution.
277 277 # See the display_data content for the structure of the representation data.
278 278 'user_expressions' : dict,
279 279
280 280 # Some frontends do not support stdin requests.
281 281 # If raw_input is called from code executed from such a frontend,
282 282 # a StdinNotImplementedError will be raised.
283 283 'allow_stdin' : True,
284 284 }
285 285
286 286 .. versionchanged:: 5.0
287 287
288 288 ``user_variables`` removed, because it is redundant with user_expressions.
289 289
290 290 The ``code`` field contains a single string (possibly multiline) to be executed.
291 291
292 292 The ``user_expressions`` field deserves a detailed explanation. In the past, IPython had
293 293 the notion of a prompt string that allowed arbitrary code to be evaluated, and
294 294 this was put to good use by many in creating prompts that displayed system
295 295 status, path information, and even more esoteric uses like remote instrument
296 296 status acquired over the network. But now that IPython has a clean separation
297 297 between the kernel and the clients, the kernel has no prompt knowledge; prompts
298 298 are a frontend feature, and it should be even possible for different
299 299 frontends to display different prompts while interacting with the same kernel.
300 300 ``user_expressions`` can be used to retrieve this information.
301 301
302 302 Any error in evaluating any expression in ``user_expressions`` will result in
303 303 only that key containing a standard error message, of the form::
304 304
305 305 {
306 306 'status' : 'error',
307 307 'ename' : 'NameError',
308 308 'evalue' : 'foo',
309 309 'traceback' : ...
310 310 }
311 311
312 312 .. Note::
313 313
314 314 In order to obtain the current execution counter for the purposes of
315 315 displaying input prompts, frontends may make an execution request with an
316 316 empty code string and ``silent=True``.
317 317
318 318 Upon completion of the execution request, the kernel *always* sends a reply,
319 319 with a status code indicating what happened and additional data depending on
320 320 the outcome. See :ref:`below <execution_results>` for the possible return
321 321 codes and associated data.
322 322
323 323 .. seealso::
324 324
325 325 :ref:`execution_semantics`
326 326
327 327 .. _execution_counter:
328 328
329 329 Execution counter (prompt number)
330 330 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
331 331
332 332 The kernel should have a single, monotonically increasing counter of all execution
333 333 requests that are made with ``store_history=True``. This counter is used to populate
334 334 the ``In[n]`` and ``Out[n]`` prompts. The value of this counter will be returned as the
335 335 ``execution_count`` field of all ``execute_reply`` and ``execute_input`` messages.
336 336
337 337 .. _execution_results:
338 338
339 339 Execution results
340 340 ~~~~~~~~~~~~~~~~~
341 341
342 342 Message type: ``execute_reply``::
343 343
344 344 content = {
345 345 # One of: 'ok' OR 'error' OR 'abort'
346 346 'status' : str,
347 347
348 348 # The global kernel counter that increases by one with each request that
349 349 # stores history. This will typically be used by clients to display
350 350 # prompt numbers to the user. If the request did not store history, this will
351 351 # be the current value of the counter in the kernel.
352 352 'execution_count' : int,
353 353 }
354 354
355 355 When status is 'ok', the following extra fields are present::
356 356
357 357 {
358 # 'payload' will be a list of payload dicts.
359 # Each execution payload is a dict with string keys that may have been
360 # produced by the code being executed. It is retrieved by the kernel at
361 # the end of the execution and sent back to the front end, which can take
362 # action on it as needed.
358 # 'payload' will be a list of payload dicts, and is optional.
359 # payloads are considered deprecated.
363 360 # The only requirement of each payload dict is that it have a 'source' key,
364 # which is a string classifying the payload (e.g. 'pager').
361 # which is a string classifying the payload (e.g. 'page').
362
365 363 'payload' : list(dict),
366 364
367 365 # Results for the user_expressions.
368 366 'user_expressions' : dict,
369 367 }
370 368
371 369 .. versionchanged:: 5.0
372 370
373 371 ``user_variables`` is removed, use user_expressions instead.
374 372
375 .. admonition:: Execution payloads
376
377 The notion of an 'execution payload' is different from a return value of a
378 given set of code, which normally is just displayed on the execute_result stream
379 through the PUB socket. The idea of a payload is to allow special types of
380 code, typically magics, to populate a data container in the IPython kernel
381 that will be shipped back to the caller via this channel. The kernel
382 has an API for this in the PayloadManager::
383
384 ip.payload_manager.write_payload(payload_dict)
385
386 which appends a dictionary to the list of payloads.
387
388 The payload API is not yet stabilized,
389 and should probably not be supported by non-Python kernels at this time.
390 In such cases, the payload list should always be empty.
391
392
393 373 When status is 'error', the following extra fields are present::
394 374
395 375 {
396 376 'ename' : str, # Exception name, as a string
397 377 'evalue' : str, # Exception value, as a string
398 378
399 379 # The traceback will contain a list of frames, represented each as a
400 380 # string. For now we'll stick to the existing design of ultraTB, which
401 381 # controls exception level of detail statefully. But eventually we'll
402 382 # want to grow into a model where more information is collected and
403 383 # packed into the traceback object, with clients deciding how little or
404 384 # how much of it to unpack. But for now, let's start with a simple list
405 385 # of strings, since that requires only minimal changes to ultratb as
406 386 # written.
407 387 'traceback' : list,
408 388 }
409 389
410 390
411 391 When status is 'abort', there are for now no additional data fields. This
412 392 happens when the kernel was interrupted by a signal.
413 393
394 Payloads
395 ********
396
397 .. admonition:: Execution payloads
398
399 Payloads are considered deprecated, though their replacement is not yet implemented.
400
401 Payloads are a way to trigger frontend actions from the kernel. Current payloads:
402
403 **page**: display data in a pager.
404
405 Pager output is used for introspection, or other displayed information that's not considered output.
406 Pager payloads are generally displayed in a separate pane, that can be viewed alongside code,
407 and are not included in notebook documents.
408
409 .. sourcecode:: python
410
411 {
412 "source": "page",
413 # mime-bundle of data to display in the pager.
414 # Must include text/plain.
415 "data": mimebundle,
416 # line offset to start from
417 "start": int,
418 }
419
420 **set_next_input**: create a new output
421
422 used to create new cells in the notebook,
423 or set the next input in a console interface.
424 The main example being ``%load``.
425
426 .. sourcecode:: python
427
428 {
429 "source": "set_next_input",
430 # the text contents of the cell to create
431 "text": "some cell content",
432 }
433
434 **edit**: open a file for editing.
435
436 Triggered by `%edit`. Only the QtConsole currently supports edit payloads.
437
438 .. sourcecode:: python
439
440 {
441 "source": "edit",
442 "filename": "/path/to/file.py", # the file to edit
443 "line_number": int, # the line number to start with
444 }
445
446 **ask_exit**: instruct the frontend to prompt the user for exit
447
448 Allows the kernel to request exit, e.g. via ``%exit`` in IPython.
449 Only for console frontends.
450
451 .. sourcecode:: python
452
453 {
454 "source": "ask_exit",
455 # whether the kernel should be left running, only closing the client
456 "keepkernel": bool,
457 }
458
459
414 460 .. _msging_inspection:
415 461
416 462 Introspection
417 463 -------------
418 464
419 465 Code can be inspected to show useful information to the user.
420 466 It is up to the Kernel to decide what information should be displayed, and its formatting.
421 467
422 468 Message type: ``inspect_request``::
423 469
424 470 content = {
425 471 # The code context in which introspection is requested
426 472 # this may be up to an entire multiline cell.
427 473 'code' : str,
428 474
429 475 # The cursor position within 'code' (in unicode characters) where inspection is requested
430 476 'cursor_pos' : int,
431 477
432 478 # The level of detail desired. In IPython, the default (0) is equivalent to typing
433 479 # 'x?' at the prompt, 1 is equivalent to 'x??'.
434 480 # The difference is up to kernels, but in IPython level 1 includes the source code
435 481 # if available.
436 482 'detail_level' : 0 or 1,
437 483 }
438 484
439 485 .. versionchanged:: 5.0
440 486
441 487 ``object_info_request`` renamed to ``inspect_request``.
442 488
443 489 .. versionchanged:: 5.0
444 490
445 491 ``name`` key replaced with ``code`` and ``cursor_pos``,
446 492 moving the lexing responsibility to the kernel.
447 493
448 494 The reply is a mime-bundle, like a `display_data`_ message,
449 495 which should be a formatted representation of information about the context.
450 496 In the notebook, this is used to show tooltips over function calls, etc.
451 497
452 498 Message type: ``inspect_reply``::
453 499
454 500 content = {
455 501 # 'ok' if the request succeeded or 'error', with error information as in all other replies.
456 502 'status' : 'ok',
457 503
458 504 # data can be empty if nothing is found
459 505 'data' : dict,
460 506 'metadata' : dict,
461 507 }
462 508
463 509 .. versionchanged:: 5.0
464 510
465 511 ``object_info_reply`` renamed to ``inspect_reply``.
466 512
467 513 .. versionchanged:: 5.0
468 514
469 515 Reply is changed from structured data to a mime bundle, allowing formatting decisions to be made by the kernel.
470 516
471 517 .. _msging_completion:
472 518
473 519 Completion
474 520 ----------
475 521
476 522 Message type: ``complete_request``::
477 523
478 524 content = {
479 525 # The code context in which completion is requested
480 526 # this may be up to an entire multiline cell, such as
481 527 # 'foo = a.isal'
482 528 'code' : str,
483 529
484 530 # The cursor position within 'code' (in unicode characters) where completion is requested
485 531 'cursor_pos' : int,
486 532 }
487 533
488 534 .. versionchanged:: 5.0
489 535
490 536 ``line``, ``block``, and ``text`` keys are removed in favor of a single ``code`` for context.
491 537 Lexing is up to the kernel.
492 538
493 539
494 540 Message type: ``complete_reply``::
495 541
496 542 content = {
497 543 # The list of all matches to the completion request, such as
498 544 # ['a.isalnum', 'a.isalpha'] for the above example.
499 545 'matches' : list,
500 546
501 547 # The range of text that should be replaced by the above matches when a completion is accepted.
502 548 # typically cursor_end is the same as cursor_pos in the request.
503 549 'cursor_start' : int,
504 550 'cursor_end' : int,
505 551
506 552 # Information that frontend plugins might use for extra display information about completions.
507 553 'metadata' : dict,
508 554
509 555 # status should be 'ok' unless an exception was raised during the request,
510 556 # in which case it should be 'error', along with the usual error message content
511 557 # in other messages.
512 558 'status' : 'ok'
513 559 }
514 560
515 561 .. versionchanged:: 5.0
516 562
517 563 - ``matched_text`` is removed in favor of ``cursor_start`` and ``cursor_end``.
518 564 - ``metadata`` is added for extended information.
519 565
520 566 .. _msging_history:
521 567
522 568 History
523 569 -------
524 570
525 571 For clients to explicitly request history from a kernel. The kernel has all
526 572 the actual execution history stored in a single location, so clients can
527 573 request it from the kernel when needed.
528 574
529 575 Message type: ``history_request``::
530 576
531 577 content = {
532 578
533 579 # If True, also return output history in the resulting dict.
534 580 'output' : bool,
535 581
536 582 # If True, return the raw input history, else the transformed input.
537 583 'raw' : bool,
538 584
539 585 # So far, this can be 'range', 'tail' or 'search'.
540 586 'hist_access_type' : str,
541 587
542 588 # If hist_access_type is 'range', get a range of input cells. session can
543 589 # be a positive session number, or a negative number to count back from
544 590 # the current session.
545 591 'session' : int,
546 592 # start and stop are line numbers within that session.
547 593 'start' : int,
548 594 'stop' : int,
549 595
550 596 # If hist_access_type is 'tail' or 'search', get the last n cells.
551 597 'n' : int,
552 598
553 599 # If hist_access_type is 'search', get cells matching the specified glob
554 600 # pattern (with * and ? as wildcards).
555 601 'pattern' : str,
556 602
557 603 # If hist_access_type is 'search' and unique is true, do not
558 604 # include duplicated history. Default is false.
559 605 'unique' : bool,
560 606
561 607 }
562 608
563 609 .. versionadded:: 4.0
564 610 The key ``unique`` for ``history_request``.
565 611
566 612 Message type: ``history_reply``::
567 613
568 614 content = {
569 615 # A list of 3 tuples, either:
570 616 # (session, line_number, input) or
571 617 # (session, line_number, (input, output)),
572 618 # depending on whether output was False or True, respectively.
573 619 'history' : list,
574 620 }
575 621
576 622 .. _msging_is_complete:
577 623
578 624 Code completeness
579 625 -----------------
580 626
581 627 .. versionadded:: 5.0
582 628
583 629 When the user enters a line in a console style interface, the console must
584 630 decide whether to immediately execute the current code, or whether to show a
585 631 continuation prompt for further input. For instance, in Python ``a = 5`` would
586 632 be executed immediately, while ``for i in range(5):`` would expect further input.
587 633
588 634 There are four possible replies:
589 635
590 636 - *complete* code is ready to be executed
591 637 - *incomplete* code should prompt for another line
592 638 - *invalid* code will typically be sent for execution, so that the user sees the
593 639 error soonest.
594 640 - *unknown* - if the kernel is not able to determine this. The frontend should
595 641 also handle the kernel not replying promptly. It may default to sending the
596 642 code for execution, or it may implement simple fallback heuristics for whether
597 643 to execute the code (e.g. execute after a blank line).
598 644
599 645 Frontends may have ways to override this, forcing the code to be sent for
600 646 execution or forcing a continuation prompt.
601 647
602 648 Message type: ``is_complete_request``::
603 649
604 650 content = {
605 651 # The code entered so far as a multiline string
606 652 'code' : str,
607 653 }
608 654
609 655 Message type: ``is_complete_reply``::
610 656
611 657 content = {
612 658 # One of 'complete', 'incomplete', 'invalid', 'unknown'
613 659 'status' : str,
614 660
615 661 # If status is 'incomplete', indent should contain the characters to use
616 662 # to indent the next line. This is only a hint: frontends may ignore it
617 663 # and use their own autoindentation rules. For other statuses, this
618 664 # field does not exist.
619 665 'indent': str,
620 666 }
621 667
622 668 Connect
623 669 -------
624 670
625 671 When a client connects to the request/reply socket of the kernel, it can issue
626 672 a connect request to get basic information about the kernel, such as the ports
627 673 the other ZeroMQ sockets are listening on. This allows clients to only have
628 674 to know about a single port (the shell channel) to connect to a kernel.
629 675
630 676 Message type: ``connect_request``::
631 677
632 678 content = {
633 679 }
634 680
635 681 Message type: ``connect_reply``::
636 682
637 683 content = {
638 684 'shell_port' : int, # The port the shell ROUTER socket is listening on.
639 685 'iopub_port' : int, # The port the PUB socket is listening on.
640 686 'stdin_port' : int, # The port the stdin ROUTER socket is listening on.
641 687 'hb_port' : int, # The port the heartbeat socket is listening on.
642 688 }
643 689
644 690 .. _msging_kernel_info:
645 691
646 692 Kernel info
647 693 -----------
648 694
649 695 If a client needs to know information about the kernel, it can
650 696 make a request of the kernel's information.
651 697 This message can be used to fetch core information of the
652 698 kernel, including language (e.g., Python), language version number and
653 699 IPython version number, and the IPython message spec version number.
654 700
655 701 Message type: ``kernel_info_request``::
656 702
657 703 content = {
658 704 }
659 705
660 706 Message type: ``kernel_info_reply``::
661 707
662 708 content = {
663 709 # Version of messaging protocol.
664 710 # The first integer indicates major version. It is incremented when
665 711 # there is any backward incompatible change.
666 712 # The second integer indicates minor version. It is incremented when
667 713 # there is any backward compatible change.
668 714 'protocol_version': 'X.Y.Z',
669 715
670 716 # The kernel implementation name
671 717 # (e.g. 'ipython' for the IPython kernel)
672 718 'implementation': str,
673 719
674 720 # Implementation version number.
675 721 # The version number of the kernel's implementation
676 722 # (e.g. IPython.__version__ for the IPython kernel)
677 723 'implementation_version': 'X.Y.Z',
678 724
679 725 # Programming language in which kernel is implemented.
680 726 # Kernel included in IPython returns 'python'.
681 727 'language': str,
682 728
683 729 # Language version number.
684 730 # It is Python version number (e.g., '2.7.3') for the kernel
685 731 # included in IPython.
686 732 'language_version': 'X.Y.Z',
687 733
688 734 # Information about the language of code for the kernel
689 735 'language_info': {
690 736 'mimetype': str,
691 737
692 738 # Pygments lexer, for highlighting
693 739 # Only needed if it differs from the top level 'language' field.
694 740 'pygments_lexer': str,
695 741
696 742 # Codemirror mode, for for highlighting in the notebook.
697 743 # Only needed if it differs from the top level 'language' field.
698 744 'codemirror_mode': str or dict,
699 745 },
700 746
701 747 # A banner of information about the kernel,
702 748 # which may be desplayed in console environments.
703 749 'banner' : str,
704 750
705 751 # Optional: A list of dictionaries, each with keys 'text' and 'url'.
706 752 # These will be displayed in the help menu in the notebook UI.
707 753 'help_links': [
708 754 {'text': str, 'url': str}
709 755 ],
710 756 }
711 757
712 758 Refer to the lists of available `Pygments lexers <http://pygments.org/docs/lexers/>`_
713 759 and `codemirror modes <http://codemirror.net/mode/index.html>`_ for those fields.
714 760
715 761 .. versionchanged:: 5.0
716 762
717 763 Versions changed from lists of integers to strings.
718 764
719 765 .. versionchanged:: 5.0
720 766
721 767 ``ipython_version`` is removed.
722 768
723 769 .. versionchanged:: 5.0
724 770
725 771 ``language_info``, ``implementation``, ``implementation_version``, ``banner``
726 772 and ``help_links`` keys are added.
727 773
728 774 .. _msging_shutdown:
729 775
730 776 Kernel shutdown
731 777 ---------------
732 778
733 779 The clients can request the kernel to shut itself down; this is used in
734 780 multiple cases:
735 781
736 782 - when the user chooses to close the client application via a menu or window
737 783 control.
738 784 - when the user types 'exit' or 'quit' (or their uppercase magic equivalents).
739 785 - when the user chooses a GUI method (like the 'Ctrl-C' shortcut in the
740 786 IPythonQt client) to force a kernel restart to get a clean kernel without
741 787 losing client-side state like history or inlined figures.
742 788
743 789 The client sends a shutdown request to the kernel, and once it receives the
744 790 reply message (which is otherwise empty), it can assume that the kernel has
745 791 completed shutdown safely.
746 792
747 793 Upon their own shutdown, client applications will typically execute a last
748 794 minute sanity check and forcefully terminate any kernel that is still alive, to
749 795 avoid leaving stray processes in the user's machine.
750 796
751 797 Message type: ``shutdown_request``::
752 798
753 799 content = {
754 800 'restart' : bool # whether the shutdown is final, or precedes a restart
755 801 }
756 802
757 803 Message type: ``shutdown_reply``::
758 804
759 805 content = {
760 806 'restart' : bool # whether the shutdown is final, or precedes a restart
761 807 }
762 808
763 809 .. Note::
764 810
765 811 When the clients detect a dead kernel thanks to inactivity on the heartbeat
766 812 socket, they simply send a forceful process termination signal, since a dead
767 813 process is unlikely to respond in any useful way to messages.
768 814
769 815
770 816 Messages on the PUB/SUB socket
771 817 ==============================
772 818
773 819 Streams (stdout, stderr, etc)
774 820 ------------------------------
775 821
776 822 Message type: ``stream``::
777 823
778 824 content = {
779 825 # The name of the stream is one of 'stdout', 'stderr'
780 826 'name' : str,
781 827
782 828 # The text is an arbitrary string to be written to that stream
783 829 'text' : str,
784 830 }
785 831
786 832 .. versionchanged:: 5.0
787 833
788 834 'data' key renamed to 'text' for conistency with the notebook format.
789 835
790 836 Display Data
791 837 ------------
792 838
793 839 This type of message is used to bring back data that should be displayed (text,
794 840 html, svg, etc.) in the frontends. This data is published to all frontends.
795 841 Each message can have multiple representations of the data; it is up to the
796 842 frontend to decide which to use and how. A single message should contain all
797 843 possible representations of the same information. Each representation should
798 844 be a JSON'able data structure, and should be a valid MIME type.
799 845
800 846 Some questions remain about this design:
801 847
802 848 * Do we use this message type for execute_result/displayhook? Probably not, because
803 849 the displayhook also has to handle the Out prompt display. On the other hand
804 850 we could put that information into the metadata section.
805 851
806 852 .. _display_data:
807 853
808 854 Message type: ``display_data``::
809 855
810 856 content = {
811 857
812 858 # Who create the data
813 859 'source' : str,
814 860
815 861 # The data dict contains key/value pairs, where the keys are MIME
816 862 # types and the values are the raw data of the representation in that
817 863 # format.
818 864 'data' : dict,
819 865
820 866 # Any metadata that describes the data
821 867 'metadata' : dict
822 868 }
823 869
824 870
825 871 The ``metadata`` contains any metadata that describes the output.
826 872 Global keys are assumed to apply to the output as a whole.
827 873 The ``metadata`` dict can also contain mime-type keys, which will be sub-dictionaries,
828 874 which are interpreted as applying only to output of that type.
829 875 Third parties should put any data they write into a single dict
830 876 with a reasonably unique name to avoid conflicts.
831 877
832 878 The only metadata keys currently defined in IPython are the width and height
833 879 of images::
834 880
835 881 metadata = {
836 882 'image/png' : {
837 883 'width': 640,
838 884 'height': 480
839 885 }
840 886 }
841 887
842 888
843 889 .. versionchanged:: 5.0
844 890
845 891 `application/json` data should be unpacked JSON data,
846 892 not double-serialized as a JSON string.
847 893
848 894
849 895 Raw Data Publication
850 896 --------------------
851 897
852 898 ``display_data`` lets you publish *representations* of data, such as images and html.
853 899 This ``data_pub`` message lets you publish *actual raw data*, sent via message buffers.
854 900
855 901 data_pub messages are constructed via the :func:`IPython.lib.datapub.publish_data` function:
856 902
857 903 .. sourcecode:: python
858 904
859 905 from IPython.kernel.zmq.datapub import publish_data
860 906 ns = dict(x=my_array)
861 907 publish_data(ns)
862 908
863 909
864 910 Message type: ``data_pub``::
865 911
866 912 content = {
867 913 # the keys of the data dict, after it has been unserialized
868 914 'keys' : ['a', 'b']
869 915 }
870 916 # the namespace dict will be serialized in the message buffers,
871 917 # which will have a length of at least one
872 918 buffers = [b'pdict', ...]
873 919
874 920
875 921 The interpretation of a sequence of data_pub messages for a given parent request should be
876 922 to update a single namespace with subsequent results.
877 923
878 924 .. note::
879 925
880 926 No frontends directly handle data_pub messages at this time.
881 927 It is currently only used by the client/engines in :mod:`IPython.parallel`,
882 928 where engines may publish *data* to the Client,
883 929 of which the Client can then publish *representations* via ``display_data``
884 930 to various frontends.
885 931
886 932 Code inputs
887 933 -----------
888 934
889 935 To let all frontends know what code is being executed at any given time, these
890 936 messages contain a re-broadcast of the ``code`` portion of an
891 937 :ref:`execute_request <execute>`, along with the :ref:`execution_count
892 938 <execution_counter>`.
893 939
894 940 Message type: ``execute_input``::
895 941
896 942 content = {
897 943 'code' : str, # Source code to be executed, one or more lines
898 944
899 945 # The counter for this execution is also provided so that clients can
900 946 # display it, since IPython automatically creates variables called _iN
901 947 # (for input prompt In[N]).
902 948 'execution_count' : int
903 949 }
904 950
905 951 .. versionchanged:: 5.0
906 952
907 953 ``pyin`` is renamed to ``execute_input``.
908 954
909 955
910 956 Execution results
911 957 -----------------
912 958
913 959 Results of an execution are published as an ``execute_result``.
914 960 These are identical to `display_data`_ messages, with the addition of an ``execution_count`` key.
915 961
916 962 Results can have multiple simultaneous formats depending on its
917 963 configuration. A plain text representation should always be provided
918 964 in the ``text/plain`` mime-type. Frontends are free to display any or all of these
919 965 according to its capabilities.
920 966 Frontends should ignore mime-types they do not understand. The data itself is
921 967 any JSON object and depends on the format. It is often, but not always a string.
922 968
923 969 Message type: ``execute_result``::
924 970
925 971 content = {
926 972
927 973 # The counter for this execution is also provided so that clients can
928 974 # display it, since IPython automatically creates variables called _N
929 975 # (for prompt N).
930 976 'execution_count' : int,
931 977
932 978 # data and metadata are identical to a display_data message.
933 979 # the object being displayed is that passed to the display hook,
934 980 # i.e. the *result* of the execution.
935 981 'data' : dict,
936 982 'metadata' : dict,
937 983 }
938 984
939 985 Execution errors
940 986 ----------------
941 987
942 988 When an error occurs during code execution
943 989
944 990 Message type: ``error``::
945 991
946 992 content = {
947 993 # Similar content to the execute_reply messages for the 'error' case,
948 994 # except the 'status' field is omitted.
949 995 }
950 996
951 997 .. versionchanged:: 5.0
952 998
953 999 ``pyerr`` renamed to ``error``
954 1000
955 1001 Kernel status
956 1002 -------------
957 1003
958 1004 This message type is used by frontends to monitor the status of the kernel.
959 1005
960 1006 Message type: ``status``::
961 1007
962 1008 content = {
963 1009 # When the kernel starts to handle a message, it will enter the 'busy'
964 1010 # state and when it finishes, it will enter the 'idle' state.
965 1011 # The kernel will publish state 'starting' exactly once at process startup.
966 1012 execution_state : ('busy', 'idle', 'starting')
967 1013 }
968 1014
969 1015 .. versionchanged:: 5.0
970 1016
971 1017 Busy and idle messages should be sent before/after handling every message,
972 1018 not just execution.
973 1019
974 1020 Clear output
975 1021 ------------
976 1022
977 1023 This message type is used to clear the output that is visible on the frontend.
978 1024
979 1025 Message type: ``clear_output``::
980 1026
981 1027 content = {
982 1028
983 1029 # Wait to clear the output until new output is available. Clears the
984 1030 # existing output immediately before the new output is displayed.
985 1031 # Useful for creating simple animations with minimal flickering.
986 1032 'wait' : bool,
987 1033 }
988 1034
989 1035 .. versionchanged:: 4.1
990 1036
991 1037 ``stdout``, ``stderr``, and ``display`` boolean keys for selective clearing are removed,
992 1038 and ``wait`` is added.
993 1039 The selective clearing keys are ignored in v4 and the default behavior remains the same,
994 1040 so v4 clear_output messages will be safely handled by a v4.1 frontend.
995 1041
996 1042
997 1043 Messages on the stdin ROUTER/DEALER sockets
998 1044 ===========================================
999 1045
1000 1046 This is a socket where the request/reply pattern goes in the opposite direction:
1001 1047 from the kernel to a *single* frontend, and its purpose is to allow
1002 1048 ``raw_input`` and similar operations that read from ``sys.stdin`` on the kernel
1003 1049 to be fulfilled by the client. The request should be made to the frontend that
1004 1050 made the execution request that prompted ``raw_input`` to be called. For now we
1005 1051 will keep these messages as simple as possible, since they only mean to convey
1006 1052 the ``raw_input(prompt)`` call.
1007 1053
1008 1054 Message type: ``input_request``::
1009 1055
1010 1056 content = {
1011 1057 # the text to show at the prompt
1012 1058 'prompt' : str,
1013 1059 # Is the request for a password?
1014 1060 # If so, the frontend shouldn't echo input.
1015 1061 'password' : bool
1016 1062 }
1017 1063
1018 1064 Message type: ``input_reply``::
1019 1065
1020 1066 content = { 'value' : str }
1021 1067
1022 1068
1023 1069 When ``password`` is True, the frontend should not echo the input as it is entered.
1024 1070
1025 1071 .. versionchanged:: 5.0
1026 1072
1027 1073 ``password`` key added.
1028 1074
1029 1075 .. note::
1030 1076
1031 1077 The stdin socket of the client is required to have the same zmq IDENTITY
1032 1078 as the client's shell socket.
1033 1079 Because of this, the ``input_request`` must be sent with the same IDENTITY
1034 1080 routing prefix as the ``execute_reply`` in order for the frontend to receive
1035 1081 the message.
1036 1082
1037 1083 .. note::
1038 1084
1039 1085 We do not explicitly try to forward the raw ``sys.stdin`` object, because in
1040 1086 practice the kernel should behave like an interactive program. When a
1041 1087 program is opened on the console, the keyboard effectively takes over the
1042 1088 ``stdin`` file descriptor, and it can't be used for raw reading anymore.
1043 1089 Since the IPython kernel effectively behaves like a console program (albeit
1044 1090 one whose "keyboard" is actually living in a separate process and
1045 1091 transported over the zmq connection), raw ``stdin`` isn't expected to be
1046 1092 available.
1047 1093
1048 1094 .. _kernel_heartbeat:
1049 1095
1050 1096 Heartbeat for kernels
1051 1097 =====================
1052 1098
1053 1099 Clients send ping messages on a REQ socket, which are echoed right back
1054 1100 from the Kernel's REP socket. These are simple bytestrings, not full JSON messages described above.
1055 1101
1056 1102
1057 1103 Custom Messages
1058 1104 ===============
1059 1105
1060 1106 .. versionadded:: 4.1
1061 1107
1062 1108 IPython 2.0 (msgspec v4.1) adds a messaging system for developers to add their own objects with Frontend
1063 1109 and Kernel-side components, and allow them to communicate with each other.
1064 1110 To do this, IPython adds a notion of a ``Comm``, which exists on both sides,
1065 1111 and can communicate in either direction.
1066 1112
1067 1113 These messages are fully symmetrical - both the Kernel and the Frontend can send each message,
1068 1114 and no messages expect a reply.
1069 1115 The Kernel listens for these messages on the Shell channel,
1070 1116 and the Frontend listens for them on the IOPub channel.
1071 1117
1072 1118 Opening a Comm
1073 1119 --------------
1074 1120
1075 1121 Opening a Comm produces a ``comm_open`` message, to be sent to the other side::
1076 1122
1077 1123 {
1078 1124 'comm_id' : 'u-u-i-d',
1079 1125 'target_name' : 'my_comm',
1080 1126 'data' : {}
1081 1127 }
1082 1128
1083 1129 Every Comm has an ID and a target name.
1084 1130 The code handling the message on the receiving side is responsible for maintaining a mapping
1085 1131 of target_name keys to constructors.
1086 1132 After a ``comm_open`` message has been sent,
1087 1133 there should be a corresponding Comm instance on both sides.
1088 1134 The ``data`` key is always a dict and can be any extra JSON information used in initialization of the comm.
1089 1135
1090 1136 If the ``target_name`` key is not found on the receiving side,
1091 1137 then it should immediately reply with a ``comm_close`` message to avoid an inconsistent state.
1092 1138
1093 1139 Comm Messages
1094 1140 -------------
1095 1141
1096 1142 Comm messages are one-way communications to update comm state,
1097 1143 used for synchronizing widget state, or simply requesting actions of a comm's counterpart.
1098 1144
1099 1145 Essentially, each comm pair defines their own message specification implemented inside the ``data`` dict.
1100 1146
1101 1147 There are no expected replies (of course, one side can send another ``comm_msg`` in reply).
1102 1148
1103 1149 Message type: ``comm_msg``::
1104 1150
1105 1151 {
1106 1152 'comm_id' : 'u-u-i-d',
1107 1153 'data' : {}
1108 1154 }
1109 1155
1110 1156 Tearing Down Comms
1111 1157 ------------------
1112 1158
1113 1159 Since comms live on both sides, when a comm is destroyed the other side must be notified.
1114 1160 This is done with a ``comm_close`` message.
1115 1161
1116 1162 Message type: ``comm_close``::
1117 1163
1118 1164 {
1119 1165 'comm_id' : 'u-u-i-d',
1120 1166 'data' : {}
1121 1167 }
1122 1168
1123 1169 Output Side Effects
1124 1170 -------------------
1125 1171
1126 1172 Since comm messages can execute arbitrary user code,
1127 1173 handlers should set the parent header and publish status busy / idle,
1128 1174 just like an execute request.
1129 1175
1130 1176
1131 1177 To Do
1132 1178 =====
1133 1179
1134 1180 Missing things include:
1135 1181
1136 1182 * Important: finish thinking through the payload concept and API.
1137 1183
1138 1184 .. include:: ../links.txt
General Comments 0
You need to be logged in to leave comments. Login now