##// END OF EJS Templates
Clean up kernel.js
Jessica B. Hamrick -
Show More
@@ -1,627 +1,731 b''
1 1 // Copyright (c) IPython Development Team.
2 2 // Distributed under the terms of the Modified BSD License.
3 3
4 4 define([
5 5 'base/js/namespace',
6 6 'jquery',
7 7 'base/js/utils',
8 8 'services/kernels/js/comm',
9 9 'widgets/js/init',
10 10 ], function(IPython, $, utils, comm, widgetmanager) {
11 11 "use strict";
12 12
13 13 // Initialization and connection.
14 14 /**
15 15 * A Kernel Class to communicate with the Python kernel
16 16 * @Class Kernel
17 17 */
18 var Kernel = function (kernel_service_url, ws_url, notebook, name) {
18 var Kernel = function (kernel_service_url, ws_url, notebook, id, name) {
19 19 this.events = notebook.events;
20 this.kernel_id = null;
20
21 this.id = id;
22 this.name = name;
23
21 24 this.shell_channel = null;
22 25 this.iopub_channel = null;
23 26 this.stdin_channel = null;
27
24 28 this.kernel_service_url = kernel_service_url;
25 this.name = name;
29 this.kernel_url = utils.url_join_encode(this.kernel_service_url, this.id);
26 30 this.ws_url = ws_url || IPython.utils.get_body_data("wsUrl");
27 31 if (!this.ws_url) {
28 32 // trailing 's' in https will become wss for secure web sockets
29 33 this.ws_url = location.protocol.replace('http', 'ws') + "//" + location.host;
30 34 }
31 this.running = false;
35
32 36 this.username = "username";
33 37 this.session_id = utils.uuid();
34 38 this._msg_callbacks = {};
35 this.post = $.post;
36 39
37 40 if (typeof(WebSocket) !== 'undefined') {
38 41 this.WebSocket = WebSocket;
39 42 } else if (typeof(MozWebSocket) !== 'undefined') {
40 43 this.WebSocket = MozWebSocket;
41 44 } else {
42 45 alert('Your browser does not have WebSocket support, please try Chrome, Safari or Firefox β‰₯ 6. Firefox 4 and 5 are also supported by you have to enable WebSockets in about:config.');
43 46 }
44 47
45 48 this.bind_events();
46 49 this.init_iopub_handlers();
47 50 this.comm_manager = new comm.CommManager(this);
48 51 this.widget_manager = new widgetmanager.WidgetManager(this.comm_manager, notebook);
49 52
50 53 this.last_msg_id = null;
51 54 this.last_msg_callbacks = {};
52 55 };
53 56
54 57
55 58 Kernel.prototype._get_msg = function (msg_type, content, metadata) {
56 59 var msg = {
57 60 header : {
58 61 msg_id : utils.uuid(),
59 62 username : this.username,
60 63 session : this.session_id,
61 64 msg_type : msg_type,
62 65 version : "5.0"
63 66 },
64 67 metadata : metadata || {},
65 68 content : content,
66 69 parent_header : {}
67 70 };
68 71 return msg;
69 72 };
70 73
71 74 Kernel.prototype.bind_events = function () {
72 75 var that = this;
73 76 this.events.on('send_input_reply.Kernel', function(evt, data) {
74 77 that.send_input_reply(data);
75 78 });
76 79 };
77 80
78 81 // Initialize the iopub handlers
79 82
80 83 Kernel.prototype.init_iopub_handlers = function () {
81 84 var output_msg_types = ['stream', 'display_data', 'execute_result', 'error'];
82 85 this._iopub_handlers = {};
83 86 this.register_iopub_handler('status', $.proxy(this._handle_status_message, this));
84 87 this.register_iopub_handler('clear_output', $.proxy(this._handle_clear_output, this));
85 88
86 89 for (var i=0; i < output_msg_types.length; i++) {
87 90 this.register_iopub_handler(output_msg_types[i], $.proxy(this._handle_output_message, this));
88 91 }
89 92 };
90 93
91 94 /**
92 * Start the Python kernel
93 * @method start
95 * GET /api/kernels
94 96 */
95 Kernel.prototype.start = function (params) {
96 params = params || {};
97 if (!this.running) {
98 var qs = $.param(params);
99 this.post(utils.url_join_encode(this.kernel_service_url) + '?' + qs,
100 $.proxy(this._kernel_started, this),
101 'json'
102 );
103 }
97 Kernel.prototype.list = function (success, error) {
98 $.ajax(this.kernel_service_url, {
99 processData: false,
100 cache: false,
101 type: "GET",
102 dataType: "json",
103 success: success,
104 error: this._on_error(error)
105 });
104 106 };
105 107
106 108 /**
107 * Restart the python kernel.
108 *
109 * Emit a 'status_restarting.Kernel' event with
110 * the current object as parameter
111 *
112 * @method restart
109 * POST /api/kernels
110 */
111 Kernel.prototype.start = function (success, error) {
112 var that = this;
113 var on_success = function (data, status, xhr) {
114 that._kernel_started(data);
115 if (success) {
116 success(data, status, xhr);
117 }
118 };
119
120 $.ajax(this.kernel_service_url, {
121 processData: false,
122 cache: false,
123 type: "POST",
124 dataType: "json",
125 success: this._on_success(on_success),
126 error: this._on_error(error)
127 });
128 };
129
130 /**
131 * GET /api/kernels/[:kernel_id]
132 */
133 Kernel.prototype.get_info = function (success, error) {
134 $.ajax(this.kernel_url, {
135 processData: false,
136 cache: false,
137 type: "GET",
138 dataType: "json",
139 success: this._on_success(success),
140 error: this._on_error(error)
141 });
142 };
143
144 /**
145 * DELETE /api/kernels/[:kernel_id]
146 */
147 Kernel.prototype.kill = function (success, error) {
148 var that = this;
149 var on_success = function (data, status, xhr) {
150 that._kernel_dead();
151 if (success) {
152 success(data, status, xhr);
153 }
154 };
155
156 $.ajax(this.kernel_url, {
157 processData: false,
158 cache: false,
159 type: "DELETE",
160 dataType: "json",
161 success: this._on_success(success),
162 error: this._on_error(error)
163 });
164 };
165
166 /**
167 * POST /api/kernels/[:kernel_id]/interrupt
168 */
169 Kernel.prototype.interrupt = function (success, error) {
170 this.events.trigger('status_interrupting.Kernel', {kernel: this});
171 var url = utils.url_join_encode(this.kernel_url, 'interrupt');
172 $.ajax(url, {
173 processData: false,
174 cache: false,
175 type: "POST",
176 dataType: "json",
177 success: this._on_success(success),
178 error: this._on_error(error)
179 });
180 };
181
182 /**
183 * POST /api/kernels/[:kernel_id]/restart
113 184 */
114 Kernel.prototype.restart = function () {
185 Kernel.prototype.restart = function (success, error) {
115 186 this.events.trigger('status_restarting.Kernel', {kernel: this});
116 if (this.running) {
117 this.stop_channels();
118 this.post(utils.url_join_encode(this.kernel_url, "restart"),
119 $.proxy(this._kernel_started, this),
120 'json'
121 );
122 }
187 this.stop_channels();
188
189 var that = this;
190 var on_success = function (data, status, xhr) {
191 that._handle_start_success(data, status, xhr);
192 if (success) {
193 success(data, status, xhr);
194 }
195 };
196 var on_error = function (xhr, status, err) {
197 that._handle_start_failure(xhr, status, err);
198 if (error) {
199 error(xhr, status, err);
200 }
201 };
202
203 var url = utils.url_join_encode(this.kernel_url, 'restart');
204 $.ajax(url, {
205 processData: false,
206 cache: false,
207 type: "POST",
208 dataType: "json",
209 success: this._on_success(success),
210 error: this._on_error(error)
211 });
212 };
213
214 Kernel.prototype._on_success = function (success) {
215 var that = this;
216 return function (data, status, xhr) {
217 that.id = data.id;
218 that.name = data.name;
219 that.kernel_url = utils.url_join_encode(that.kernel_service_url, that.id);
220 if (success) {
221 success(data, status, xhr);
222 }
223 };
123 224 };
124 225
226 Kernel.prototype._on_error = function (error) {
227 return function (xhr, status, err) {
228 utils.log_ajax_error(xhr, status, err);
229 if (error) {
230 error(xhr, status, err);
231 }
232 };
233 };
125 234
126 235 Kernel.prototype._kernel_started = function (json) {
127 236 console.log("Kernel started: ", json.id);
128 this.running = true;
129 this.kernel_id = json.id;
130 this.kernel_url = utils.url_path_join(this.kernel_service_url, this.kernel_id);
237 this.events.trigger('status_started.Kernel', {kernel: this});
131 238 this.start_channels();
132 239 };
133 240
241 Kernel.prototype._kernel_dead = function () {
242 this.stop_channels();
243 this.events.trigger('status_dead.Kernel');
244 };
134 245
135 Kernel.prototype._websocket_closed = function(ws_url, early) {
246 Kernel.prototype._ws_closed = function(ws_url, early) {
136 247 this.stop_channels();
137 this.events.trigger('websocket_closed.Kernel',
248 this.events.trigger('status_disconnected.Kernel',
138 249 {ws_url: ws_url, kernel: this, early: early}
139 250 );
140 251 };
141 252
142 253 /**
143 254 * Start the `shell`and `iopub` channels.
144 255 * Will stop and restart them if they already exist.
145 256 *
146 257 * @method start_channels
147 258 */
148 259 Kernel.prototype.start_channels = function () {
149 260 var that = this;
150 261 this.stop_channels();
151 262 var ws_host_url = this.ws_url + this.kernel_url;
152 263 console.log("Starting WebSockets:", ws_host_url);
153 264 this.shell_channel = new this.WebSocket(
154 265 this.ws_url + utils.url_join_encode(this.kernel_url, "shell")
155 266 );
156 267 this.stdin_channel = new this.WebSocket(
157 268 this.ws_url + utils.url_join_encode(this.kernel_url, "stdin")
158 269 );
159 270 this.iopub_channel = new this.WebSocket(
160 271 this.ws_url + utils.url_join_encode(this.kernel_url, "iopub")
161 272 );
162 273
163 274 var already_called_onclose = false; // only alert once
164 275 var ws_closed_early = function(evt){
165 276 if (already_called_onclose){
166 277 return;
167 278 }
168 279 already_called_onclose = true;
169 280 if ( ! evt.wasClean ){
170 that._websocket_closed(ws_host_url, true);
281 that._ws_closed(ws_host_url, true);
171 282 }
172 283 };
173 284 var ws_closed_late = function(evt){
174 285 if (already_called_onclose){
175 286 return;
176 287 }
177 288 already_called_onclose = true;
178 289 if ( ! evt.wasClean ){
179 that._websocket_closed(ws_host_url, false);
290 that._ws_closed(ws_host_url, false);
180 291 }
181 292 };
182 293 var ws_error = function(evt){
183 294 if (already_called_onclose){
184 295 return;
185 296 }
186 297 already_called_onclose = true;
187 that._websocket_closed(ws_host_url, false);
298 that._ws_closed(ws_host_url, false);
188 299 };
189 300 var channels = [this.shell_channel, this.iopub_channel, this.stdin_channel];
190 301 for (var i=0; i < channels.length; i++) {
191 302 channels[i].onopen = $.proxy(this._ws_opened, this);
192 303 channels[i].onclose = ws_closed_early;
193 304 channels[i].onerror = ws_error;
194 305 }
195 306 // switch from early-close to late-close message after 1s
196 307 setTimeout(function() {
197 308 for (var i=0; i < channels.length; i++) {
198 309 if (channels[i] !== null) {
199 310 channels[i].onclose = ws_closed_late;
200 311 }
201 312 }
202 313 }, 1000);
203 314 this.shell_channel.onmessage = $.proxy(this._handle_shell_reply, this);
204 315 this.iopub_channel.onmessage = $.proxy(this._handle_iopub_message, this);
205 316 this.stdin_channel.onmessage = $.proxy(this._handle_input_request, this);
206 317 };
207 318
208 319 /**
209 320 * Handle a websocket entering the open state
210 321 * sends session and cookie authentication info as first message.
211 322 * Once all sockets are open, signal the Kernel.status_started event.
212 323 * @method _ws_opened
213 324 */
214 325 Kernel.prototype._ws_opened = function (evt) {
215 326 // send the session id so the Session object Python-side
216 327 // has the same identity
217 328 evt.target.send(this.session_id + ':' + document.cookie);
218
219 var channels = [this.shell_channel, this.iopub_channel, this.stdin_channel];
220 for (var i=0; i < channels.length; i++) {
221 // if any channel is not ready, don't trigger event.
222 if ( channels[i].readyState !== WebSocket.OPEN ) return;
329
330 if (this.is_connected()) {
331 // all events ready, trigger started event.
332 this.events.trigger('status_connected.Kernel', {kernel: this});
223 333 }
224 // all events ready, trigger started event.
225 this.events.trigger('status_started.Kernel', {kernel: this});
226 334 };
227 335
228 336 /**
229 337 * Stop the websocket channels.
230 338 * @method stop_channels
231 339 */
232 340 Kernel.prototype.stop_channels = function () {
233 341 var channels = [this.shell_channel, this.iopub_channel, this.stdin_channel];
234 342 for (var i=0; i < channels.length; i++) {
235 343 if ( channels[i] !== null ) {
236 344 channels[i].onclose = null;
237 345 channels[i].close();
238 346 }
239 347 }
240 348 this.shell_channel = this.iopub_channel = this.stdin_channel = null;
241 349 };
242 350
243 351 // Main public methods.
352
353 Kernel.prototype.is_connected = function () {
354 var channels = [this.shell_channel, this.iopub_channel, this.stdin_channel];
355 for (var i=0; i < channels.length; i++) {
356 // if any channel is not ready, then we're not connected
357 if (channels[i] === null) {
358 return false;
359 }
360 if (channels[i].readyState !== WebSocket.OPEN) {
361 return false;
362 }
363 }
364 return true;
365 };
244 366
245 367 // send a message on the Kernel's shell channel
246 368 Kernel.prototype.send_shell_message = function (msg_type, content, callbacks, metadata) {
369 if (!this.is_connected()) {
370 throw new Error("kernel is not connected");
371 }
247 372 var msg = this._get_msg(msg_type, content, metadata);
248 373 this.shell_channel.send(JSON.stringify(msg));
249 374 this.set_callbacks_for_msg(msg.header.msg_id, callbacks);
250 375 return msg.header.msg_id;
251 376 };
252 377
253 378 /**
254 379 * Get kernel info
255 380 *
256 381 * @param callback {function}
257 382 * @method kernel_info
258 383 *
259 384 * When calling this method, pass a callback function that expects one argument.
260 385 * The callback will be passed the complete `kernel_info_reply` message documented
261 386 * [here](http://ipython.org/ipython-doc/dev/development/messaging.html#kernel-info)
262 387 */
263 388 Kernel.prototype.kernel_info = function (callback) {
264 389 var callbacks;
265 390 if (callback) {
266 391 callbacks = { shell : { reply : callback } };
267 392 }
268 393 return this.send_shell_message("kernel_info_request", {}, callbacks);
269 394 };
270 395
271 396 /**
272 397 * Get info on an object
273 398 *
274 399 * @param code {string}
275 400 * @param cursor_pos {integer}
276 401 * @param callback {function}
277 402 * @method inspect
278 403 *
279 404 * When calling this method, pass a callback function that expects one argument.
280 405 * The callback will be passed the complete `inspect_reply` message documented
281 406 * [here](http://ipython.org/ipython-doc/dev/development/messaging.html#object-information)
282 407 */
283 408 Kernel.prototype.inspect = function (code, cursor_pos, callback) {
284 409 var callbacks;
285 410 if (callback) {
286 411 callbacks = { shell : { reply : callback } };
287 412 }
288 413
289 414 var content = {
290 415 code : code,
291 416 cursor_pos : cursor_pos,
292 detail_level : 0,
417 detail_level : 0
293 418 };
294 419 return this.send_shell_message("inspect_request", content, callbacks);
295 420 };
296 421
297 422 /**
298 423 * Execute given code into kernel, and pass result to callback.
299 424 *
300 425 * @async
301 426 * @method execute
302 427 * @param {string} code
303 428 * @param [callbacks] {Object} With the following keys (all optional)
304 429 * @param callbacks.shell.reply {function}
305 430 * @param callbacks.shell.payload.[payload_name] {function}
306 431 * @param callbacks.iopub.output {function}
307 432 * @param callbacks.iopub.clear_output {function}
308 433 * @param callbacks.input {function}
309 434 * @param {object} [options]
310 435 * @param [options.silent=false] {Boolean}
311 436 * @param [options.user_expressions=empty_dict] {Dict}
312 437 * @param [options.allow_stdin=false] {Boolean} true|false
313 438 *
314 439 * @example
315 440 *
316 441 * The options object should contain the options for the execute call. Its default
317 442 * values are:
318 443 *
319 444 * options = {
320 445 * silent : true,
321 446 * user_expressions : {},
322 447 * allow_stdin : false
323 448 * }
324 449 *
325 450 * When calling this method pass a callbacks structure of the form:
326 451 *
327 452 * callbacks = {
328 453 * shell : {
329 454 * reply : execute_reply_callback,
330 455 * payload : {
331 456 * set_next_input : set_next_input_callback,
332 457 * }
333 458 * },
334 459 * iopub : {
335 460 * output : output_callback,
336 461 * clear_output : clear_output_callback,
337 462 * },
338 463 * input : raw_input_callback
339 464 * }
340 465 *
341 466 * Each callback will be passed the entire message as a single arugment.
342 467 * Payload handlers will be passed the corresponding payload and the execute_reply message.
343 468 */
344 469 Kernel.prototype.execute = function (code, callbacks, options) {
345
346 470 var content = {
347 471 code : code,
348 472 silent : true,
349 473 store_history : false,
350 474 user_expressions : {},
351 475 allow_stdin : false
352 476 };
353 477 callbacks = callbacks || {};
354 478 if (callbacks.input !== undefined) {
355 479 content.allow_stdin = true;
356 480 }
357 481 $.extend(true, content, options);
358 482 this.events.trigger('execution_request.Kernel', {kernel: this, content:content});
359 483 return this.send_shell_message("execute_request", content, callbacks);
360 484 };
361 485
362 486 /**
363 487 * When calling this method, pass a function to be called with the `complete_reply` message
364 488 * as its only argument when it arrives.
365 489 *
366 490 * `complete_reply` is documented
367 491 * [here](http://ipython.org/ipython-doc/dev/development/messaging.html#complete)
368 492 *
369 493 * @method complete
370 494 * @param code {string}
371 495 * @param cursor_pos {integer}
372 496 * @param callback {function}
373 497 *
374 498 */
375 499 Kernel.prototype.complete = function (code, cursor_pos, callback) {
376 500 var callbacks;
377 501 if (callback) {
378 502 callbacks = { shell : { reply : callback } };
379 503 }
380 504 var content = {
381 505 code : code,
382 cursor_pos : cursor_pos,
506 cursor_pos : cursor_pos
383 507 };
384 508 return this.send_shell_message("complete_request", content, callbacks);
385 509 };
386 510
387
388 Kernel.prototype.interrupt = function () {
389 if (this.running) {
390 this.events.trigger('status_interrupting.Kernel', {kernel: this});
391 this.post(utils.url_join_encode(this.kernel_url, "interrupt"));
392 }
393 };
394
395
396 Kernel.prototype.kill = function (success, error) {
397 if (this.running) {
398 this.running = false;
399 var settings = {
400 cache : false,
401 type : "DELETE",
402 success : success,
403 error : error || utils.log_ajax_error,
404 };
405 $.ajax(utils.url_join_encode(this.kernel_url), settings);
406 this.stop_channels();
407 }
408 };
409
410 511 Kernel.prototype.send_input_reply = function (input) {
512 if (!this.is_connected()) {
513 throw new Error("kernel is not connected");
514 }
411 515 var content = {
412 value : input,
516 value : input
413 517 };
414 518 this.events.trigger('input_reply.Kernel', {kernel: this, content:content});
415 519 var msg = this._get_msg("input_reply", content);
416 520 this.stdin_channel.send(JSON.stringify(msg));
417 521 return msg.header.msg_id;
418 522 };
419 523
420 524
421 525 // Reply handlers
422 526
423 527 Kernel.prototype.register_iopub_handler = function (msg_type, callback) {
424 528 this._iopub_handlers[msg_type] = callback;
425 529 };
426 530
427 531 Kernel.prototype.get_iopub_handler = function (msg_type) {
428 532 // get iopub handler for a specific message type
429 533 return this._iopub_handlers[msg_type];
430 534 };
431 535
432 536
433 537 Kernel.prototype.get_callbacks_for_msg = function (msg_id) {
434 538 // get callbacks for a specific message
435 539 if (msg_id == this.last_msg_id) {
436 540 return this.last_msg_callbacks;
437 541 } else {
438 542 return this._msg_callbacks[msg_id];
439 543 }
440 544 };
441 545
442 546
443 547 Kernel.prototype.clear_callbacks_for_msg = function (msg_id) {
444 548 if (this._msg_callbacks[msg_id] !== undefined ) {
445 549 delete this._msg_callbacks[msg_id];
446 550 }
447 551 };
448 552
449 553 Kernel.prototype._finish_shell = function (msg_id) {
450 554 var callbacks = this._msg_callbacks[msg_id];
451 555 if (callbacks !== undefined) {
452 556 callbacks.shell_done = true;
453 557 if (callbacks.iopub_done) {
454 558 this.clear_callbacks_for_msg(msg_id);
455 559 }
456 560 }
457 561 };
458 562
459 563 Kernel.prototype._finish_iopub = function (msg_id) {
460 564 var callbacks = this._msg_callbacks[msg_id];
461 565 if (callbacks !== undefined) {
462 566 callbacks.iopub_done = true;
463 567 if (callbacks.shell_done) {
464 568 this.clear_callbacks_for_msg(msg_id);
465 569 }
466 570 }
467 571 };
468 572
469 573 /* Set callbacks for a particular message.
470 574 * Callbacks should be a struct of the following form:
471 575 * shell : {
472 576 *
473 577 * }
474 578
475 579 */
476 580 Kernel.prototype.set_callbacks_for_msg = function (msg_id, callbacks) {
477 581 this.last_msg_id = msg_id;
478 582 if (callbacks) {
479 583 // shallow-copy mapping, because we will modify it at the top level
480 584 var cbcopy = this._msg_callbacks[msg_id] = this.last_msg_callbacks = {};
481 585 cbcopy.shell = callbacks.shell;
482 586 cbcopy.iopub = callbacks.iopub;
483 587 cbcopy.input = callbacks.input;
484 588 cbcopy.shell_done = (!callbacks.shell);
485 589 cbcopy.iopub_done = (!callbacks.iopub);
486 590 } else {
487 591 this.last_msg_callbacks = {};
488 592 }
489 593 };
490 594
491 595
492 596 Kernel.prototype._handle_shell_reply = function (e) {
493 597 var reply = $.parseJSON(e.data);
494 598 this.events.trigger('shell_reply.Kernel', {kernel: this, reply:reply});
495 599 var content = reply.content;
496 600 var metadata = reply.metadata;
497 601 var parent_id = reply.parent_header.msg_id;
498 602 var callbacks = this.get_callbacks_for_msg(parent_id);
499 603 if (!callbacks || !callbacks.shell) {
500 604 return;
501 605 }
502 606 var shell_callbacks = callbacks.shell;
503 607
504 608 // signal that shell callbacks are done
505 609 this._finish_shell(parent_id);
506 610
507 611 if (shell_callbacks.reply !== undefined) {
508 612 shell_callbacks.reply(reply);
509 613 }
510 614 if (content.payload && shell_callbacks.payload) {
511 615 this._handle_payloads(content.payload, shell_callbacks.payload, reply);
512 616 }
513 617 };
514 618
515 619
516 620 Kernel.prototype._handle_payloads = function (payloads, payload_callbacks, msg) {
517 621 var l = payloads.length;
518 622 // Payloads are handled by triggering events because we don't want the Kernel
519 623 // to depend on the Notebook or Pager classes.
520 624 for (var i=0; i<l; i++) {
521 625 var payload = payloads[i];
522 626 var callback = payload_callbacks[payload.source];
523 627 if (callback) {
524 628 callback(payload, msg);
525 629 }
526 630 }
527 631 };
528 632
529 633 Kernel.prototype._handle_status_message = function (msg) {
530 634 var execution_state = msg.content.execution_state;
531 635 var parent_id = msg.parent_header.msg_id;
532 636
533 637 // dispatch status msg callbacks, if any
534 638 var callbacks = this.get_callbacks_for_msg(parent_id);
535 639 if (callbacks && callbacks.iopub && callbacks.iopub.status) {
536 640 try {
537 641 callbacks.iopub.status(msg);
538 642 } catch (e) {
539 643 console.log("Exception in status msg handler", e, e.stack);
540 644 }
541 645 }
542 646
543 647 if (execution_state === 'busy') {
544 648 this.events.trigger('status_busy.Kernel', {kernel: this});
545 649 } else if (execution_state === 'idle') {
546 650 // signal that iopub callbacks are (probably) done
547 651 // async output may still arrive,
548 652 // but only for the most recent request
549 653 this._finish_iopub(parent_id);
550 654
551 655 // trigger status_idle event
552 656 this.events.trigger('status_idle.Kernel', {kernel: this});
553 657 } else if (execution_state === 'restarting') {
554 658 // autorestarting is distinct from restarting,
555 659 // in that it means the kernel died and the server is restarting it.
556 660 // status_restarting sets the notification widget,
557 661 // autorestart shows the more prominent dialog.
558 662 this.events.trigger('status_autorestarting.Kernel', {kernel: this});
559 663 this.events.trigger('status_restarting.Kernel', {kernel: this});
560 664 } else if (execution_state === 'dead') {
561 665 this.stop_channels();
562 666 this.events.trigger('status_dead.Kernel', {kernel: this});
563 667 this.events.trigger('status_restart_failed.Kernel', {kernel: this});
564 668 }
565 669 };
566 670
567 671
568 672 // handle clear_output message
569 673 Kernel.prototype._handle_clear_output = function (msg) {
570 674 var callbacks = this.get_callbacks_for_msg(msg.parent_header.msg_id);
571 675 if (!callbacks || !callbacks.iopub) {
572 676 return;
573 677 }
574 678 var callback = callbacks.iopub.clear_output;
575 679 if (callback) {
576 680 callback(msg);
577 681 }
578 682 };
579 683
580 684
581 685 // handle an output message (execute_result, display_data, etc.)
582 686 Kernel.prototype._handle_output_message = function (msg) {
583 687 var callbacks = this.get_callbacks_for_msg(msg.parent_header.msg_id);
584 688 if (!callbacks || !callbacks.iopub) {
585 689 return;
586 690 }
587 691 var callback = callbacks.iopub.output;
588 692 if (callback) {
589 693 callback(msg);
590 694 }
591 695 };
592 696
593 697 // dispatch IOPub messages to respective handlers.
594 698 // each message type should have a handler.
595 699 Kernel.prototype._handle_iopub_message = function (e) {
596 700 var msg = $.parseJSON(e.data);
597 701
598 702 var handler = this.get_iopub_handler(msg.header.msg_type);
599 703 if (handler !== undefined) {
600 704 handler(msg);
601 705 }
602 706 };
603 707
604 708
605 709 Kernel.prototype._handle_input_request = function (e) {
606 710 var request = $.parseJSON(e.data);
607 711 var header = request.header;
608 712 var content = request.content;
609 713 var metadata = request.metadata;
610 714 var msg_type = header.msg_type;
611 715 if (msg_type !== 'input_request') {
612 716 console.log("Invalid input request!", request);
613 717 return;
614 718 }
615 719 var callbacks = this.get_callbacks_for_msg(request.parent_header.msg_id);
616 720 if (callbacks) {
617 721 if (callbacks.input) {
618 722 callbacks.input(request);
619 723 }
620 724 }
621 725 };
622 726
623 727 // Backwards compatability.
624 728 IPython.Kernel = Kernel;
625 729
626 730 return {'Kernel': Kernel};
627 731 });
General Comments 0
You need to be logged in to leave comments. Login now