##// END OF EJS Templates
Update messaging spec.
Fernando Perez -
Show More
@@ -1,580 +1,590 b''
1 1 .. _messaging:
2 2
3 3 ======================
4 4 Messaging in IPython
5 5 ======================
6 6
7 7
8 8 Introduction
9 9 ============
10 10
11 11 This document explains the basic communications design and messaging
12 12 specification for how the various IPython objects interact over a network
13 13 transport. The current implementation uses the ZeroMQ_ library for messaging
14 14 within and between hosts.
15 15
16 16 .. Note::
17 17
18 18 This document should be considered the authoritative description of the
19 19 IPython messaging protocol, and all developers are strongly encouraged to
20 20 keep it updated as the implementation evolves, so that we have a single
21 21 common reference for all protocol details.
22 22
23 23 The basic design is explained in the following diagram:
24 24
25 25 .. image:: frontend-kernel.png
26 26 :width: 450px
27 27 :alt: IPython kernel/frontend messaging architecture.
28 28 :align: center
29 29 :target: ../_images/frontend-kernel.png
30 30
31 31 A single kernel can be simultaneously connected to one or more frontends. The
32 32 kernel has three sockets that serve the following functions:
33 33
34 34 1. REQ: this socket is connected to a *single* frontend at a time, and it allows
35 35 the kernel to request input from a frontend when :func:`raw_input` is called.
36 36 The frontend holding the matching REP socket acts as a 'virtual keyboard'
37 37 for the kernel while this communication is happening (illustrated in the
38 38 figure by the black outline around the central keyboard). In practice,
39 39 frontends may display such kernel requests using a special input widget or
40 40 otherwise indicating that the user is to type input for the kernel instead
41 41 of normal commands in the frontend.
42 42
43 43 2. XREP: this single sockets allows multiple incoming connections from
44 44 frontends, and this is the socket where requests for code execution, object
45 45 information, prompts, etc. are made to the kernel by any frontend. The
46 46 communication on this socket is a sequence of request/reply actions from
47 47 each frontend and the kernel.
48 48
49 49 3. PUB: this socket is the 'broadcast channel' where the kernel publishes all
50 50 side effects (stdout, stderr, etc.) as well as the requests coming from any
51 51 client over the XREP socket and its own requests on the REP socket. There
52 52 are a number of actions in Python which generate side effects: :func:`print`
53 53 writes to ``sys.stdout``, errors generate tracebacks, etc. Additionally, in
54 54 a multi-client scenario, we want all frontends to be able to know what each
55 55 other has sent to the kernel (this can be useful in collaborative scenarios,
56 56 for example). This socket allows both side effects and the information
57 57 about communications taking place with one client over the XREQ/XREP channel
58 58 to be made available to all clients in a uniform manner.
59 59
60 60 All messages are tagged with enough information (details below) for clients
61 61 to know which messages come from their own interaction with the kernel and
62 62 which ones are from other clients, so they can display each type
63 63 appropriately.
64 64
65 65 The actual format of the messages allowed on each of these channels is
66 66 specified below. Messages are dicts of dicts with string keys and values that
67 67 are reasonably representable in JSON. Our current implementation uses JSON
68 68 explicitly as its message format, but this shouldn't be considered a permanent
69 69 feature. As we've discovered that JSON has non-trivial performance issues due
70 70 to excessive copying, we may in the future move to a pure pickle-based raw
71 71 message format. However, it should be possible to easily convert from the raw
72 72 objects to JSON, since we may have non-python clients (e.g. a web frontend).
73 73 As long as it's easy to make a JSON version of the objects that is a faithful
74 74 representation of all the data, we can communicate with such clients.
75 75
76 76 .. Note::
77 77
78 78 Not all of these have yet been fully fleshed out, but the key ones are, see
79 79 kernel and frontend files for actual implementation details.
80 80
81 81
82 82 Python functional API
83 83 =====================
84 84
85 85 As messages are dicts, they map naturally to a ``func(**kw)`` call form. We
86 86 should develop, at a few key points, functional forms of all the requests that
87 87 take arguments in this manner and automatically construct the necessary dict
88 88 for sending.
89 89
90 90
91 91 General Message Format
92 92 ======================
93 93
94 94 All messages send or received by any IPython process should have the following
95 95 generic structure::
96 96
97 97 {
98 98 # The message header contains a pair of unique identifiers for the
99 99 # originating session and the actual message id, in addition to the
100 100 # username for the process that generated the message. This is useful in
101 101 # collaborative settings where multiple users may be interacting with the
102 102 # same kernel simultaneously, so that frontends can label the various
103 103 # messages in a meaningful way.
104 104 'header' : { 'msg_id' : uuid,
105 105 'username' : str,
106 106 'session' : uuid
107 107 },
108 108
109 109 # In a chain of messages, the header from the parent is copied so that
110 110 # clients can track where messages come from.
111 111 'parent_header' : dict,
112 112
113 113 # All recognized message type strings are listed below.
114 114 'msg_type' : str,
115 115
116 116 # The actual content of the message must be a dict, whose structure
117 117 # depends on the message type.x
118 118 'content' : dict,
119 119 }
120 120
121 121 For each message type, the actual content will differ and all existing message
122 122 types are specified in what follows of this document.
123 123
124 124
125 125 Messages on the XREP/XREQ socket
126 126 ================================
127 127
128 128 .. _execute:
129 129
130 130 Execute
131 131 -------
132 132
133 133 The execution request contains a single string, but this may be a multiline
134 134 string. The kernel is responsible for splitting this into possibly more than
135 135 one block and deciding whether to compile these in 'single' or 'exec' mode.
136 136 We're still sorting out this policy. The current inputsplitter is capable of
137 137 splitting the input for blocks that can all be run as 'single', but in the long
138 138 run it may prove cleaner to only use 'single' mode for truly single-line
139 139 inputs, and run all multiline input in 'exec' mode. This would preserve the
140 140 natural behavior of single-line inputs while allowing long cells to behave more
141 141 likea a script. This design will be refined as we complete the implementation.
142 142
143 143 Message type: ``execute_request``::
144 144
145 145 content = {
146 146 # Source code to be executed by the kernel, one or more lines.
147 147 'code' : str,
148 148
149 149 # A boolean flag which, if True, signals the kernel to execute this
150 150 # code as quietly as possible. This means that the kernel will compile
151 151 # the code with 'exec' instead of 'single' (so sys.displayhook will not
152 152 # fire), and will *not*:
153 153 # - broadcast exceptions on the PUB socket
154 154 # - do any logging
155 155 # - populate any history
156 156 # The default is False.
157 157 'silent' : bool,
158 158 }
159 159
160 160 Upon execution, the kernel *always* sends a reply, with a status code
161 161 indicating what happened and additional data depending on the outcome.
162 162
163 163 Message type: ``execute_reply``::
164 164
165 165 content = {
166 166 # One of: 'ok' OR 'error' OR 'abort'
167 167 'status' : str,
168 168
169 169 # This has the same structure as the output of a prompt request, but is
170 170 # for the client to set up the *next* prompt (with identical limitations
171 171 # to a prompt request)
172 172 'next_prompt' : {
173 173 'prompt_string' : str,
174 174 'prompt_number' : int,
175 175 'input_sep' : str
176 176 },
177 177
178 178 # The prompt number of the actual execution for this code, which may be
179 179 # different from the one used when the code was typed, which was the
180 180 # 'next_prompt' field of the *previous* request. They will differ in the
181 181 # case where there is more than one client talking simultaneously to a
182 182 # kernel, since the numbers can go out of sync. GUI clients can use this
183 183 # to correct the previously written number in-place, terminal ones may
184 184 # re-print a corrected one if desired.
185 185 'prompt_number' : int,
186 186 }
187 187
188 188 When status is 'ok', the following extra fields are present::
189 189
190 190 {
191 191 # The kernel will often transform the input provided to it. This
192 192 # contains the transformed code, which is what was actually executed.
193 193 'transformed_code' : str,
194 194
195 195 # The execution payload is a dict with string keys that may have been
196 196 # produced by the code being executed. It is retrieved by the kernel at
197 197 # the end of the execution and sent back to the front end, which can take
198 198 # action on it as needed. See main text for further details.
199 199 'payload' : dict,
200 200 }
201 201
202 202 .. admonition:: Execution payloads
203 203
204 204 The notion of an 'execution payload' is different from a return value of a
205 205 given set of code, which normally is just displayed on the pyout stream
206 206 through the PUB socket. The idea of a payload is to allow special types of
207 207 code, typically magics, to populate a data container in the IPython kernel
208 208 that will be shipped back to the caller via this channel. The kernel will
209 209 have an API for this, probably something along the lines of::
210 210
211 211 ip.exec_payload_add(key, value)
212 212
213 213 though this API is still in the design stages. The data returned in this
214 214 payload will allow frontends to present special views of what just happened.
215 215
216 216
217 217 When status is 'error', the following extra fields are present::
218 218
219 219 {
220 220 'exc_name' : str, # Exception name, as a string
221 221 'exc_value' : str, # Exception value, as a string
222 222
223 223 # The traceback will contain a list of frames, represented each as a
224 224 # string. For now we'll stick to the existing design of ultraTB, which
225 225 # controls exception level of detail statefully. But eventually we'll
226 226 # want to grow into a model where more information is collected and
227 227 # packed into the traceback object, with clients deciding how little or
228 228 # how much of it to unpack. But for now, let's start with a simple list
229 229 # of strings, since that requires only minimal changes to ultratb as
230 230 # written.
231 231 'traceback' : list,
232 232 }
233 233
234 234
235 235 When status is 'abort', there are for now no additional data fields. This
236 236 happens when the kernel was interrupted by a signal.
237 237
238 238
239 239 Prompt
240 240 ------
241 241
242 242 A simple request for a current prompt string.
243 243
244 244 Message type: ``prompt_request``::
245 245
246 246 content = {}
247 247
248 248 In the reply, the prompt string comes back with the prompt number placeholder
249 249 *unevaluated*. The message format is:
250 250
251 251 Message type: ``prompt_reply``::
252 252
253 253 content = {
254 254 'prompt_string' : str,
255 255 'prompt_number' : int,
256 256 }
257 257
258 258 Clients can produce a prompt with ``prompt_string.format(prompt_number)``, but
259 259 they should be aware that the actual prompt number for that input could change
260 260 later, in the case where multiple clients are interacting with a single
261 261 kernel.
262 262
263 263
264 264 Object information
265 265 ------------------
266 266
267 267 One of IPython's most used capabilities is the introspection of Python objects
268 268 in the user's namespace, typically invoked via the ``?`` and ``??`` characters
269 269 (which in reality are shorthands for the ``%pinfo`` magic). This is used often
270 270 enough that it warrants an explicit message type, especially because frontends
271 271 may want to get object information in response to user keystrokes (like Tab or
272 272 F1) besides from the user explicitly typing code like ``x??``.
273 273
274 274 Message type: ``object_info_request``::
275 275
276 276 content = {
277 277 # The (possibly dotted) name of the object to be searched in all
278 278 # relevant namespaces
279 279 'name' : str,
280 280
281 281 # The level of detail desired. The default (0) is equivalent to typing
282 282 # 'x?' at the prompt, 1 is equivalent to 'x??'.
283 283 'detail_level' : int,
284 284 }
285 285
286 286 The returned information will be a dictionary with keys very similar to the
287 287 field names that IPython prints at the terminal.
288 288
289 289 Message type: ``object_info_reply``::
290 290
291 291 content = {
292 292 # Flags for magics and system aliases
293 293 'ismagic' : bool,
294 294 'isalias' : bool,
295 295
296 296 # The name of the namespace where the object was found ('builtin',
297 297 # 'magics', 'alias', 'interactive', etc.)
298 298 'namespace' : str,
299 299
300 300 # The type name will be type.__name__ for normal Python objects, but it
301 301 # can also be a string like 'Magic function' or 'System alias'
302 302 'type_name' : str,
303 303
304 304 'string_form' : str,
305 305
306 306 # For objects with a __class__ attribute this will be set
307 307 'base_class' : str,
308 308
309 309 # For objects with a __len__ attribute this will be set
310 310 'length' : int,
311 311
312 312 # If the object is a function, class or method whose file we can find,
313 313 # we give its full path
314 314 'file' : str,
315 315
316 316 # For pure Python callable objects, we can reconstruct the object
317 317 # definition line which provides its call signature
318 318 'definition' : str,
319 319
320 320 # For instances, provide the constructor signature (the definition of
321 321 # the __init__ method):
322 322 'init_definition' : str,
323 323
324 324 # Docstrings: for any object (function, method, module, package) with a
325 325 # docstring, we show it. But in addition, we may provide additional
326 326 # docstrings. For example, for instances we will show the constructor
327 327 # and class docstrings as well, if available.
328 328 'docstring' : str,
329 329
330 330 # For instances, provide the constructor and class docstrings
331 331 'init_docstring' : str,
332 332 'class_docstring' : str,
333 333
334 334 # If detail_level was 1, we also try to find the source code that
335 335 # defines the object, if possible. The string 'None' will indicate
336 336 # that no source was found.
337 337 'source' : str,
338 338 }
339 339
340 340
341 341 Complete
342 342 --------
343 343
344 344 Message type: ``complete_request``::
345 345
346 346 content = {
347 347 # The text to be completed, such as 'a.is'
348 348 'text' : str,
349 349
350 350 # The full line, such as 'print a.is'. This allows completers to
351 351 # make decisions that may require information about more than just the
352 352 # current word.
353 353 'line' : str,
354
355 # The entire block of text where the line is. This may be useful in the
356 # case of multiline completions where more context may be needed. Note: if
357 # in practice this field proves unnecessary, remove it to lighten the
358 # messages.
359
360 'block' : str,
361
362 # The position of the cursor where the user hit 'TAB' on the line.
363 'cursor_pos' : int,
354 364 }
355 365
356 366 Message type: ``complete_reply``::
357 367
358 368 content = {
359 369 # The list of all matches to the completion request, such as
360 370 # ['a.isalnum', 'a.isalpha'] for the above example.
361 371 'matches' : list
362 372 }
363 373
364 374
365 375 History
366 376 -------
367 377
368 378 For clients to explicitly request history from a kernel. The kernel has all
369 379 the actual execution history stored in a single location, so clients can
370 380 request it from the kernel when needed.
371 381
372 382 Message type: ``history_request``::
373 383
374 384 content = {
375 385
376 386 # If True, also return output history in the resulting dict.
377 387 'output' : bool,
378 388
379 389 # If True, return the raw input history, else the transformed input.
380 390 'raw' : bool,
381 391
382 392 # This parameter can be one of: A number, a pair of numbers, None
383 393 # If not given, last 40 are returned.
384 394 # - number n: return the last n entries.
385 395 # - pair n1, n2: return entries in the range(n1, n2).
386 396 # - None: return all history
387 397 'range' : n or (n1, n2) or None,
388 398
389 399 # If a filter is given, it is treated as a regular expression and only
390 400 # matching entries are returned. re.search() is used to find matches.
391 401 'filter' : str,
392 402 }
393 403
394 404 Message type: ``history_reply``::
395 405
396 406 content = {
397 407 # A dict with prompt numbers as keys and either (input, output) or input
398 408 # as the value depending on whether output was True or False,
399 409 # respectively.
400 410 'history' : dict,
401 411 }
402 412 Messages on the PUB/SUB socket
403 413 ==============================
404 414
405 415 Streams (stdout, stderr, etc)
406 416 ------------------------------
407 417
408 418 Message type: ``stream``::
409 419
410 420 content = {
411 421 # The name of the stream is one of 'stdin', 'stdout', 'stderr'
412 422 'name' : str,
413 423
414 424 # The data is an arbitrary string to be written to that stream
415 425 'data' : str,
416 426 }
417 427
418 428 When a kernel receives a raw_input call, it should also broadcast it on the pub
419 429 socket with the names 'stdin' and 'stdin_reply'. This will allow other clients
420 430 to monitor/display kernel interactions and possibly replay them to their user
421 431 or otherwise expose them.
422 432
423 433 Python inputs
424 434 -------------
425 435
426 436 These messages are the re-broadcast of the ``execute_request``.
427 437
428 438 Message type: ``pyin``::
429 439
430 440 content = {
431 441 # Source code to be executed, one or more lines
432 442 'code' : str
433 443 }
434 444
435 445 Python outputs
436 446 --------------
437 447
438 448 When Python produces output from code that has been compiled in with the
439 449 'single' flag to :func:`compile`, any expression that produces a value (such as
440 450 ``1+1``) is passed to ``sys.displayhook``, which is a callable that can do with
441 451 this value whatever it wants. The default behavior of ``sys.displayhook`` in
442 452 the Python interactive prompt is to print to ``sys.stdout`` the :func:`repr` of
443 453 the value as long as it is not ``None`` (which isn't printed at all). In our
444 454 case, the kernel instantiates as ``sys.displayhook`` an object which has
445 455 similar behavior, but which instead of printing to stdout, broadcasts these
446 456 values as ``pyout`` messages for clients to display appropriately.
447 457
448 458 Message type: ``pyout``::
449 459
450 460 content = {
451 461 # The data is typically the repr() of the object.
452 462 'data' : str,
453 463
454 464 # The prompt number for this execution is also provided so that clients
455 465 # can display it, since IPython automatically creates variables called
456 466 # _N (for prompt N).
457 467 'prompt_number' : int,
458 468 }
459 469
460 470 Python errors
461 471 -------------
462 472
463 473 When an error occurs during code execution
464 474
465 475 Message type: ``pyerr``::
466 476
467 477 content = {
468 478 # Similar content to the execute_reply messages for the 'error' case,
469 479 # except the 'status' field is omitted.
470 480 }
471 481
472 482 Kernel crashes
473 483 --------------
474 484
475 485 When the kernel has an unexpected exception, caught by the last-resort
476 486 sys.excepthook, we should broadcast the crash handler's output before exiting.
477 487 This will allow clients to notice that a kernel died, inform the user and
478 488 propose further actions.
479 489
480 490 Message type: ``crash``::
481 491
482 492 content = {
483 493 # Similarly to the 'error' case for execute_reply messages, this will
484 494 # contain exc_name, exc_type and traceback fields.
485 495
486 496 # An additional field with supplementary information such as where to
487 497 # send the crash message
488 498 'info' : str,
489 499 }
490 500
491 501
492 502 Future ideas
493 503 ------------
494 504
495 505 Other potential message types, currently unimplemented, listed below as ideas.
496 506
497 507 Message type: ``file``::
498 508
499 509 content = {
500 510 'path' : 'cool.jpg',
501 511 'mimetype' : str,
502 512 'data' : str,
503 513 }
504 514
505 515
506 516 Messages on the REQ/REP socket
507 517 ==============================
508 518
509 519 This is a socket that goes in the opposite direction: from the kernel to a
510 520 *single* frontend, and its purpose is to allow ``raw_input`` and similar
511 521 operations that read from ``sys.stdin`` on the kernel to be fulfilled by the
512 522 client. For now we will keep these messages as simple as possible, since they
513 523 basically only mean to convey the ``raw_input(prompt)`` call.
514 524
515 525 Message type: ``input_request``::
516 526
517 527 content = { 'prompt' : str }
518 528
519 529 Message type: ``input_reply``::
520 530
521 531 content = { 'value' : str }
522 532
523 533 .. Note::
524 534
525 535 We do not explicitly try to forward the raw ``sys.stdin`` object, because in
526 536 practice the kernel should behave like an interactive program. When a
527 537 program is opened on the console, the keyboard effectively takes over the
528 538 ``stdin`` file descriptor, and it can't be used for raw reading anymore.
529 539 Since the IPython kernel effectively behaves like a console program (albeit
530 540 one whose "keyboard" is actually living in a separate process and
531 541 transported over the zmq connection), raw ``stdin`` isn't expected to be
532 542 available.
533 543
534 544
535 545 Heartbeat for kernels
536 546 =====================
537 547
538 548 Initially we had considered using messages like those above over ZMQ for a
539 549 kernel 'heartbeat' (a way to detect quickly and reliably whether a kernel is
540 550 alive at all, even if it may be busy executing user code). But this has the
541 551 problem that if the kernel is locked inside extension code, it wouldn't execute
542 552 the python heartbeat code. But it turns out that we can implement a basic
543 553 heartbeat with pure ZMQ, without using any Python messaging at all.
544 554
545 555 The monitor sends out a single zmq message (right now, it is a str of the
546 556 monitor's lifetime in seconds), and gets the same message right back, prefixed
547 557 with the zmq identity of the XREQ socket in the heartbeat process. This can be
548 558 a uuid, or even a full message, but there doesn't seem to be a need for packing
549 559 up a message when the sender and receiver are the exact same Python object.
550 560
551 561 The model is this::
552 562
553 563 monitor.send(str(self.lifetime)) # '1.2345678910'
554 564
555 565 and the monitor receives some number of messages of the form::
556 566
557 567 ['uuid-abcd-dead-beef', '1.2345678910']
558 568
559 569 where the first part is the zmq.IDENTITY of the heart's XREQ on the engine, and
560 570 the rest is the message sent by the monitor. No Python code ever has any
561 571 access to the message between the monitor's send, and the monitor's recv.
562 572
563 573
564 574 ToDo
565 575 ====
566 576
567 577 Missing things include:
568 578
569 579 * Important: finish thinking through the payload concept and API.
570 580
571 581 * Important: ensure that we have a good solution for magics like %edit. It's
572 582 likely that with the payload concept we can build a full solution, but not
573 583 100% clear yet.
574 584
575 585 * Finishing the details of the heartbeat protocol.
576 586
577 587 * Signal handling: specify what kind of information kernel should broadcast (or
578 588 not) when it receives signals.
579 589
580 590 .. include:: ../links.rst
General Comments 0
You need to be logged in to leave comments. Login now