##// END OF EJS Templates
Merge pull request #4979 from minrk/clear-output-msgspec...
Thomas Kluyver -
r15001:cf7b62ae merge
parent child Browse files
Show More
@@ -1,148 +1,148 b''
1 1 # -*- coding: utf-8 -*-
2 2 """Release data for the IPython project."""
3 3
4 4 #-----------------------------------------------------------------------------
5 5 # Copyright (c) 2008, IPython Development Team.
6 6 # Copyright (c) 2001, Fernando Perez <fernando.perez@colorado.edu>
7 7 # Copyright (c) 2001, Janko Hauser <jhauser@zscout.de>
8 8 # Copyright (c) 2001, Nathaniel Gray <n8gray@caltech.edu>
9 9 #
10 10 # Distributed under the terms of the Modified BSD License.
11 11 #
12 12 # The full license is in the file COPYING.txt, distributed with this software.
13 13 #-----------------------------------------------------------------------------
14 14
15 15 # Name of the package for release purposes. This is the name which labels
16 16 # the tarballs and RPMs made by distutils, so it's best to lowercase it.
17 17 name = 'ipython'
18 18
19 19 # IPython version information. An empty _version_extra corresponds to a full
20 20 # release. 'dev' as a _version_extra string means this is a development
21 21 # version
22 22 _version_major = 2
23 23 _version_minor = 0
24 24 _version_patch = 0
25 25 _version_extra = 'dev'
26 26 # _version_extra = 'rc1'
27 27 # _version_extra = '' # Uncomment this for full releases
28 28
29 29 codename = 'Work in Progress'
30 30
31 31 # Construct full version string from these.
32 32 _ver = [_version_major, _version_minor, _version_patch]
33 33
34 34 __version__ = '.'.join(map(str, _ver))
35 35 if _version_extra:
36 36 __version__ = __version__ + '-' + _version_extra
37 37
38 38 version = __version__ # backwards compatibility name
39 39 version_info = (_version_major, _version_minor, _version_patch, _version_extra)
40 40
41 41 # Change this when incrementing the kernel protocol version
42 kernel_protocol_version_info = (4, 0)
42 kernel_protocol_version_info = (4, 1)
43 43
44 44 description = "IPython: Productive Interactive Computing"
45 45
46 46 long_description = \
47 47 """
48 48 IPython provides a rich toolkit to help you make the most out of using Python
49 49 interactively. Its main components are:
50 50
51 51 * Powerful interactive Python shells (terminal- and Qt-based).
52 52 * A web-based interactive notebook environment with all shell features plus
53 53 support for embedded figures, animations and rich media.
54 54 * Support for interactive data visualization and use of GUI toolkits.
55 55 * Flexible, embeddable interpreters to load into your own projects.
56 56 * A high-performance library for high level and interactive parallel computing
57 57 that works in multicore systems, clusters, supercomputing and cloud scenarios.
58 58
59 59 The enhanced interactive Python shells have the following main features:
60 60
61 61 * Comprehensive object introspection.
62 62
63 63 * Input history, persistent across sessions.
64 64
65 65 * Caching of output results during a session with automatically generated
66 66 references.
67 67
68 68 * Extensible tab completion, with support by default for completion of python
69 69 variables and keywords, filenames and function keywords.
70 70
71 71 * Extensible system of 'magic' commands for controlling the environment and
72 72 performing many tasks related either to IPython or the operating system.
73 73
74 74 * A rich configuration system with easy switching between different setups
75 75 (simpler than changing $PYTHONSTARTUP environment variables every time).
76 76
77 77 * Session logging and reloading.
78 78
79 79 * Extensible syntax processing for special purpose situations.
80 80
81 81 * Access to the system shell with user-extensible alias system.
82 82
83 83 * Easily embeddable in other Python programs and GUIs.
84 84
85 85 * Integrated access to the pdb debugger and the Python profiler.
86 86
87 87 The parallel computing architecture has the following main features:
88 88
89 89 * Quickly parallelize Python code from an interactive Python/IPython session.
90 90
91 91 * A flexible and dynamic process model that be deployed on anything from
92 92 multicore workstations to supercomputers.
93 93
94 94 * An architecture that supports many different styles of parallelism, from
95 95 message passing to task farming.
96 96
97 97 * Both blocking and fully asynchronous interfaces.
98 98
99 99 * High level APIs that enable many things to be parallelized in a few lines
100 100 of code.
101 101
102 102 * Share live parallel jobs with other users securely.
103 103
104 104 * Dynamically load balanced task farming system.
105 105
106 106 * Robust error handling in parallel code.
107 107
108 108 The latest development version is always available from IPython's `GitHub
109 109 site <http://github.com/ipython>`_.
110 110 """
111 111
112 112 license = 'BSD'
113 113
114 114 authors = {'Fernando' : ('Fernando Perez','fperez.net@gmail.com'),
115 115 'Janko' : ('Janko Hauser','jhauser@zscout.de'),
116 116 'Nathan' : ('Nathaniel Gray','n8gray@caltech.edu'),
117 117 'Ville' : ('Ville Vainio','vivainio@gmail.com'),
118 118 'Brian' : ('Brian E Granger', 'ellisonbg@gmail.com'),
119 119 'Min' : ('Min Ragan-Kelley', 'benjaminrk@gmail.com'),
120 120 'Thomas' : ('Thomas A. Kluyver', 'takowl@gmail.com'),
121 121 'Jorgen' : ('Jorgen Stenarson', 'jorgen.stenarson@bostream.nu'),
122 122 'Matthias' : ('Matthias Bussonnier', 'bussonniermatthias@gmail.com'),
123 123 }
124 124
125 125 author = 'The IPython Development Team'
126 126
127 127 author_email = 'ipython-dev@scipy.org'
128 128
129 129 url = 'http://ipython.org'
130 130
131 131 download_url = 'https://github.com/ipython/ipython/downloads'
132 132
133 133 platforms = ['Linux','Mac OSX','Windows XP/Vista/7/8']
134 134
135 135 keywords = ['Interactive','Interpreter','Shell','Parallel','Distributed',
136 136 'Web-based computing', 'Qt console', 'Embedding']
137 137
138 138 classifiers = [
139 139 'Intended Audience :: Developers',
140 140 'Intended Audience :: Science/Research',
141 141 'License :: OSI Approved :: BSD License',
142 142 'Programming Language :: Python',
143 143 'Programming Language :: Python :: 2',
144 144 'Programming Language :: Python :: 2.7',
145 145 'Programming Language :: Python :: 3',
146 146 'Topic :: System :: Distributed Computing',
147 147 'Topic :: System :: Shells'
148 148 ]
@@ -1,822 +1,827 b''
1 1 //----------------------------------------------------------------------------
2 2 // Copyright (C) 2008 The IPython Development Team
3 3 //
4 4 // Distributed under the terms of the BSD License. The full license is in
5 5 // the file COPYING, distributed as part of this software.
6 6 //----------------------------------------------------------------------------
7 7
8 8 //============================================================================
9 9 // OutputArea
10 10 //============================================================================
11 11
12 12 /**
13 13 * @module IPython
14 14 * @namespace IPython
15 15 * @submodule OutputArea
16 16 */
17 17 var IPython = (function (IPython) {
18 18 "use strict";
19 19
20 20 var utils = IPython.utils;
21 21
22 22 /**
23 23 * @class OutputArea
24 24 *
25 25 * @constructor
26 26 */
27 27
28 28 var OutputArea = function (selector, prompt_area) {
29 29 this.selector = selector;
30 30 this.wrapper = $(selector);
31 31 this.outputs = [];
32 32 this.collapsed = false;
33 33 this.scrolled = false;
34 34 this.trusted = true;
35 35 this.clear_queued = null;
36 36 if (prompt_area === undefined) {
37 37 this.prompt_area = true;
38 38 } else {
39 39 this.prompt_area = prompt_area;
40 40 }
41 41 this.create_elements();
42 42 this.style();
43 43 this.bind_events();
44 44 };
45 45
46 46 OutputArea.prototype.create_elements = function () {
47 47 this.element = $("<div/>");
48 48 this.collapse_button = $("<div/>");
49 49 this.prompt_overlay = $("<div/>");
50 50 this.wrapper.append(this.prompt_overlay);
51 51 this.wrapper.append(this.element);
52 52 this.wrapper.append(this.collapse_button);
53 53 };
54 54
55 55
56 56 OutputArea.prototype.style = function () {
57 57 this.collapse_button.hide();
58 58 this.prompt_overlay.hide();
59 59
60 60 this.wrapper.addClass('output_wrapper');
61 61 this.element.addClass('output');
62 62
63 63 this.collapse_button.addClass("btn output_collapsed");
64 64 this.collapse_button.attr('title', 'click to expand output');
65 65 this.collapse_button.text('. . .');
66 66
67 67 this.prompt_overlay.addClass('out_prompt_overlay prompt');
68 68 this.prompt_overlay.attr('title', 'click to expand output; double click to hide output');
69 69
70 70 this.collapse();
71 71 };
72 72
73 73 /**
74 74 * Should the OutputArea scroll?
75 75 * Returns whether the height (in lines) exceeds a threshold.
76 76 *
77 77 * @private
78 78 * @method _should_scroll
79 79 * @param [lines=100]{Integer}
80 80 * @return {Bool}
81 81 *
82 82 */
83 83 OutputArea.prototype._should_scroll = function (lines) {
84 84 if (lines <=0 ){ return }
85 85 if (!lines) {
86 86 lines = 100;
87 87 }
88 88 // line-height from http://stackoverflow.com/questions/1185151
89 89 var fontSize = this.element.css('font-size');
90 90 var lineHeight = Math.floor(parseInt(fontSize.replace('px','')) * 1.5);
91 91
92 92 return (this.element.height() > lines * lineHeight);
93 93 };
94 94
95 95
96 96 OutputArea.prototype.bind_events = function () {
97 97 var that = this;
98 98 this.prompt_overlay.dblclick(function () { that.toggle_output(); });
99 99 this.prompt_overlay.click(function () { that.toggle_scroll(); });
100 100
101 101 this.element.resize(function () {
102 102 // FIXME: Firefox on Linux misbehaves, so automatic scrolling is disabled
103 103 if ( IPython.utils.browser[0] === "Firefox" ) {
104 104 return;
105 105 }
106 106 // maybe scroll output,
107 107 // if it's grown large enough and hasn't already been scrolled.
108 108 if ( !that.scrolled && that._should_scroll(OutputArea.auto_scroll_threshold)) {
109 109 that.scroll_area();
110 110 }
111 111 });
112 112 this.collapse_button.click(function () {
113 113 that.expand();
114 114 });
115 115 };
116 116
117 117
118 118 OutputArea.prototype.collapse = function () {
119 119 if (!this.collapsed) {
120 120 this.element.hide();
121 121 this.prompt_overlay.hide();
122 122 if (this.element.html()){
123 123 this.collapse_button.show();
124 124 }
125 125 this.collapsed = true;
126 126 }
127 127 };
128 128
129 129
130 130 OutputArea.prototype.expand = function () {
131 131 if (this.collapsed) {
132 132 this.collapse_button.hide();
133 133 this.element.show();
134 134 this.prompt_overlay.show();
135 135 this.collapsed = false;
136 136 }
137 137 };
138 138
139 139
140 140 OutputArea.prototype.toggle_output = function () {
141 141 if (this.collapsed) {
142 142 this.expand();
143 143 } else {
144 144 this.collapse();
145 145 }
146 146 };
147 147
148 148
149 149 OutputArea.prototype.scroll_area = function () {
150 150 this.element.addClass('output_scroll');
151 151 this.prompt_overlay.attr('title', 'click to unscroll output; double click to hide');
152 152 this.scrolled = true;
153 153 };
154 154
155 155
156 156 OutputArea.prototype.unscroll_area = function () {
157 157 this.element.removeClass('output_scroll');
158 158 this.prompt_overlay.attr('title', 'click to scroll output; double click to hide');
159 159 this.scrolled = false;
160 160 };
161 161
162 162 /**
163 163 * Threshold to trigger autoscroll when the OutputArea is resized,
164 164 * typically when new outputs are added.
165 165 *
166 166 * Behavior is undefined if autoscroll is lower than minimum_scroll_threshold,
167 167 * unless it is < 0, in which case autoscroll will never be triggered
168 168 *
169 169 * @property auto_scroll_threshold
170 170 * @type Number
171 171 * @default 100
172 172 *
173 173 **/
174 174 OutputArea.auto_scroll_threshold = 100;
175 175
176 176
177 177 /**
178 178 * Lower limit (in lines) for OutputArea to be made scrollable. OutputAreas
179 179 * shorter than this are never scrolled.
180 180 *
181 181 * @property minimum_scroll_threshold
182 182 * @type Number
183 183 * @default 20
184 184 *
185 185 **/
186 186 OutputArea.minimum_scroll_threshold = 20;
187 187
188 188
189 189 /**
190 190 *
191 191 * Scroll OutputArea if height supperior than a threshold (in lines).
192 192 *
193 193 * Threshold is a maximum number of lines. If unspecified, defaults to
194 194 * OutputArea.minimum_scroll_threshold.
195 195 *
196 196 * Negative threshold will prevent the OutputArea from ever scrolling.
197 197 *
198 198 * @method scroll_if_long
199 199 *
200 200 * @param [lines=20]{Number} Default to 20 if not set,
201 201 * behavior undefined for value of `0`.
202 202 *
203 203 **/
204 204 OutputArea.prototype.scroll_if_long = function (lines) {
205 205 var n = lines | OutputArea.minimum_scroll_threshold;
206 206 if(n <= 0){
207 207 return
208 208 }
209 209
210 210 if (this._should_scroll(n)) {
211 211 // only allow scrolling long-enough output
212 212 this.scroll_area();
213 213 }
214 214 };
215 215
216 216
217 217 OutputArea.prototype.toggle_scroll = function () {
218 218 if (this.scrolled) {
219 219 this.unscroll_area();
220 220 } else {
221 221 // only allow scrolling long-enough output
222 222 this.scroll_if_long();
223 223 }
224 224 };
225 225
226 226
227 227 // typeset with MathJax if MathJax is available
228 228 OutputArea.prototype.typeset = function () {
229 229 if (window.MathJax){
230 230 MathJax.Hub.Queue(["Typeset",MathJax.Hub]);
231 231 }
232 232 };
233 233
234 234
235 235 OutputArea.prototype.handle_output = function (msg) {
236 236 var json = {};
237 237 var msg_type = json.output_type = msg.header.msg_type;
238 238 var content = msg.content;
239 239 if (msg_type === "stream") {
240 240 json.text = content.data;
241 241 json.stream = content.name;
242 242 } else if (msg_type === "display_data") {
243 243 json = content.data;
244 244 json.output_type = msg_type;
245 245 json.metadata = content.metadata;
246 246 } else if (msg_type === "pyout") {
247 247 json = content.data;
248 248 json.output_type = msg_type;
249 249 json.metadata = content.metadata;
250 250 json.prompt_number = content.execution_count;
251 251 } else if (msg_type === "pyerr") {
252 252 json.ename = content.ename;
253 253 json.evalue = content.evalue;
254 254 json.traceback = content.traceback;
255 255 }
256 256 this.append_output(json);
257 257 };
258 258
259 259 OutputArea.mime_map = {
260 260 "text/plain" : "text",
261 261 "text/html" : "html",
262 262 "image/svg+xml" : "svg",
263 263 "image/png" : "png",
264 264 "image/jpeg" : "jpeg",
265 265 "text/latex" : "latex",
266 266 "application/json" : "json",
267 267 "application/javascript" : "javascript",
268 268 };
269 269
270 270 OutputArea.mime_map_r = {
271 271 "text" : "text/plain",
272 272 "html" : "text/html",
273 273 "svg" : "image/svg+xml",
274 274 "png" : "image/png",
275 275 "jpeg" : "image/jpeg",
276 276 "latex" : "text/latex",
277 277 "json" : "application/json",
278 278 "javascript" : "application/javascript",
279 279 };
280 280
281 281 OutputArea.prototype.rename_keys = function (data, key_map) {
282 282 var remapped = {};
283 283 for (var key in data) {
284 284 var new_key = key_map[key] || key;
285 285 remapped[new_key] = data[key];
286 286 }
287 287 return remapped;
288 288 };
289 289
290 290
291 291 OutputArea.output_types = [
292 292 'application/javascript',
293 293 'text/html',
294 294 'text/latex',
295 295 'image/svg+xml',
296 296 'image/png',
297 297 'image/jpeg',
298 298 'text/plain'
299 299 ];
300 300
301 301 OutputArea.prototype.validate_output = function (json) {
302 302 // scrub invalid outputs
303 303 // TODO: right now everything is a string, but JSON really shouldn't be.
304 304 // nbformat 4 will fix that.
305 305 $.map(OutputArea.output_types, function(key){
306 306 if (json[key] !== undefined && typeof json[key] !== 'string') {
307 307 console.log("Invalid type for " + key, json[key]);
308 308 delete json[key];
309 309 }
310 310 });
311 311 return json;
312 312 };
313 313
314 314 OutputArea.prototype.append_output = function (json) {
315 315 this.expand();
316 316 // Clear the output if clear is queued.
317 317 var needs_height_reset = false;
318 318 if (this.clear_queued) {
319 319 this.clear_output(false);
320 320 needs_height_reset = true;
321 321 }
322 322
323 323 // validate output data types
324 324 json = this.validate_output(json);
325 325
326 326 if (json.output_type === 'pyout') {
327 327 this.append_pyout(json);
328 328 } else if (json.output_type === 'pyerr') {
329 329 this.append_pyerr(json);
330 330 } else if (json.output_type === 'display_data') {
331 331 this.append_display_data(json);
332 332 } else if (json.output_type === 'stream') {
333 333 this.append_stream(json);
334 334 }
335 335
336 336 this.outputs.push(json);
337 337
338 338 // Only reset the height to automatic if the height is currently
339 339 // fixed (done by wait=True flag on clear_output).
340 340 if (needs_height_reset) {
341 341 this.element.height('');
342 342 }
343 343
344 344 var that = this;
345 345 setTimeout(function(){that.element.trigger('resize');}, 100);
346 346 };
347 347
348 348
349 349 OutputArea.prototype.create_output_area = function () {
350 350 var oa = $("<div/>").addClass("output_area");
351 351 if (this.prompt_area) {
352 352 oa.append($('<div/>').addClass('prompt'));
353 353 }
354 354 return oa;
355 355 };
356 356
357 357
358 358 function _get_metadata_key(metadata, key, mime) {
359 359 var mime_md = metadata[mime];
360 360 // mime-specific higher priority
361 361 if (mime_md && mime_md[key] !== undefined) {
362 362 return mime_md[key];
363 363 }
364 364 // fallback on global
365 365 return metadata[key];
366 366 }
367 367
368 368 OutputArea.prototype.create_output_subarea = function(md, classes, mime) {
369 369 var subarea = $('<div/>').addClass('output_subarea').addClass(classes);
370 370 if (_get_metadata_key(md, 'isolated', mime)) {
371 371 // Create an iframe to isolate the subarea from the rest of the
372 372 // document
373 373 var iframe = $('<iframe/>').addClass('box-flex1');
374 374 iframe.css({'height':1, 'width':'100%', 'display':'block'});
375 375 iframe.attr('frameborder', 0);
376 376 iframe.attr('scrolling', 'auto');
377 377
378 378 // Once the iframe is loaded, the subarea is dynamically inserted
379 379 iframe.on('load', function() {
380 380 // Workaround needed by Firefox, to properly render svg inside
381 381 // iframes, see http://stackoverflow.com/questions/10177190/
382 382 // svg-dynamically-added-to-iframe-does-not-render-correctly
383 383 this.contentDocument.open();
384 384
385 385 // Insert the subarea into the iframe
386 386 // We must directly write the html. When using Jquery's append
387 387 // method, javascript is evaluated in the parent document and
388 388 // not in the iframe document.
389 389 this.contentDocument.write(subarea.html());
390 390
391 391 this.contentDocument.close();
392 392
393 393 var body = this.contentDocument.body;
394 394 // Adjust the iframe height automatically
395 395 iframe.height(body.scrollHeight + 'px');
396 396 });
397 397
398 398 // Elements should be appended to the inner subarea and not to the
399 399 // iframe
400 400 iframe.append = function(that) {
401 401 subarea.append(that);
402 402 };
403 403
404 404 return iframe;
405 405 } else {
406 406 return subarea;
407 407 }
408 408 }
409 409
410 410
411 411 OutputArea.prototype._append_javascript_error = function (err, element) {
412 412 // display a message when a javascript error occurs in display output
413 413 var msg = "Javascript error adding output!"
414 414 if ( element === undefined ) return;
415 415 element.append(
416 416 $('<div/>').html(msg + "<br/>" +
417 417 err.toString() +
418 418 '<br/>See your browser Javascript console for more details.'
419 419 ).addClass('js-error')
420 420 );
421 421 };
422 422
423 423 OutputArea.prototype._safe_append = function (toinsert) {
424 424 // safely append an item to the document
425 425 // this is an object created by user code,
426 426 // and may have errors, which should not be raised
427 427 // under any circumstances.
428 428 try {
429 429 this.element.append(toinsert);
430 430 } catch(err) {
431 431 console.log(err);
432 432 // Create an actual output_area and output_subarea, which creates
433 433 // the prompt area and the proper indentation.
434 434 var toinsert = this.create_output_area();
435 435 var subarea = $('<div/>').addClass('output_subarea');
436 436 toinsert.append(subarea);
437 437 this._append_javascript_error(err, subarea);
438 438 this.element.append(toinsert);
439 439 }
440 440 };
441 441
442 442
443 443 OutputArea.prototype.append_pyout = function (json) {
444 444 var n = json.prompt_number || ' ';
445 445 var toinsert = this.create_output_area();
446 446 if (this.prompt_area) {
447 447 toinsert.find('div.prompt').addClass('output_prompt').text('Out[' + n + ']:');
448 448 }
449 449 this.append_mime_type(json, toinsert);
450 450 this._safe_append(toinsert);
451 451 // If we just output latex, typeset it.
452 452 if ((json['text/latex'] !== undefined) || (json['text/html'] !== undefined)) {
453 453 this.typeset();
454 454 }
455 455 };
456 456
457 457
458 458 OutputArea.prototype.append_pyerr = function (json) {
459 459 var tb = json.traceback;
460 460 if (tb !== undefined && tb.length > 0) {
461 461 var s = '';
462 462 var len = tb.length;
463 463 for (var i=0; i<len; i++) {
464 464 s = s + tb[i] + '\n';
465 465 }
466 466 s = s + '\n';
467 467 var toinsert = this.create_output_area();
468 468 this.append_text(s, {}, toinsert);
469 469 this._safe_append(toinsert);
470 470 }
471 471 };
472 472
473 473
474 474 OutputArea.prototype.append_stream = function (json) {
475 475 // temporary fix: if stream undefined (json file written prior to this patch),
476 476 // default to most likely stdout:
477 477 if (json.stream == undefined){
478 478 json.stream = 'stdout';
479 479 }
480 480 var text = json.text;
481 481 var subclass = "output_"+json.stream;
482 482 if (this.outputs.length > 0){
483 483 // have at least one output to consider
484 484 var last = this.outputs[this.outputs.length-1];
485 485 if (last.output_type == 'stream' && json.stream == last.stream){
486 486 // latest output was in the same stream,
487 487 // so append directly into its pre tag
488 488 // escape ANSI & HTML specials:
489 489 var pre = this.element.find('div.'+subclass).last().find('pre');
490 490 var html = utils.fixCarriageReturn(
491 491 pre.html() + utils.fixConsole(text));
492 492 pre.html(html);
493 493 return;
494 494 }
495 495 }
496 496
497 497 if (!text.replace("\r", "")) {
498 498 // text is nothing (empty string, \r, etc.)
499 499 // so don't append any elements, which might add undesirable space
500 500 return;
501 501 }
502 502
503 503 // If we got here, attach a new div
504 504 var toinsert = this.create_output_area();
505 505 this.append_text(text, {}, toinsert, "output_stream "+subclass);
506 506 this._safe_append(toinsert);
507 507 };
508 508
509 509
510 510 OutputArea.prototype.append_display_data = function (json) {
511 511 var toinsert = this.create_output_area();
512 512 if (this.append_mime_type(json, toinsert)) {
513 513 this._safe_append(toinsert);
514 514 // If we just output latex, typeset it.
515 515 if ((json['text/latex'] !== undefined) || (json['text/html'] !== undefined)) {
516 516 this.typeset();
517 517 }
518 518 }
519 519 };
520 520
521 521 OutputArea.display_order = [
522 522 'application/javascript',
523 523 'text/html',
524 524 'text/latex',
525 525 'image/svg+xml',
526 526 'image/png',
527 527 'image/jpeg',
528 528 'text/plain'
529 529 ];
530 530
531 531 OutputArea.safe_outputs = {
532 532 'text/plain' : true,
533 533 'image/png' : true,
534 534 'image/jpeg' : true
535 535 };
536 536
537 537 OutputArea.prototype.append_mime_type = function (json, element) {
538 538 for (var type_i in OutputArea.display_order) {
539 539 var type = OutputArea.display_order[type_i];
540 540 var append = OutputArea.append_map[type];
541 541 if ((json[type] !== undefined) && append) {
542 542 if (!this.trusted && !OutputArea.safe_outputs[type]) {
543 543 // not trusted show warning and do not display
544 544 var content = {
545 545 text : "Untrusted " + type + " output ignored.",
546 546 stream : "stderr"
547 547 }
548 548 this.append_stream(content);
549 549 continue;
550 550 }
551 551 var md = json.metadata || {};
552 552 append.apply(this, [json[type], md, element]);
553 553 return true;
554 554 }
555 555 }
556 556 return false;
557 557 };
558 558
559 559
560 560 OutputArea.prototype.append_html = function (html, md, element) {
561 561 var type = 'text/html';
562 562 var toinsert = this.create_output_subarea(md, "output_html rendered_html", type);
563 563 IPython.keyboard_manager.register_events(toinsert);
564 564 toinsert.append(html);
565 565 element.append(toinsert);
566 566 };
567 567
568 568
569 569 OutputArea.prototype.append_javascript = function (js, md, container) {
570 570 // We just eval the JS code, element appears in the local scope.
571 571 var type = 'application/javascript';
572 572 var element = this.create_output_subarea(md, "output_javascript", type);
573 573 IPython.keyboard_manager.register_events(element);
574 574 container.append(element);
575 575 try {
576 576 eval(js);
577 577 } catch(err) {
578 578 console.log(err);
579 579 this._append_javascript_error(err, element);
580 580 }
581 581 };
582 582
583 583
584 584 OutputArea.prototype.append_text = function (data, md, element, extra_class) {
585 585 var type = 'text/plain';
586 586 var toinsert = this.create_output_subarea(md, "output_text", type);
587 587 // escape ANSI & HTML specials in plaintext:
588 588 data = utils.fixConsole(data);
589 589 data = utils.fixCarriageReturn(data);
590 590 data = utils.autoLinkUrls(data);
591 591 if (extra_class){
592 592 toinsert.addClass(extra_class);
593 593 }
594 594 toinsert.append($("<pre/>").html(data));
595 595 element.append(toinsert);
596 596 };
597 597
598 598
599 599 OutputArea.prototype.append_svg = function (svg, md, element) {
600 600 var type = 'image/svg+xml';
601 601 var toinsert = this.create_output_subarea(md, "output_svg", type);
602 602 toinsert.append(svg);
603 603 element.append(toinsert);
604 604 };
605 605
606 606
607 607 OutputArea.prototype._dblclick_to_reset_size = function (img) {
608 608 // schedule wrapping image in resizable after a delay,
609 609 // so we don't end up calling resize on a zero-size object
610 610 var that = this;
611 611 setTimeout(function () {
612 612 var h0 = img.height();
613 613 var w0 = img.width();
614 614 if (!(h0 && w0)) {
615 615 // zero size, schedule another timeout
616 616 that._dblclick_to_reset_size(img);
617 617 return;
618 618 }
619 619 img.resizable({
620 620 aspectRatio: true,
621 621 autoHide: true
622 622 });
623 623 img.dblclick(function () {
624 624 // resize wrapper & image together for some reason:
625 625 img.parent().height(h0);
626 626 img.height(h0);
627 627 img.parent().width(w0);
628 628 img.width(w0);
629 629 });
630 630 }, 250);
631 631 };
632 632
633 633 var set_width_height = function (img, md, mime) {
634 634 // set width and height of an img element from metadata
635 635 var height = _get_metadata_key(md, 'height', mime);
636 636 if (height !== undefined) img.attr('height', height);
637 637 var width = _get_metadata_key(md, 'width', mime);
638 638 if (width !== undefined) img.attr('width', width);
639 639 };
640 640
641 641 OutputArea.prototype.append_png = function (png, md, element) {
642 642 var type = 'image/png';
643 643 var toinsert = this.create_output_subarea(md, "output_png", type);
644 644 var img = $("<img/>").attr('src','data:image/png;base64,'+png);
645 645 set_width_height(img, md, 'image/png');
646 646 this._dblclick_to_reset_size(img);
647 647 toinsert.append(img);
648 648 element.append(toinsert);
649 649 };
650 650
651 651
652 652 OutputArea.prototype.append_jpeg = function (jpeg, md, element) {
653 653 var type = 'image/jpeg';
654 654 var toinsert = this.create_output_subarea(md, "output_jpeg", type);
655 655 var img = $("<img/>").attr('src','data:image/jpeg;base64,'+jpeg);
656 656 set_width_height(img, md, 'image/jpeg');
657 657 this._dblclick_to_reset_size(img);
658 658 toinsert.append(img);
659 659 element.append(toinsert);
660 660 };
661 661
662 662
663 663 OutputArea.prototype.append_latex = function (latex, md, element) {
664 664 // This method cannot do the typesetting because the latex first has to
665 665 // be on the page.
666 666 var type = 'text/latex';
667 667 var toinsert = this.create_output_subarea(md, "output_latex", type);
668 668 toinsert.append(latex);
669 669 element.append(toinsert);
670 670 };
671 671
672 672 OutputArea.append_map = {
673 673 "text/plain" : OutputArea.prototype.append_text,
674 674 "text/html" : OutputArea.prototype.append_html,
675 675 "image/svg+xml" : OutputArea.prototype.append_svg,
676 676 "image/png" : OutputArea.prototype.append_png,
677 677 "image/jpeg" : OutputArea.prototype.append_jpeg,
678 678 "text/latex" : OutputArea.prototype.append_latex,
679 679 "application/json" : OutputArea.prototype.append_json,
680 680 "application/javascript" : OutputArea.prototype.append_javascript,
681 681 };
682 682
683 683 OutputArea.prototype.append_raw_input = function (msg) {
684 684 var that = this;
685 685 this.expand();
686 686 var content = msg.content;
687 687 var area = this.create_output_area();
688 688
689 689 // disable any other raw_inputs, if they are left around
690 690 $("div.output_subarea.raw_input").remove();
691 691
692 692 area.append(
693 693 $("<div/>")
694 694 .addClass("box-flex1 output_subarea raw_input")
695 695 .append(
696 696 $("<span/>")
697 697 .addClass("input_prompt")
698 698 .text(content.prompt)
699 699 )
700 700 .append(
701 701 $("<input/>")
702 702 .addClass("raw_input")
703 703 .attr('type', 'text')
704 704 .attr("size", 47)
705 705 .keydown(function (event, ui) {
706 706 // make sure we submit on enter,
707 707 // and don't re-execute the *cell* on shift-enter
708 708 if (event.which === utils.keycodes.ENTER) {
709 709 that._submit_raw_input();
710 710 return false;
711 711 }
712 712 })
713 713 )
714 714 );
715 715
716 716 this.element.append(area);
717 717 var raw_input = area.find('input.raw_input');
718 718 // Register events that enable/disable the keyboard manager while raw
719 719 // input is focused.
720 720 IPython.keyboard_manager.register_events(raw_input);
721 721 // Note, the following line used to read raw_input.focus().focus().
722 722 // This seemed to be needed otherwise only the cell would be focused.
723 723 // But with the modal UI, this seems to work fine with one call to focus().
724 724 raw_input.focus();
725 725 }
726 726
727 727 OutputArea.prototype._submit_raw_input = function (evt) {
728 728 var container = this.element.find("div.raw_input");
729 729 var theprompt = container.find("span.input_prompt");
730 730 var theinput = container.find("input.raw_input");
731 731 var value = theinput.val();
732 732 var content = {
733 733 output_type : 'stream',
734 734 name : 'stdout',
735 735 text : theprompt.text() + value + '\n'
736 736 }
737 737 // remove form container
738 738 container.parent().remove();
739 739 // replace with plaintext version in stdout
740 740 this.append_output(content, false);
741 741 $([IPython.events]).trigger('send_input_reply.Kernel', value);
742 742 }
743 743
744 744
745 745 OutputArea.prototype.handle_clear_output = function (msg) {
746 this.clear_output(msg.content.wait);
746 // msg spec v4 had stdout, stderr, display keys
747 // v4.1 replaced these with just wait
748 // The default behavior is the same (stdout=stderr=display=True, wait=False),
749 // so v4 messages will still be properly handled,
750 // except for the rarely used clearing less than all output.
751 this.clear_output(msg.content.wait || false);
747 752 };
748 753
749 754
750 755 OutputArea.prototype.clear_output = function(wait) {
751 756 if (wait) {
752 757
753 758 // If a clear is queued, clear before adding another to the queue.
754 759 if (this.clear_queued) {
755 760 this.clear_output(false);
756 761 };
757 762
758 763 this.clear_queued = true;
759 764 } else {
760 765
761 766 // Fix the output div's height if the clear_output is waiting for
762 767 // new output (it is being used in an animation).
763 768 if (this.clear_queued) {
764 769 var height = this.element.height();
765 770 this.element.height(height);
766 771 this.clear_queued = false;
767 772 }
768 773
769 774 // clear all, no need for logic
770 775 this.element.html("");
771 776 this.outputs = [];
772 777 this.trusted = true;
773 778 this.unscroll_area();
774 779 return;
775 780 };
776 781 };
777 782
778 783
779 784 // JSON serialization
780 785
781 786 OutputArea.prototype.fromJSON = function (outputs) {
782 787 var len = outputs.length;
783 788 var data;
784 789
785 790 for (var i=0; i<len; i++) {
786 791 data = outputs[i];
787 792 var msg_type = data.output_type;
788 793 if (msg_type === "display_data" || msg_type === "pyout") {
789 794 // convert short keys to mime keys
790 795 // TODO: remove mapping of short keys when we update to nbformat 4
791 796 data = this.rename_keys(data, OutputArea.mime_map_r);
792 797 data.metadata = this.rename_keys(data.metadata, OutputArea.mime_map_r);
793 798 }
794 799
795 800 this.append_output(data);
796 801 }
797 802 };
798 803
799 804
800 805 OutputArea.prototype.toJSON = function () {
801 806 var outputs = [];
802 807 var len = this.outputs.length;
803 808 var data;
804 809 for (var i=0; i<len; i++) {
805 810 data = this.outputs[i];
806 811 var msg_type = data.output_type;
807 812 if (msg_type === "display_data" || msg_type === "pyout") {
808 813 // convert mime keys to short keys
809 814 data = this.rename_keys(data, OutputArea.mime_map);
810 815 data.metadata = this.rename_keys(data.metadata, OutputArea.mime_map);
811 816 }
812 817 outputs[i] = data;
813 818 }
814 819 return outputs;
815 820 };
816 821
817 822
818 823 IPython.OutputArea = OutputArea;
819 824
820 825 return IPython;
821 826
822 827 }(IPython));
@@ -1,1156 +1,1171 b''
1 1 .. _messaging:
2 2
3 3 ======================
4 4 Messaging in IPython
5 5 ======================
6 6
7 7
8 Versioning
9 ==========
10
11 The IPython message specification is versioned independently of IPython.
12 The current version of the specification is 4.1.
13
14
8 15 Introduction
9 16 ============
10 17
11 18 This document explains the basic communications design and messaging
12 19 specification for how the various IPython objects interact over a network
13 20 transport. The current implementation uses the ZeroMQ_ library for messaging
14 21 within and between hosts.
15 22
16 23 .. Note::
17 24
18 25 This document should be considered the authoritative description of the
19 26 IPython messaging protocol, and all developers are strongly encouraged to
20 27 keep it updated as the implementation evolves, so that we have a single
21 28 common reference for all protocol details.
22 29
23 30 The basic design is explained in the following diagram:
24 31
25 32 .. image:: figs/frontend-kernel.png
26 33 :width: 450px
27 34 :alt: IPython kernel/frontend messaging architecture.
28 35 :align: center
29 36 :target: ../_images/frontend-kernel.png
30 37
31 38 A single kernel can be simultaneously connected to one or more frontends. The
32 39 kernel has three sockets that serve the following functions:
33 40
34 41 1. stdin: this ROUTER socket is connected to all frontends, and it allows
35 42 the kernel to request input from the active frontend when :func:`raw_input` is called.
36 43 The frontend that executed the code has a DEALER socket that acts as a 'virtual keyboard'
37 44 for the kernel while this communication is happening (illustrated in the
38 45 figure by the black outline around the central keyboard). In practice,
39 46 frontends may display such kernel requests using a special input widget or
40 47 otherwise indicating that the user is to type input for the kernel instead
41 48 of normal commands in the frontend.
42 49
43 50 2. Shell: this single ROUTER socket allows multiple incoming connections from
44 51 frontends, and this is the socket where requests for code execution, object
45 52 information, prompts, etc. are made to the kernel by any frontend. The
46 53 communication on this socket is a sequence of request/reply actions from
47 54 each frontend and the kernel.
48 55
49 56 3. IOPub: this socket is the 'broadcast channel' where the kernel publishes all
50 57 side effects (stdout, stderr, etc.) as well as the requests coming from any
51 58 client over the shell socket and its own requests on the stdin socket. There
52 59 are a number of actions in Python which generate side effects: :func:`print`
53 60 writes to ``sys.stdout``, errors generate tracebacks, etc. Additionally, in
54 61 a multi-client scenario, we want all frontends to be able to know what each
55 62 other has sent to the kernel (this can be useful in collaborative scenarios,
56 63 for example). This socket allows both side effects and the information
57 64 about communications taking place with one client over the shell channel
58 65 to be made available to all clients in a uniform manner.
59 66
60 67 All messages are tagged with enough information (details below) for clients
61 68 to know which messages come from their own interaction with the kernel and
62 69 which ones are from other clients, so they can display each type
63 70 appropriately.
64 71
65 72 The actual format of the messages allowed on each of these channels is
66 73 specified below. Messages are dicts of dicts with string keys and values that
67 74 are reasonably representable in JSON. Our current implementation uses JSON
68 75 explicitly as its message format, but this shouldn't be considered a permanent
69 76 feature. As we've discovered that JSON has non-trivial performance issues due
70 77 to excessive copying, we may in the future move to a pure pickle-based raw
71 78 message format. However, it should be possible to easily convert from the raw
72 79 objects to JSON, since we may have non-python clients (e.g. a web frontend).
73 80 As long as it's easy to make a JSON version of the objects that is a faithful
74 81 representation of all the data, we can communicate with such clients.
75 82
76 83 .. Note::
77 84
78 85 Not all of these have yet been fully fleshed out, but the key ones are, see
79 86 kernel and frontend files for actual implementation details.
80 87
81 88 General Message Format
82 89 ======================
83 90
84 91 A message is defined by the following four-dictionary structure::
85 92
86 93 {
87 94 # The message header contains a pair of unique identifiers for the
88 95 # originating session and the actual message id, in addition to the
89 96 # username for the process that generated the message. This is useful in
90 97 # collaborative settings where multiple users may be interacting with the
91 98 # same kernel simultaneously, so that frontends can label the various
92 99 # messages in a meaningful way.
93 100 'header' : {
94 101 'msg_id' : uuid,
95 102 'username' : str,
96 103 'session' : uuid,
97 104 # All recognized message type strings are listed below.
98 105 'msg_type' : str,
99 106 },
100 107
101 108 # In a chain of messages, the header from the parent is copied so that
102 109 # clients can track where messages come from.
103 110 'parent_header' : dict,
104 111
105 112 # Any metadata associated with the message.
106 113 'metadata' : dict,
107 114
108 115 # The actual content of the message must be a dict, whose structure
109 116 # depends on the message type.
110 117 'content' : dict,
111 118 }
112 119
113 120 The Wire Protocol
114 121 =================
115 122
116 123
117 124 This message format exists at a high level,
118 125 but does not describe the actual *implementation* at the wire level in zeromq.
119 126 The canonical implementation of the message spec is our :class:`~IPython.kernel.zmq.session.Session` class.
120 127
121 128 .. note::
122 129
123 130 This section should only be relevant to non-Python consumers of the protocol.
124 131 Python consumers should simply import and use IPython's own implementation of the wire protocol
125 132 in the :class:`IPython.kernel.zmq.session.Session` object.
126 133
127 134 Every message is serialized to a sequence of at least six blobs of bytes:
128 135
129 136 .. sourcecode:: python
130 137
131 138 [
132 139 b'u-u-i-d', # zmq identity(ies)
133 140 b'<IDS|MSG>', # delimiter
134 141 b'baddad42', # HMAC signature
135 142 b'{header}', # serialized header dict
136 143 b'{parent_header}', # serialized parent header dict
137 144 b'{metadata}', # serialized metadata dict
138 145 b'{content}, # serialized content dict
139 146 b'blob', # extra raw data buffer(s)
140 147 ...
141 148 ]
142 149
143 150 The front of the message is the ZeroMQ routing prefix,
144 151 which can be zero or more socket identities.
145 152 This is every piece of the message prior to the delimiter key ``<IDS|MSG>``.
146 153 In the case of IOPub, there should be just one prefix component,
147 154 which is the topic for IOPub subscribers, e.g. ``pyout``, ``display_data``.
148 155
149 156 .. note::
150 157
151 158 In most cases, the IOPub topics are irrelevant and completely ignored,
152 159 because frontends just subscribe to all topics.
153 160 The convention used in the IPython kernel is to use the msg_type as the topic,
154 161 and possibly extra information about the message, e.g. ``pyout`` or ``stream.stdout``
155 162
156 163 After the delimiter is the `HMAC`_ signature of the message, used for authentication.
157 164 If authentication is disabled, this should be an empty string.
158 165 By default, the hashing function used for computing these signatures is sha256.
159 166
160 167 .. _HMAC: http://en.wikipedia.org/wiki/HMAC
161 168
162 169 .. note::
163 170
164 171 To disable authentication and signature checking,
165 172 set the `key` field of a connection file to an empty string.
166 173
167 174 The signature is the HMAC hex digest of the concatenation of:
168 175
169 176 - A shared key (typically the ``key`` field of a connection file)
170 177 - The serialized header dict
171 178 - The serialized parent header dict
172 179 - The serialized metadata dict
173 180 - The serialized content dict
174 181
175 182 In Python, this is implemented via:
176 183
177 184 .. sourcecode:: python
178 185
179 186 # once:
180 187 digester = HMAC(key, digestmod=hashlib.sha256)
181 188
182 189 # for each message
183 190 d = digester.copy()
184 191 for serialized_dict in (header, parent, metadata, content):
185 192 d.update(serialized_dict)
186 193 signature = d.hexdigest()
187 194
188 195 After the signature is the actual message, always in four frames of bytes.
189 196 The four dictionaries that compose a message are serialized separately,
190 197 in the order of header, parent header, metadata, and content.
191 198 These can be serialized by any function that turns a dict into bytes.
192 199 The default and most common serialization is JSON, but msgpack and pickle
193 200 are common alternatives.
194 201
195 202 After the serialized dicts are zero to many raw data buffers,
196 203 which can be used by message types that support binary data (mainly apply and data_pub).
197 204
198 205
199 206 Python functional API
200 207 =====================
201 208
202 209 As messages are dicts, they map naturally to a ``func(**kw)`` call form. We
203 210 should develop, at a few key points, functional forms of all the requests that
204 211 take arguments in this manner and automatically construct the necessary dict
205 212 for sending.
206 213
207 214 In addition, the Python implementation of the message specification extends
208 215 messages upon deserialization to the following form for convenience::
209 216
210 217 {
211 218 'header' : dict,
212 219 # The msg's unique identifier and type are always stored in the header,
213 220 # but the Python implementation copies them to the top level.
214 221 'msg_id' : uuid,
215 222 'msg_type' : str,
216 223 'parent_header' : dict,
217 224 'content' : dict,
218 225 'metadata' : dict,
219 226 }
220 227
221 228 All messages sent to or received by any IPython process should have this
222 229 extended structure.
223 230
224 231
225 232 Messages on the shell ROUTER/DEALER sockets
226 233 ===========================================
227 234
228 235 .. _execute:
229 236
230 237 Execute
231 238 -------
232 239
233 240 This message type is used by frontends to ask the kernel to execute code on
234 241 behalf of the user, in a namespace reserved to the user's variables (and thus
235 242 separate from the kernel's own internal code and variables).
236 243
237 244 Message type: ``execute_request``::
238 245
239 246 content = {
240 247 # Source code to be executed by the kernel, one or more lines.
241 248 'code' : str,
242 249
243 250 # A boolean flag which, if True, signals the kernel to execute
244 251 # this code as quietly as possible. This means that the kernel
245 252 # will compile the code with 'exec' instead of 'single' (so
246 253 # sys.displayhook will not fire), forces store_history to be False,
247 254 # and will *not*:
248 255 # - broadcast exceptions on the PUB socket
249 256 # - do any logging
250 257 #
251 258 # The default is False.
252 259 'silent' : bool,
253 260
254 261 # A boolean flag which, if True, signals the kernel to populate history
255 262 # The default is True if silent is False. If silent is True, store_history
256 263 # is forced to be False.
257 264 'store_history' : bool,
258 265
259 266 # A list of variable names from the user's namespace to be retrieved.
260 267 # What returns is a rich representation of each variable (dict keyed by name).
261 268 # See the display_data content for the structure of the representation data.
262 269 'user_variables' : list,
263 270
264 271 # Similarly, a dict mapping names to expressions to be evaluated in the
265 272 # user's dict.
266 273 'user_expressions' : dict,
267 274
268 275 # Some frontends (e.g. the Notebook) do not support stdin requests. If
269 276 # raw_input is called from code executed from such a frontend, a
270 277 # StdinNotImplementedError will be raised.
271 278 'allow_stdin' : True,
272 279
273 280 }
274 281
275 282 The ``code`` field contains a single string (possibly multiline). The kernel
276 283 is responsible for splitting this into one or more independent execution blocks
277 284 and deciding whether to compile these in 'single' or 'exec' mode (see below for
278 285 detailed execution semantics).
279 286
280 287 The ``user_`` fields deserve a detailed explanation. In the past, IPython had
281 288 the notion of a prompt string that allowed arbitrary code to be evaluated, and
282 289 this was put to good use by many in creating prompts that displayed system
283 290 status, path information, and even more esoteric uses like remote instrument
284 291 status acquired over the network. But now that IPython has a clean separation
285 292 between the kernel and the clients, the kernel has no prompt knowledge; prompts
286 293 are a frontend-side feature, and it should be even possible for different
287 294 frontends to display different prompts while interacting with the same kernel.
288 295
289 296 The kernel now provides the ability to retrieve data from the user's namespace
290 297 after the execution of the main ``code``, thanks to two fields in the
291 298 ``execute_request`` message:
292 299
293 300 - ``user_variables``: If only variables from the user's namespace are needed, a
294 301 list of variable names can be passed and a dict with these names as keys and
295 302 their :func:`repr()` as values will be returned.
296 303
297 304 - ``user_expressions``: For more complex expressions that require function
298 305 evaluations, a dict can be provided with string keys and arbitrary python
299 306 expressions as values. The return message will contain also a dict with the
300 307 same keys and the :func:`repr()` of the evaluated expressions as value.
301 308
302 309 With this information, frontends can display any status information they wish
303 310 in the form that best suits each frontend (a status line, a popup, inline for a
304 311 terminal, etc).
305 312
306 313 .. Note::
307 314
308 315 In order to obtain the current execution counter for the purposes of
309 316 displaying input prompts, frontends simply make an execution request with an
310 317 empty code string and ``silent=True``.
311 318
312 319 Execution semantics
313 320 ~~~~~~~~~~~~~~~~~~~
314 321
315 322 When the silent flag is false, the execution of use code consists of the
316 323 following phases (in silent mode, only the ``code`` field is executed):
317 324
318 325 1. Run the ``pre_runcode_hook``.
319 326
320 327 2. Execute the ``code`` field, see below for details.
321 328
322 329 3. If #2 succeeds, compute ``user_variables`` and ``user_expressions`` are
323 330 computed. This ensures that any error in the latter don't harm the main
324 331 code execution.
325 332
326 333 4. Call any method registered with :meth:`register_post_execute`.
327 334
328 335 .. warning::
329 336
330 337 The API for running code before/after the main code block is likely to
331 338 change soon. Both the ``pre_runcode_hook`` and the
332 339 :meth:`register_post_execute` are susceptible to modification, as we find a
333 340 consistent model for both.
334 341
335 342 To understand how the ``code`` field is executed, one must know that Python
336 343 code can be compiled in one of three modes (controlled by the ``mode`` argument
337 344 to the :func:`compile` builtin):
338 345
339 346 *single*
340 347 Valid for a single interactive statement (though the source can contain
341 348 multiple lines, such as a for loop). When compiled in this mode, the
342 349 generated bytecode contains special instructions that trigger the calling of
343 350 :func:`sys.displayhook` for any expression in the block that returns a value.
344 351 This means that a single statement can actually produce multiple calls to
345 352 :func:`sys.displayhook`, if for example it contains a loop where each
346 353 iteration computes an unassigned expression would generate 10 calls::
347 354
348 355 for i in range(10):
349 356 i**2
350 357
351 358 *exec*
352 359 An arbitrary amount of source code, this is how modules are compiled.
353 360 :func:`sys.displayhook` is *never* implicitly called.
354 361
355 362 *eval*
356 363 A single expression that returns a value. :func:`sys.displayhook` is *never*
357 364 implicitly called.
358 365
359 366
360 367 The ``code`` field is split into individual blocks each of which is valid for
361 368 execution in 'single' mode, and then:
362 369
363 370 - If there is only a single block: it is executed in 'single' mode.
364 371
365 372 - If there is more than one block:
366 373
367 374 * if the last one is a single line long, run all but the last in 'exec' mode
368 375 and the very last one in 'single' mode. This makes it easy to type simple
369 376 expressions at the end to see computed values.
370 377
371 378 * if the last one is no more than two lines long, run all but the last in
372 379 'exec' mode and the very last one in 'single' mode. This makes it easy to
373 380 type simple expressions at the end to see computed values. - otherwise
374 381 (last one is also multiline), run all in 'exec' mode
375 382
376 383 * otherwise (last one is also multiline), run all in 'exec' mode as a single
377 384 unit.
378 385
379 386 Any error in retrieving the ``user_variables`` or evaluating the
380 387 ``user_expressions`` will result in a simple error message in the return fields
381 388 of the form::
382 389
383 390 [ERROR] ExceptionType: Exception message
384 391
385 392 The user can simply send the same variable name or expression for evaluation to
386 393 see a regular traceback.
387 394
388 395 Errors in any registered post_execute functions are also reported similarly,
389 396 and the failing function is removed from the post_execution set so that it does
390 397 not continue triggering failures.
391 398
392 399 Upon completion of the execution request, the kernel *always* sends a reply,
393 400 with a status code indicating what happened and additional data depending on
394 401 the outcome. See :ref:`below <execution_results>` for the possible return
395 402 codes and associated data.
396 403
397 404
398 405 Execution counter (old prompt number)
399 406 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
400 407
401 408 The kernel has a single, monotonically increasing counter of all execution
402 409 requests that are made with ``store_history=True``. This counter is used to populate
403 410 the ``In[n]``, ``Out[n]`` and ``_n`` variables, so clients will likely want to
404 411 display it in some form to the user, which will typically (but not necessarily)
405 412 be done in the prompts. The value of this counter will be returned as the
406 413 ``execution_count`` field of all ``execute_reply`` messages.
407 414
408 415 .. _execution_results:
409 416
410 417 Execution results
411 418 ~~~~~~~~~~~~~~~~~
412 419
413 420 Message type: ``execute_reply``::
414 421
415 422 content = {
416 423 # One of: 'ok' OR 'error' OR 'abort'
417 424 'status' : str,
418 425
419 426 # The global kernel counter that increases by one with each request that
420 427 # stores history. This will typically be used by clients to display
421 428 # prompt numbers to the user. If the request did not store history, this will
422 429 # be the current value of the counter in the kernel.
423 430 'execution_count' : int,
424 431 }
425 432
426 433 When status is 'ok', the following extra fields are present::
427 434
428 435 {
429 436 # 'payload' will be a list of payload dicts.
430 437 # Each execution payload is a dict with string keys that may have been
431 438 # produced by the code being executed. It is retrieved by the kernel at
432 439 # the end of the execution and sent back to the front end, which can take
433 440 # action on it as needed.
434 441 # The only requirement of each payload dict is that it have a 'source' key,
435 442 # which is a string classifying the payload (e.g. 'pager').
436 443 'payload' : list(dict),
437 444
438 445 # Results for the user_variables and user_expressions.
439 446 'user_variables' : dict,
440 447 'user_expressions' : dict,
441 448 }
442 449
443 450 .. admonition:: Execution payloads
444 451
445 452 The notion of an 'execution payload' is different from a return value of a
446 453 given set of code, which normally is just displayed on the pyout stream
447 454 through the PUB socket. The idea of a payload is to allow special types of
448 455 code, typically magics, to populate a data container in the IPython kernel
449 456 that will be shipped back to the caller via this channel. The kernel
450 457 has an API for this in the PayloadManager::
451 458
452 459 ip.payload_manager.write_payload(payload_dict)
453 460
454 461 which appends a dictionary to the list of payloads.
455 462
456 463 The payload API is not yet stabilized,
457 464 and should probably not be supported by non-Python kernels at this time.
458 465 In such cases, the payload list should always be empty.
459 466
460 467
461 468 When status is 'error', the following extra fields are present::
462 469
463 470 {
464 471 'ename' : str, # Exception name, as a string
465 472 'evalue' : str, # Exception value, as a string
466 473
467 474 # The traceback will contain a list of frames, represented each as a
468 475 # string. For now we'll stick to the existing design of ultraTB, which
469 476 # controls exception level of detail statefully. But eventually we'll
470 477 # want to grow into a model where more information is collected and
471 478 # packed into the traceback object, with clients deciding how little or
472 479 # how much of it to unpack. But for now, let's start with a simple list
473 480 # of strings, since that requires only minimal changes to ultratb as
474 481 # written.
475 482 'traceback' : list,
476 483 }
477 484
478 485
479 486 When status is 'abort', there are for now no additional data fields. This
480 487 happens when the kernel was interrupted by a signal.
481 488
482 489
483 490 Object information
484 491 ------------------
485 492
486 493 One of IPython's most used capabilities is the introspection of Python objects
487 494 in the user's namespace, typically invoked via the ``?`` and ``??`` characters
488 495 (which in reality are shorthands for the ``%pinfo`` magic). This is used often
489 496 enough that it warrants an explicit message type, especially because frontends
490 497 may want to get object information in response to user keystrokes (like Tab or
491 498 F1) besides from the user explicitly typing code like ``x??``.
492 499
493 500 Message type: ``object_info_request``::
494 501
495 502 content = {
496 503 # The (possibly dotted) name of the object to be searched in all
497 504 # relevant namespaces
498 505 'oname' : str,
499 506
500 507 # The level of detail desired. The default (0) is equivalent to typing
501 508 # 'x?' at the prompt, 1 is equivalent to 'x??'.
502 509 'detail_level' : int,
503 510 }
504 511
505 512 The returned information will be a dictionary with keys very similar to the
506 513 field names that IPython prints at the terminal.
507 514
508 515 Message type: ``object_info_reply``::
509 516
510 517 content = {
511 518 # The name the object was requested under
512 519 'name' : str,
513 520
514 521 # Boolean flag indicating whether the named object was found or not. If
515 522 # it's false, all other fields will be empty.
516 523 'found' : bool,
517 524
518 525 # Flags for magics and system aliases
519 526 'ismagic' : bool,
520 527 'isalias' : bool,
521 528
522 529 # The name of the namespace where the object was found ('builtin',
523 530 # 'magics', 'alias', 'interactive', etc.)
524 531 'namespace' : str,
525 532
526 533 # The type name will be type.__name__ for normal Python objects, but it
527 534 # can also be a string like 'Magic function' or 'System alias'
528 535 'type_name' : str,
529 536
530 537 # The string form of the object, possibly truncated for length if
531 538 # detail_level is 0
532 539 'string_form' : str,
533 540
534 541 # For objects with a __class__ attribute this will be set
535 542 'base_class' : str,
536 543
537 544 # For objects with a __len__ attribute this will be set
538 545 'length' : int,
539 546
540 547 # If the object is a function, class or method whose file we can find,
541 548 # we give its full path
542 549 'file' : str,
543 550
544 551 # For pure Python callable objects, we can reconstruct the object
545 552 # definition line which provides its call signature. For convenience this
546 553 # is returned as a single 'definition' field, but below the raw parts that
547 554 # compose it are also returned as the argspec field.
548 555 'definition' : str,
549 556
550 557 # The individual parts that together form the definition string. Clients
551 558 # with rich display capabilities may use this to provide a richer and more
552 559 # precise representation of the definition line (e.g. by highlighting
553 560 # arguments based on the user's cursor position). For non-callable
554 561 # objects, this field is empty.
555 562 'argspec' : { # The names of all the arguments
556 563 args : list,
557 564 # The name of the varargs (*args), if any
558 565 varargs : str,
559 566 # The name of the varkw (**kw), if any
560 567 varkw : str,
561 568 # The values (as strings) of all default arguments. Note
562 569 # that these must be matched *in reverse* with the 'args'
563 570 # list above, since the first positional args have no default
564 571 # value at all.
565 572 defaults : list,
566 573 },
567 574
568 575 # For instances, provide the constructor signature (the definition of
569 576 # the __init__ method):
570 577 'init_definition' : str,
571 578
572 579 # Docstrings: for any object (function, method, module, package) with a
573 580 # docstring, we show it. But in addition, we may provide additional
574 581 # docstrings. For example, for instances we will show the constructor
575 582 # and class docstrings as well, if available.
576 583 'docstring' : str,
577 584
578 585 # For instances, provide the constructor and class docstrings
579 586 'init_docstring' : str,
580 587 'class_docstring' : str,
581 588
582 589 # If it's a callable object whose call method has a separate docstring and
583 590 # definition line:
584 591 'call_def' : str,
585 592 'call_docstring' : str,
586 593
587 594 # If detail_level was 1, we also try to find the source code that
588 595 # defines the object, if possible. The string 'None' will indicate
589 596 # that no source was found.
590 597 'source' : str,
591 598 }
592 599
593 600
594 601 Complete
595 602 --------
596 603
597 604 Message type: ``complete_request``::
598 605
599 606 content = {
600 607 # The text to be completed, such as 'a.is'
601 608 # this may be an empty string if the frontend does not do any lexing,
602 609 # in which case the kernel must figure out the completion
603 610 # based on 'line' and 'cursor_pos'.
604 611 'text' : str,
605 612
606 613 # The full line, such as 'print a.is'. This allows completers to
607 614 # make decisions that may require information about more than just the
608 615 # current word.
609 616 'line' : str,
610 617
611 618 # The entire block of text where the line is. This may be useful in the
612 619 # case of multiline completions where more context may be needed. Note: if
613 620 # in practice this field proves unnecessary, remove it to lighten the
614 621 # messages.
615 622
616 623 'block' : str or null/None,
617 624
618 625 # The position of the cursor where the user hit 'TAB' on the line.
619 626 'cursor_pos' : int,
620 627 }
621 628
622 629 Message type: ``complete_reply``::
623 630
624 631 content = {
625 632 # The list of all matches to the completion request, such as
626 633 # ['a.isalnum', 'a.isalpha'] for the above example.
627 634 'matches' : list,
628 635
629 636 # the substring of the matched text
630 637 # this is typically the common prefix of the matches,
631 638 # and the text that is already in the block that would be replaced by the full completion.
632 639 # This would be 'a.is' in the above example.
633 640 'matched_text' : str,
634 641
635 642 # status should be 'ok' unless an exception was raised during the request,
636 643 # in which case it should be 'error', along with the usual error message content
637 644 # in other messages.
638 645 'status' : 'ok'
639 646 }
640 647
641 648
642 649 History
643 650 -------
644 651
645 652 For clients to explicitly request history from a kernel. The kernel has all
646 653 the actual execution history stored in a single location, so clients can
647 654 request it from the kernel when needed.
648 655
649 656 Message type: ``history_request``::
650 657
651 658 content = {
652 659
653 660 # If True, also return output history in the resulting dict.
654 661 'output' : bool,
655 662
656 663 # If True, return the raw input history, else the transformed input.
657 664 'raw' : bool,
658 665
659 666 # So far, this can be 'range', 'tail' or 'search'.
660 667 'hist_access_type' : str,
661 668
662 669 # If hist_access_type is 'range', get a range of input cells. session can
663 670 # be a positive session number, or a negative number to count back from
664 671 # the current session.
665 672 'session' : int,
666 673 # start and stop are line numbers within that session.
667 674 'start' : int,
668 675 'stop' : int,
669 676
670 677 # If hist_access_type is 'tail' or 'search', get the last n cells.
671 678 'n' : int,
672 679
673 680 # If hist_access_type is 'search', get cells matching the specified glob
674 681 # pattern (with * and ? as wildcards).
675 682 'pattern' : str,
676 683
677 684 # If hist_access_type is 'search' and unique is true, do not
678 685 # include duplicated history. Default is false.
679 686 'unique' : bool,
680 687
681 688 }
682 689
683 690 .. versionadded:: 4.0
684 691 The key ``unique`` for ``history_request``.
685 692
686 693 Message type: ``history_reply``::
687 694
688 695 content = {
689 696 # A list of 3 tuples, either:
690 697 # (session, line_number, input) or
691 698 # (session, line_number, (input, output)),
692 699 # depending on whether output was False or True, respectively.
693 700 'history' : list,
694 701 }
695 702
696 703
697 704 Connect
698 705 -------
699 706
700 707 When a client connects to the request/reply socket of the kernel, it can issue
701 708 a connect request to get basic information about the kernel, such as the ports
702 709 the other ZeroMQ sockets are listening on. This allows clients to only have
703 710 to know about a single port (the shell channel) to connect to a kernel.
704 711
705 712 Message type: ``connect_request``::
706 713
707 714 content = {
708 715 }
709 716
710 717 Message type: ``connect_reply``::
711 718
712 719 content = {
713 720 'shell_port' : int, # The port the shell ROUTER socket is listening on.
714 721 'iopub_port' : int, # The port the PUB socket is listening on.
715 722 'stdin_port' : int, # The port the stdin ROUTER socket is listening on.
716 723 'hb_port' : int, # The port the heartbeat socket is listening on.
717 724 }
718 725
719 726
720 727 Kernel info
721 728 -----------
722 729
723 730 If a client needs to know information about the kernel, it can
724 731 make a request of the kernel's information.
725 732 This message can be used to fetch core information of the
726 733 kernel, including language (e.g., Python), language version number and
727 734 IPython version number, and the IPython message spec version number.
728 735
729 736 Message type: ``kernel_info_request``::
730 737
731 738 content = {
732 739 }
733 740
734 741 Message type: ``kernel_info_reply``::
735 742
736 743 content = {
737 744 # Version of messaging protocol (mandatory).
738 745 # The first integer indicates major version. It is incremented when
739 746 # there is any backward incompatible change.
740 747 # The second integer indicates minor version. It is incremented when
741 748 # there is any backward compatible change.
742 749 'protocol_version': [int, int],
743 750
744 751 # IPython version number (optional).
745 752 # Non-python kernel backend may not have this version number.
746 753 # The last component is an extra field, which may be 'dev' or
747 754 # 'rc1' in development version. It is an empty string for
748 755 # released version.
749 756 'ipython_version': [int, int, int, str],
750 757
751 758 # Language version number (mandatory).
752 759 # It is Python version number (e.g., [2, 7, 3]) for the kernel
753 760 # included in IPython.
754 761 'language_version': [int, ...],
755 762
756 763 # Programming language in which kernel is implemented (mandatory).
757 764 # Kernel included in IPython returns 'python'.
758 765 'language': str,
759 766 }
760 767
761 768
762 769 Kernel shutdown
763 770 ---------------
764 771
765 772 The clients can request the kernel to shut itself down; this is used in
766 773 multiple cases:
767 774
768 775 - when the user chooses to close the client application via a menu or window
769 776 control.
770 777 - when the user types 'exit' or 'quit' (or their uppercase magic equivalents).
771 778 - when the user chooses a GUI method (like the 'Ctrl-C' shortcut in the
772 779 IPythonQt client) to force a kernel restart to get a clean kernel without
773 780 losing client-side state like history or inlined figures.
774 781
775 782 The client sends a shutdown request to the kernel, and once it receives the
776 783 reply message (which is otherwise empty), it can assume that the kernel has
777 784 completed shutdown safely.
778 785
779 786 Upon their own shutdown, client applications will typically execute a last
780 787 minute sanity check and forcefully terminate any kernel that is still alive, to
781 788 avoid leaving stray processes in the user's machine.
782 789
783 790 Message type: ``shutdown_request``::
784 791
785 792 content = {
786 793 'restart' : bool # whether the shutdown is final, or precedes a restart
787 794 }
788 795
789 796 Message type: ``shutdown_reply``::
790 797
791 798 content = {
792 799 'restart' : bool # whether the shutdown is final, or precedes a restart
793 800 }
794 801
795 802 .. Note::
796 803
797 804 When the clients detect a dead kernel thanks to inactivity on the heartbeat
798 805 socket, they simply send a forceful process termination signal, since a dead
799 806 process is unlikely to respond in any useful way to messages.
800 807
801 808
802 809 Messages on the PUB/SUB socket
803 810 ==============================
804 811
805 812 Streams (stdout, stderr, etc)
806 813 ------------------------------
807 814
808 815 Message type: ``stream``::
809 816
810 817 content = {
811 818 # The name of the stream is one of 'stdout', 'stderr'
812 819 'name' : str,
813 820
814 821 # The data is an arbitrary string to be written to that stream
815 822 'data' : str,
816 823 }
817 824
818 825 Display Data
819 826 ------------
820 827
821 828 This type of message is used to bring back data that should be displayed (text,
822 829 html, svg, etc.) in the frontends. This data is published to all frontends.
823 830 Each message can have multiple representations of the data; it is up to the
824 831 frontend to decide which to use and how. A single message should contain all
825 832 possible representations of the same information. Each representation should
826 833 be a JSON'able data structure, and should be a valid MIME type.
827 834
828 835 Some questions remain about this design:
829 836
830 837 * Do we use this message type for pyout/displayhook? Probably not, because
831 838 the displayhook also has to handle the Out prompt display. On the other hand
832 839 we could put that information into the metadata section.
833 840
834 841 Message type: ``display_data``::
835 842
836 843 content = {
837 844
838 845 # Who create the data
839 846 'source' : str,
840 847
841 848 # The data dict contains key/value pairs, where the keys are MIME
842 849 # types and the values are the raw data of the representation in that
843 850 # format.
844 851 'data' : dict,
845 852
846 853 # Any metadata that describes the data
847 854 'metadata' : dict
848 855 }
849 856
850 857
851 858 The ``metadata`` contains any metadata that describes the output.
852 859 Global keys are assumed to apply to the output as a whole.
853 860 The ``metadata`` dict can also contain mime-type keys, which will be sub-dictionaries,
854 861 which are interpreted as applying only to output of that type.
855 862 Third parties should put any data they write into a single dict
856 863 with a reasonably unique name to avoid conflicts.
857 864
858 865 The only metadata keys currently defined in IPython are the width and height
859 866 of images::
860 867
861 868 'metadata' : {
862 869 'image/png' : {
863 870 'width': 640,
864 871 'height': 480
865 872 }
866 873 }
867 874
868 875
869 876 Raw Data Publication
870 877 --------------------
871 878
872 879 ``display_data`` lets you publish *representations* of data, such as images and html.
873 880 This ``data_pub`` message lets you publish *actual raw data*, sent via message buffers.
874 881
875 882 data_pub messages are constructed via the :func:`IPython.lib.datapub.publish_data` function:
876 883
877 884 .. sourcecode:: python
878 885
879 886 from IPython.kernel.zmq.datapub import publish_data
880 887 ns = dict(x=my_array)
881 888 publish_data(ns)
882 889
883 890
884 891 Message type: ``data_pub``::
885 892
886 893 content = {
887 894 # the keys of the data dict, after it has been unserialized
888 895 keys = ['a', 'b']
889 896 }
890 897 # the namespace dict will be serialized in the message buffers,
891 898 # which will have a length of at least one
892 899 buffers = ['pdict', ...]
893 900
894 901
895 902 The interpretation of a sequence of data_pub messages for a given parent request should be
896 903 to update a single namespace with subsequent results.
897 904
898 905 .. note::
899 906
900 907 No frontends directly handle data_pub messages at this time.
901 908 It is currently only used by the client/engines in :mod:`IPython.parallel`,
902 909 where engines may publish *data* to the Client,
903 910 of which the Client can then publish *representations* via ``display_data``
904 911 to various frontends.
905 912
906 913 Python inputs
907 914 -------------
908 915
909 916 These messages are the re-broadcast of the ``execute_request``.
910 917
911 918 Message type: ``pyin``::
912 919
913 920 content = {
914 921 'code' : str, # Source code to be executed, one or more lines
915 922
916 923 # The counter for this execution is also provided so that clients can
917 924 # display it, since IPython automatically creates variables called _iN
918 925 # (for input prompt In[N]).
919 926 'execution_count' : int
920 927 }
921 928
922 929 Python outputs
923 930 --------------
924 931
925 932 When Python produces output from code that has been compiled in with the
926 933 'single' flag to :func:`compile`, any expression that produces a value (such as
927 934 ``1+1``) is passed to ``sys.displayhook``, which is a callable that can do with
928 935 this value whatever it wants. The default behavior of ``sys.displayhook`` in
929 936 the Python interactive prompt is to print to ``sys.stdout`` the :func:`repr` of
930 937 the value as long as it is not ``None`` (which isn't printed at all). In our
931 938 case, the kernel instantiates as ``sys.displayhook`` an object which has
932 939 similar behavior, but which instead of printing to stdout, broadcasts these
933 940 values as ``pyout`` messages for clients to display appropriately.
934 941
935 942 IPython's displayhook can handle multiple simultaneous formats depending on its
936 943 configuration. The default pretty-printed repr text is always given with the
937 944 ``data`` entry in this message. Any other formats are provided in the
938 945 ``extra_formats`` list. Frontends are free to display any or all of these
939 946 according to its capabilities. ``extra_formats`` list contains 3-tuples of an ID
940 947 string, a type string, and the data. The ID is unique to the formatter
941 948 implementation that created the data. Frontends will typically ignore the ID
942 949 unless if it has requested a particular formatter. The type string tells the
943 950 frontend how to interpret the data. It is often, but not always a MIME type.
944 951 Frontends should ignore types that it does not understand. The data itself is
945 952 any JSON object and depends on the format. It is often, but not always a string.
946 953
947 954 Message type: ``pyout``::
948 955
949 956 content = {
950 957
951 958 # The counter for this execution is also provided so that clients can
952 959 # display it, since IPython automatically creates variables called _N
953 960 # (for prompt N).
954 961 'execution_count' : int,
955 962
956 963 # data and metadata are identical to a display_data message.
957 964 # the object being displayed is that passed to the display hook,
958 965 # i.e. the *result* of the execution.
959 966 'data' : dict,
960 967 'metadata' : dict,
961 968 }
962 969
963 970 Python errors
964 971 -------------
965 972
966 973 When an error occurs during code execution
967 974
968 975 Message type: ``pyerr``::
969 976
970 977 content = {
971 978 # Similar content to the execute_reply messages for the 'error' case,
972 979 # except the 'status' field is omitted.
973 980 }
974 981
975 982 Kernel status
976 983 -------------
977 984
978 985 This message type is used by frontends to monitor the status of the kernel.
979 986
980 987 Message type: ``status``::
981 988
982 989 content = {
983 990 # When the kernel starts to execute code, it will enter the 'busy'
984 991 # state and when it finishes, it will enter the 'idle' state.
985 992 # The kernel will publish state 'starting' exactly once at process startup.
986 993 execution_state : ('busy', 'idle', 'starting')
987 994 }
988 995
989 996 Clear output
990 997 ------------
991 998
992 999 This message type is used to clear the output that is visible on the frontend.
993 1000
994 1001 Message type: ``clear_output``::
995 1002
996 1003 content = {
997 1004
998 1005 # Wait to clear the output until new output is available. Clears the
999 1006 # existing output immediately before the new output is displayed.
1000 1007 # Useful for creating simple animations with minimal flickering.
1001 1008 'wait' : bool,
1002 1009 }
1003 1010
1011 .. versionchanged:: 4.1
1012
1013 'stdout', 'stderr', and 'display' boolean keys for selective clearing are removed,
1014 and 'wait' is added.
1015 The selective clearing keys are ignored in v4 and the default behavior remains the same,
1016 so v4 clear_output messages will be safely handled by a v4.1 frontend.
1017
1018
1004 1019 Messages on the stdin ROUTER/DEALER sockets
1005 1020 ===========================================
1006 1021
1007 1022 This is a socket where the request/reply pattern goes in the opposite direction:
1008 1023 from the kernel to a *single* frontend, and its purpose is to allow
1009 1024 ``raw_input`` and similar operations that read from ``sys.stdin`` on the kernel
1010 1025 to be fulfilled by the client. The request should be made to the frontend that
1011 1026 made the execution request that prompted ``raw_input`` to be called. For now we
1012 1027 will keep these messages as simple as possible, since they only mean to convey
1013 1028 the ``raw_input(prompt)`` call.
1014 1029
1015 1030 Message type: ``input_request``::
1016 1031
1017 1032 content = { 'prompt' : str }
1018 1033
1019 1034 Message type: ``input_reply``::
1020 1035
1021 1036 content = { 'value' : str }
1022 1037
1023 1038 .. note::
1024 1039
1025 1040 The stdin socket of the client is required to have the same zmq IDENTITY
1026 1041 as the client's shell socket.
1027 1042 Because of this, the ``input_request`` must be sent with the same IDENTITY
1028 1043 routing prefix as the ``execute_reply`` in order for the frontend to receive
1029 1044 the message.
1030 1045
1031 1046 .. note::
1032 1047
1033 1048 We do not explicitly try to forward the raw ``sys.stdin`` object, because in
1034 1049 practice the kernel should behave like an interactive program. When a
1035 1050 program is opened on the console, the keyboard effectively takes over the
1036 1051 ``stdin`` file descriptor, and it can't be used for raw reading anymore.
1037 1052 Since the IPython kernel effectively behaves like a console program (albeit
1038 1053 one whose "keyboard" is actually living in a separate process and
1039 1054 transported over the zmq connection), raw ``stdin`` isn't expected to be
1040 1055 available.
1041 1056
1042 1057
1043 1058 Heartbeat for kernels
1044 1059 =====================
1045 1060
1046 1061 Initially we had considered using messages like those above over ZMQ for a
1047 1062 kernel 'heartbeat' (a way to detect quickly and reliably whether a kernel is
1048 1063 alive at all, even if it may be busy executing user code). But this has the
1049 1064 problem that if the kernel is locked inside extension code, it wouldn't execute
1050 1065 the python heartbeat code. But it turns out that we can implement a basic
1051 1066 heartbeat with pure ZMQ, without using any Python messaging at all.
1052 1067
1053 1068 The monitor sends out a single zmq message (right now, it is a str of the
1054 1069 monitor's lifetime in seconds), and gets the same message right back, prefixed
1055 1070 with the zmq identity of the DEALER socket in the heartbeat process. This can be
1056 1071 a uuid, or even a full message, but there doesn't seem to be a need for packing
1057 1072 up a message when the sender and receiver are the exact same Python object.
1058 1073
1059 1074 The model is this::
1060 1075
1061 1076 monitor.send(str(self.lifetime)) # '1.2345678910'
1062 1077
1063 1078 and the monitor receives some number of messages of the form::
1064 1079
1065 1080 ['uuid-abcd-dead-beef', '1.2345678910']
1066 1081
1067 1082 where the first part is the zmq.IDENTITY of the heart's DEALER on the engine, and
1068 1083 the rest is the message sent by the monitor. No Python code ever has any
1069 1084 access to the message between the monitor's send, and the monitor's recv.
1070 1085
1071 1086 Custom Messages
1072 1087 ===============
1073 1088
1074 IPython 2.0 adds a messaging system for developers to add their own objects with Frontend
1089 .. versionadded:: 4.1
1090
1091 IPython 2.0 (msgspec v4.1) adds a messaging system for developers to add their own objects with Frontend
1075 1092 and Kernel-side components, and allow them to communicate with each other.
1076 1093 To do this, IPython adds a notion of a ``Comm``, which exists on both sides,
1077 1094 and can communicate in either direction.
1078 1095
1079 1096 These messages are fully symmetrical - both the Kernel and the Frontend can send each message,
1080 1097 and no messages expect a reply.
1081 1098 The Kernel listens for these messages on the Shell channel,
1082 1099 and the Frontend listens for them on the IOPub channel.
1083 1100
1084 .. versionadded:: 2.0
1085
1086 1101 Opening a Comm
1087 1102 --------------
1088 1103
1089 1104 Opening a Comm produces a ``comm_open`` message, to be sent to the other side::
1090 1105
1091 1106 {
1092 1107 'comm_id' : 'u-u-i-d',
1093 1108 'target_name' : 'my_comm',
1094 1109 'data' : {}
1095 1110 }
1096 1111
1097 1112 Every Comm has an ID and a target name.
1098 1113 The code handling the message on the receiving side is responsible for maintaining a mapping
1099 1114 of target_name keys to constructors.
1100 1115 After a ``comm_open`` message has been sent,
1101 1116 there should be a corresponding Comm instance on both sides.
1102 1117 The ``data`` key is always a dict and can be any extra JSON information used in initialization of the comm.
1103 1118
1104 1119 If the ``target_name`` key is not found on the receiving side,
1105 1120 then it should immediately reply with a ``comm_close`` message to avoid an inconsistent state.
1106 1121
1107 1122 Comm Messages
1108 1123 -------------
1109 1124
1110 1125 Comm messages are one-way communications to update comm state,
1111 1126 used for synchronizing widget state, or simply requesting actions of a comm's counterpart.
1112 1127
1113 1128 Essentially, each comm pair defines their own message specification implemented inside the ``data`` dict.
1114 1129
1115 1130 There are no expected replies (of course, one side can send another ``comm_msg`` in reply).
1116 1131
1117 1132 Message type: ``comm_msg``::
1118 1133
1119 1134 {
1120 1135 'comm_id' : 'u-u-i-d',
1121 1136 'data' : {}
1122 1137 }
1123 1138
1124 1139 Tearing Down Comms
1125 1140 ------------------
1126 1141
1127 1142 Since comms live on both sides, when a comm is destroyed the other side must be notified.
1128 1143 This is done with a ``comm_close`` message.
1129 1144
1130 1145 Message type: ``comm_close``::
1131 1146
1132 1147 {
1133 1148 'comm_id' : 'u-u-i-d',
1134 1149 'data' : {}
1135 1150 }
1136 1151
1137 1152 Output Side Effects
1138 1153 -------------------
1139 1154
1140 1155 Since comm messages can execute arbitrary user code,
1141 1156 handlers should set the parent header and publish status busy / idle,
1142 1157 just like an execute request.
1143 1158
1144 1159
1145 1160 ToDo
1146 1161 ====
1147 1162
1148 1163 Missing things include:
1149 1164
1150 1165 * Important: finish thinking through the payload concept and API.
1151 1166
1152 1167 * Important: ensure that we have a good solution for magics like %edit. It's
1153 1168 likely that with the payload concept we can build a full solution, but not
1154 1169 100% clear yet.
1155 1170
1156 1171 .. include:: ../links.txt
General Comments 0
You need to be logged in to leave comments. Login now