##// END OF EJS Templates
Added support for multiple kernels.
Jonathan Frederic -
Show More
@@ -1,204 +1,205
1 //----------------------------------------------------------------------------
1 //----------------------------------------------------------------------------
2 // Copyright (C) 2013 The IPython Development Team
2 // Copyright (C) 2013 The IPython Development Team
3 //
3 //
4 // Distributed under the terms of the BSD License. The full license is in
4 // Distributed under the terms of the BSD License. The full license is in
5 // the file COPYING, distributed as part of this software.
5 // the file COPYING, distributed as part of this software.
6 //----------------------------------------------------------------------------
6 //----------------------------------------------------------------------------
7
7
8 //============================================================================
8 //============================================================================
9 // WidgetModel, WidgetView, and WidgetManager
9 // WidgetModel, WidgetView, and WidgetManager
10 //============================================================================
10 //============================================================================
11 /**
11 /**
12 * Base Widget classes
12 * Base Widget classes
13 * @module IPython
13 * @module IPython
14 * @namespace IPython
14 * @namespace IPython
15 * @submodule widget
15 * @submodule widget
16 */
16 */
17
17
18 (function () {
18 (function () {
19 "use strict";
19 "use strict";
20
20
21 // Use require.js 'define' method so that require.js is intelligent enough to
21 // Use require.js 'define' method so that require.js is intelligent enough to
22 // syncronously load everything within this file when it is being 'required'
22 // syncronously load everything within this file when it is being 'required'
23 // elsewhere.
23 // elsewhere.
24 define(["underscore",
24 define(["underscore",
25 "backbone",
25 "backbone",
26 ], function (underscore, backbone) {
26 ], function (underscore, backbone) {
27
27
28 // Backbone.sync method must be in widgetmanager.js file instead of
29 // widget.js so it can be overwritten for different contexts.
30 Backbone.sync = function (method, model, options) {
28 Backbone.sync = function (method, model, options) {
29 // Sync widget models to back-end.
30 //
31 // Backbone.sync method must be in widgetmanager.js file instead of
32 // widget.js so it can be overwritten for different contexts.
31 var result = model._handle_sync(method, options);
33 var result = model._handle_sync(method, options);
32 if (options.success) {
34 if (options.success) {
33 options.success(result);
35 options.success(result);
34 }
36 }
35 };
37 };
36
38
39
37 //--------------------------------------------------------------------
40 //--------------------------------------------------------------------
38 // WidgetManager class
41 // WidgetManager class
39 //--------------------------------------------------------------------
42 //--------------------------------------------------------------------
40 var WidgetManager = function () {
43 var WidgetManager = function (comm_manager) {
41 this.comm_manager = null;
44 // Public constructor
42 this._model_types = {}; /* Dictionary of model type names
45 WidgetManager._managers.push(this);
43 (target_name) and model types. */
44 this._view_types = {}; /* Dictionary of view names and view types. */
45 this._models = {}; /* Dictionary of model ids and model instances */
46 };
47
48
46
49 WidgetManager.prototype.attach_comm_manager = function (comm_manager) {
47 // Attach a comm manager to the
50 this.comm_manager = comm_manager;
48 this.comm_manager = comm_manager;
51
49
52 // Register already-registered widget model types with the comm manager.
50 // Register already-registered widget model types with the comm manager.
53 for (var widget_model_name in this._model_types) {
51 for (var name in WidgetManager._model_types) {
54 // TODO: Should not be a for.
52 if (WidgetManager._model_types.hasOwnProperty(name)) {
55 this.comm_manager.register_target(widget_model_name, $.proxy(this._handle_comm_open, this));
53 this.comm_manager.register_target(name, $.proxy(this._handle_comm_open, this));
54
55 }
56 }
56 }
57 };
57 };
58
58
59 //--------------------------------------------------------------------
60 // Class level
61 //--------------------------------------------------------------------
62 WidgetManager._model_types = {}; /* Dictionary of model type names (target_name) and model types. */
63 WidgetManager._view_types = {}; /* Dictionary of view names and view types. */
64 WidgetManager._models = {}; /* Dictionary of model ids and model instances */
65 WidgetManager._managers = []; /* List of widget managers */
66
67 WidgetManager.register_widget_model = function (model_name, model_type) {
68 // Registers a widget model by name.
69 WidgetManager._model_types[model_name] = model_type;
59
70
60 WidgetManager.prototype.register_widget_model = function (widget_model_name, widget_model_type) {
61 // Register the widget with the comm manager. Make sure to pass this object's context
71 // Register the widget with the comm manager. Make sure to pass this object's context
62 // in so `this` works in the call back.
72 // in so `this` works in the call back.
63 if (this.comm_manager !== null) {
73 for (var i = 0; i < WidgetManager._managers.length; i++) {
64 this.comm_manager.register_target(widget_model_name, $.proxy(this._handle_comm_open, this));
74 var instance = WidgetManager._managers[i];
75 if (instance.comm_manager !== null) {
76 instance.comm_manager.register_target(model_name, $.proxy(instance._handle_comm_open, instance));
77 }
65 }
78 }
66 this._model_types[widget_model_name] = widget_model_type;
67 };
79 };
68
80
69
81 WidgetManager.register_widget_view = function (view_name, view_type) {
70 WidgetManager.prototype.register_widget_view = function (widget_view_name, widget_view_type) {
82 // Registers a widget view by name.
71 this._view_types[widget_view_name] = widget_view_type;
83 WidgetManager._view_types[view_name] = view_type;
72 };
84 };
73
85
74
86 //--------------------------------------------------------------------
87 // Instance level
88 //--------------------------------------------------------------------
75 WidgetManager.prototype.display_view = function(msg, model) {
89 WidgetManager.prototype.display_view = function(msg, model) {
76 var cell = this.get_msg_cell(msg.parent_header.msg_id);
90 var cell = this.get_msg_cell(msg.parent_header.msg_id);
77 if (cell === null) {
91 if (cell === null) {
78 console.log("Could not determine where the display" +
92 console.log("Could not determine where the display" +
79 " message was from. Widget will not be displayed");
93 " message was from. Widget will not be displayed");
80 } else {
94 } else {
81 var view = this.create_view(model, {cell: cell});
95 var view = this.create_view(model, {cell: cell});
82 if (view === undefined) {
96 if (view === undefined) {
83 console.error("View creation failed", model);
97 console.error("View creation failed", model);
84 }
98 }
85 if (cell.widget_subarea !== undefined
99 if (cell.widget_subarea !== undefined
86 && cell.widget_subarea !== null) {
100 && cell.widget_subarea !== null) {
87
101
88 cell.widget_area.show();
102 cell.widget_area.show();
89 cell.widget_subarea.append(view.$el);
103 cell.widget_subarea.append(view.$el);
90 }
104 }
91 }
105 }
92 },
106 },
93
107
94
95 WidgetManager.prototype.create_view = function(model, options) {
108 WidgetManager.prototype.create_view = function(model, options) {
96 var view_name = model.get('view_name');
109 var view_name = model.get('view_name');
97 var ViewType = this._view_types[view_name];
110 var ViewType = WidgetManager._view_types[view_name];
98 if (ViewType !== undefined && ViewType !== null) {
111 if (ViewType !== undefined && ViewType !== null) {
99 var parameters = {model: model, options: options};
112 var parameters = {model: model, options: options};
100 var view = new ViewType(parameters);
113 var view = new ViewType(parameters);
101 view.render();
114 view.render();
102 IPython.keyboard_manager.register_events(view.$el);
115 IPython.keyboard_manager.register_events(view.$el);
103 model.views.push(view);
116 model.views.push(view);
104 model.on('destroy', view.remove, view);
117 model.on('destroy', view.remove, view);
105 return view;
118 return view;
106 }
119 }
107 },
120 },
108
121
109
110 WidgetManager.prototype.get_msg_cell = function (msg_id) {
122 WidgetManager.prototype.get_msg_cell = function (msg_id) {
111 var cell = null;
123 var cell = null;
112 // First, check to see if the msg was triggered by cell execution.
124 // First, check to see if the msg was triggered by cell execution.
113 if (IPython.notebook !== undefined && IPython.notebook !== null) {
125 if (IPython.notebook !== undefined && IPython.notebook !== null) {
114 cell = IPython.notebook.get_msg_cell(msg_id);
126 cell = IPython.notebook.get_msg_cell(msg_id);
115 }
127 }
116 if (cell !== null) {
128 if (cell !== null) {
117 return cell
129 return cell
118 }
130 }
119 // Second, check to see if a get_cell callback was defined
131 // Second, check to see if a get_cell callback was defined
120 // for the message. get_cell callbacks are registered for
132 // for the message. get_cell callbacks are registered for
121 // widget messages, so this block is actually checking to see if the
133 // widget messages, so this block is actually checking to see if the
122 // message was triggered by a widget.
134 // message was triggered by a widget.
123 var kernel = null;
135 var kernel = this.comm_manager.kernel;
124 if (this.comm_manager !== null) {
125 kernel = this.comm_manager.kernel;
126 }
127 if (kernel !== undefined && kernel !== null) {
136 if (kernel !== undefined && kernel !== null) {
128 var callbacks = kernel.get_callbacks_for_msg(msg_id);
137 var callbacks = kernel.get_callbacks_for_msg(msg_id);
129 if (callbacks !== undefined &&
138 if (callbacks !== undefined &&
130 callbacks.iopub !== undefined &&
139 callbacks.iopub !== undefined &&
131 callbacks.iopub.get_cell !== undefined) {
140 callbacks.iopub.get_cell !== undefined) {
132
141
133 return callbacks.iopub.get_cell();
142 return callbacks.iopub.get_cell();
134 }
143 }
135 }
144 }
136
145
137 // Not triggered by a cell or widget (no get_cell callback
146 // Not triggered by a cell or widget (no get_cell callback
138 // exists).
147 // exists).
139 return null;
148 return null;
140 };
149 };
141
150
142 WidgetManager.prototype.callbacks = function (view) {
151 WidgetManager.prototype.callbacks = function (view) {
143 // callback handlers specific a view
152 // callback handlers specific a view
144 var callbacks = {};
153 var callbacks = {};
145 var cell = view.options.cell;
154 var cell = view.options.cell;
146 if (cell !== null) {
155 if (cell !== null) {
147 // Try to get output handlers
156 // Try to get output handlers
148 var handle_output = null;
157 var handle_output = null;
149 var handle_clear_output = null;
158 var handle_clear_output = null;
150 if (cell.output_area !== undefined && cell.output_area !== null) {
159 if (cell.output_area !== undefined && cell.output_area !== null) {
151 handle_output = $.proxy(cell.output_area.handle_output, cell.output_area);
160 handle_output = $.proxy(cell.output_area.handle_output, cell.output_area);
152 handle_clear_output = $.proxy(cell.output_area.handle_clear_output, cell.output_area);
161 handle_clear_output = $.proxy(cell.output_area.handle_clear_output, cell.output_area);
153 }
162 }
154
163
155 // Create callback dict using what is known
164 // Create callback dict using what is known
156 var that = this;
165 var that = this;
157 callbacks = {
166 callbacks = {
158 iopub : {
167 iopub : {
159 output : handle_output,
168 output : handle_output,
160 clear_output : handle_clear_output,
169 clear_output : handle_clear_output,
161
170
162 status : function (msg) {
171 status : function (msg) {
163 view.model._handle_status(msg, that.callbacks(view));
172 view.model._handle_status(msg, that.callbacks(view));
164 },
173 },
165
174
166 // Special function only registered by widget messages.
175 // Special function only registered by widget messages.
167 // Allows us to get the cell for a message so we know
176 // Allows us to get the cell for a message so we know
168 // where to add widgets if the code requires it.
177 // where to add widgets if the code requires it.
169 get_cell : function () {
178 get_cell : function () {
170 return cell;
179 return cell;
171 },
180 },
172 },
181 },
173 };
182 };
174 }
183 }
175 return callbacks;
184 return callbacks;
176 };
185 };
177
186
178
179 WidgetManager.prototype.get_model = function (model_id) {
187 WidgetManager.prototype.get_model = function (model_id) {
180 var model = this._models[model_id];
188 var model = WidgetManager._models[model_id];
181 if (model !== undefined && model.id == model_id) {
189 if (model !== undefined && model.id == model_id) {
182 return model;
190 return model;
183 }
191 }
184 return null;
192 return null;
185 };
193 };
186
194
187
188 WidgetManager.prototype._handle_comm_open = function (comm, msg) {
195 WidgetManager.prototype._handle_comm_open = function (comm, msg) {
196 var model_id = comm.comm_id;
189 var widget_type_name = msg.content.target_name;
197 var widget_type_name = msg.content.target_name;
190 var widget_model = new this._model_types[widget_type_name](this, comm.comm_id, comm);
198 var widget_model = new WidgetManager._model_types[widget_type_name](this, model_id, comm);
191 this._models[comm.comm_id] = widget_model; // comm_id == model_id
199 WidgetManager._models[model_id] = widget_model;
192 };
200 };
193
201
194 //--------------------------------------------------------------------
195 // Init code
196 //--------------------------------------------------------------------
197 IPython.WidgetManager = WidgetManager;
202 IPython.WidgetManager = WidgetManager;
198 if (IPython.widget_manager === undefined || IPython.widget_manager === null) {
203 return IPython.WidgetManager;
199 IPython.widget_manager = new WidgetManager();
200 }
201
202 return IPython.widget_manager;
203 });
204 });
204 }());
205 }());
@@ -1,587 +1,585
1 //----------------------------------------------------------------------------
1 //----------------------------------------------------------------------------
2 // Copyright (C) 2008-2011 The IPython Development Team
2 // Copyright (C) 2008-2011 The IPython Development Team
3 //
3 //
4 // Distributed under the terms of the BSD License. The full license is in
4 // Distributed under the terms of the BSD License. The full license is in
5 // the file COPYING, distributed as part of this software.
5 // the file COPYING, distributed as part of this software.
6 //----------------------------------------------------------------------------
6 //----------------------------------------------------------------------------
7
7
8 //============================================================================
8 //============================================================================
9 // Kernel
9 // Kernel
10 //============================================================================
10 //============================================================================
11
11
12 /**
12 /**
13 * @module IPython
13 * @module IPython
14 * @namespace IPython
14 * @namespace IPython
15 * @submodule Kernel
15 * @submodule Kernel
16 */
16 */
17
17
18 var IPython = (function (IPython) {
18 var IPython = (function (IPython) {
19 "use strict";
19 "use strict";
20
20
21 var utils = IPython.utils;
21 var utils = IPython.utils;
22
22
23 // Initialization and connection.
23 // Initialization and connection.
24 /**
24 /**
25 * A Kernel Class to communicate with the Python kernel
25 * A Kernel Class to communicate with the Python kernel
26 * @Class Kernel
26 * @Class Kernel
27 */
27 */
28 var Kernel = function (base_url) {
28 var Kernel = function (base_url) {
29 this.kernel_id = null;
29 this.kernel_id = null;
30 this.shell_channel = null;
30 this.shell_channel = null;
31 this.iopub_channel = null;
31 this.iopub_channel = null;
32 this.stdin_channel = null;
32 this.stdin_channel = null;
33 this.base_url = base_url;
33 this.base_url = base_url;
34 this.running = false;
34 this.running = false;
35 this.username = "username";
35 this.username = "username";
36 this.session_id = utils.uuid();
36 this.session_id = utils.uuid();
37 this._msg_callbacks = {};
37 this._msg_callbacks = {};
38
38
39 if (typeof(WebSocket) !== 'undefined') {
39 if (typeof(WebSocket) !== 'undefined') {
40 this.WebSocket = WebSocket;
40 this.WebSocket = WebSocket;
41 } else if (typeof(MozWebSocket) !== 'undefined') {
41 } else if (typeof(MozWebSocket) !== 'undefined') {
42 this.WebSocket = MozWebSocket;
42 this.WebSocket = MozWebSocket;
43 } else {
43 } else {
44 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.');
44 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.');
45 }
45 }
46
46
47 this.bind_events();
47 this.bind_events();
48 this.init_iopub_handlers();
48 this.init_iopub_handlers();
49 this.comm_manager = new IPython.CommManager(this);
49 this.comm_manager = new IPython.CommManager(this);
50 // TODO: make the comm manager an arg to the widget manager initialization
50 this.widget_manager = new IPython.WidgetManager(this.comm_manager);
51 this.widget_manager = new IPython.WidgetManager();
52 this.widget_manager.attach_comm_manager(this.comm_manager);
53 };
51 };
54
52
55
53
56 Kernel.prototype._get_msg = function (msg_type, content, metadata) {
54 Kernel.prototype._get_msg = function (msg_type, content, metadata) {
57 var msg = {
55 var msg = {
58 header : {
56 header : {
59 msg_id : utils.uuid(),
57 msg_id : utils.uuid(),
60 username : this.username,
58 username : this.username,
61 session : this.session_id,
59 session : this.session_id,
62 msg_type : msg_type
60 msg_type : msg_type
63 },
61 },
64 metadata : metadata || {},
62 metadata : metadata || {},
65 content : content,
63 content : content,
66 parent_header : {}
64 parent_header : {}
67 };
65 };
68 return msg;
66 return msg;
69 };
67 };
70
68
71 Kernel.prototype.bind_events = function () {
69 Kernel.prototype.bind_events = function () {
72 var that = this;
70 var that = this;
73 $([IPython.events]).on('send_input_reply.Kernel', function(evt, data) {
71 $([IPython.events]).on('send_input_reply.Kernel', function(evt, data) {
74 that.send_input_reply(data);
72 that.send_input_reply(data);
75 });
73 });
76 };
74 };
77
75
78 // Initialize the iopub handlers
76 // Initialize the iopub handlers
79
77
80 Kernel.prototype.init_iopub_handlers = function () {
78 Kernel.prototype.init_iopub_handlers = function () {
81 var output_types = ['stream', 'display_data', 'pyout', 'pyerr'];
79 var output_types = ['stream', 'display_data', 'pyout', 'pyerr'];
82 this._iopub_handlers = {};
80 this._iopub_handlers = {};
83 this.register_iopub_handler('status', $.proxy(this._handle_status_message, this));
81 this.register_iopub_handler('status', $.proxy(this._handle_status_message, this));
84 this.register_iopub_handler('clear_output', $.proxy(this._handle_clear_output, this));
82 this.register_iopub_handler('clear_output', $.proxy(this._handle_clear_output, this));
85
83
86 for (var i=0; i < output_types.length; i++) {
84 for (var i=0; i < output_types.length; i++) {
87 this.register_iopub_handler(output_types[i], $.proxy(this._handle_output_message, this));
85 this.register_iopub_handler(output_types[i], $.proxy(this._handle_output_message, this));
88 }
86 }
89 };
87 };
90
88
91 /**
89 /**
92 * Start the Python kernel
90 * Start the Python kernel
93 * @method start
91 * @method start
94 */
92 */
95 Kernel.prototype.start = function (params) {
93 Kernel.prototype.start = function (params) {
96 params = params || {};
94 params = params || {};
97 if (!this.running) {
95 if (!this.running) {
98 var qs = $.param(params);
96 var qs = $.param(params);
99 var url = this.base_url + '?' + qs;
97 var url = this.base_url + '?' + qs;
100 $.post(url,
98 $.post(url,
101 $.proxy(this._kernel_started, this),
99 $.proxy(this._kernel_started, this),
102 'json'
100 'json'
103 );
101 );
104 }
102 }
105 };
103 };
106
104
107 /**
105 /**
108 * Restart the python kernel.
106 * Restart the python kernel.
109 *
107 *
110 * Emit a 'status_restarting.Kernel' event with
108 * Emit a 'status_restarting.Kernel' event with
111 * the current object as parameter
109 * the current object as parameter
112 *
110 *
113 * @method restart
111 * @method restart
114 */
112 */
115 Kernel.prototype.restart = function () {
113 Kernel.prototype.restart = function () {
116 $([IPython.events]).trigger('status_restarting.Kernel', {kernel: this});
114 $([IPython.events]).trigger('status_restarting.Kernel', {kernel: this});
117 if (this.running) {
115 if (this.running) {
118 this.stop_channels();
116 this.stop_channels();
119 var url = utils.url_join_encode(this.kernel_url, "restart");
117 var url = utils.url_join_encode(this.kernel_url, "restart");
120 $.post(url,
118 $.post(url,
121 $.proxy(this._kernel_started, this),
119 $.proxy(this._kernel_started, this),
122 'json'
120 'json'
123 );
121 );
124 }
122 }
125 };
123 };
126
124
127
125
128 Kernel.prototype._kernel_started = function (json) {
126 Kernel.prototype._kernel_started = function (json) {
129 console.log("Kernel started: ", json.id);
127 console.log("Kernel started: ", json.id);
130 this.running = true;
128 this.running = true;
131 this.kernel_id = json.id;
129 this.kernel_id = json.id;
132 var ws_url = json.ws_url;
130 var ws_url = json.ws_url;
133 if (ws_url.match(/wss?:\/\//) === null) {
131 if (ws_url.match(/wss?:\/\//) === null) {
134 // trailing 's' in https will become wss for secure web sockets
132 // trailing 's' in https will become wss for secure web sockets
135 var prot = location.protocol.replace('http', 'ws') + "//";
133 var prot = location.protocol.replace('http', 'ws') + "//";
136 ws_url = prot + location.host + ws_url;
134 ws_url = prot + location.host + ws_url;
137 }
135 }
138 this.ws_url = ws_url;
136 this.ws_url = ws_url;
139 this.kernel_url = utils.url_join_encode(this.base_url, this.kernel_id);
137 this.kernel_url = utils.url_join_encode(this.base_url, this.kernel_id);
140 this.start_channels();
138 this.start_channels();
141 };
139 };
142
140
143
141
144 Kernel.prototype._websocket_closed = function(ws_url, early) {
142 Kernel.prototype._websocket_closed = function(ws_url, early) {
145 this.stop_channels();
143 this.stop_channels();
146 $([IPython.events]).trigger('websocket_closed.Kernel',
144 $([IPython.events]).trigger('websocket_closed.Kernel',
147 {ws_url: ws_url, kernel: this, early: early}
145 {ws_url: ws_url, kernel: this, early: early}
148 );
146 );
149 };
147 };
150
148
151 /**
149 /**
152 * Start the `shell`and `iopub` channels.
150 * Start the `shell`and `iopub` channels.
153 * Will stop and restart them if they already exist.
151 * Will stop and restart them if they already exist.
154 *
152 *
155 * @method start_channels
153 * @method start_channels
156 */
154 */
157 Kernel.prototype.start_channels = function () {
155 Kernel.prototype.start_channels = function () {
158 var that = this;
156 var that = this;
159 this.stop_channels();
157 this.stop_channels();
160 var ws_url = this.ws_url + this.kernel_url;
158 var ws_url = this.ws_url + this.kernel_url;
161 console.log("Starting WebSockets:", ws_url);
159 console.log("Starting WebSockets:", ws_url);
162 this.shell_channel = new this.WebSocket(ws_url + "/shell");
160 this.shell_channel = new this.WebSocket(ws_url + "/shell");
163 this.stdin_channel = new this.WebSocket(ws_url + "/stdin");
161 this.stdin_channel = new this.WebSocket(ws_url + "/stdin");
164 this.iopub_channel = new this.WebSocket(ws_url + "/iopub");
162 this.iopub_channel = new this.WebSocket(ws_url + "/iopub");
165
163
166 var already_called_onclose = false; // only alert once
164 var already_called_onclose = false; // only alert once
167 var ws_closed_early = function(evt){
165 var ws_closed_early = function(evt){
168 if (already_called_onclose){
166 if (already_called_onclose){
169 return;
167 return;
170 }
168 }
171 already_called_onclose = true;
169 already_called_onclose = true;
172 if ( ! evt.wasClean ){
170 if ( ! evt.wasClean ){
173 that._websocket_closed(ws_url, true);
171 that._websocket_closed(ws_url, true);
174 }
172 }
175 };
173 };
176 var ws_closed_late = function(evt){
174 var ws_closed_late = function(evt){
177 if (already_called_onclose){
175 if (already_called_onclose){
178 return;
176 return;
179 }
177 }
180 already_called_onclose = true;
178 already_called_onclose = true;
181 if ( ! evt.wasClean ){
179 if ( ! evt.wasClean ){
182 that._websocket_closed(ws_url, false);
180 that._websocket_closed(ws_url, false);
183 }
181 }
184 };
182 };
185 var channels = [this.shell_channel, this.iopub_channel, this.stdin_channel];
183 var channels = [this.shell_channel, this.iopub_channel, this.stdin_channel];
186 for (var i=0; i < channels.length; i++) {
184 for (var i=0; i < channels.length; i++) {
187 channels[i].onopen = $.proxy(this._ws_opened, this);
185 channels[i].onopen = $.proxy(this._ws_opened, this);
188 channels[i].onclose = ws_closed_early;
186 channels[i].onclose = ws_closed_early;
189 }
187 }
190 // switch from early-close to late-close message after 1s
188 // switch from early-close to late-close message after 1s
191 setTimeout(function() {
189 setTimeout(function() {
192 for (var i=0; i < channels.length; i++) {
190 for (var i=0; i < channels.length; i++) {
193 if (channels[i] !== null) {
191 if (channels[i] !== null) {
194 channels[i].onclose = ws_closed_late;
192 channels[i].onclose = ws_closed_late;
195 }
193 }
196 }
194 }
197 }, 1000);
195 }, 1000);
198 this.shell_channel.onmessage = $.proxy(this._handle_shell_reply, this);
196 this.shell_channel.onmessage = $.proxy(this._handle_shell_reply, this);
199 this.iopub_channel.onmessage = $.proxy(this._handle_iopub_message, this);
197 this.iopub_channel.onmessage = $.proxy(this._handle_iopub_message, this);
200 this.stdin_channel.onmessage = $.proxy(this._handle_input_request, this);
198 this.stdin_channel.onmessage = $.proxy(this._handle_input_request, this);
201 };
199 };
202
200
203 /**
201 /**
204 * Handle a websocket entering the open state
202 * Handle a websocket entering the open state
205 * sends session and cookie authentication info as first message.
203 * sends session and cookie authentication info as first message.
206 * Once all sockets are open, signal the Kernel.status_started event.
204 * Once all sockets are open, signal the Kernel.status_started event.
207 * @method _ws_opened
205 * @method _ws_opened
208 */
206 */
209 Kernel.prototype._ws_opened = function (evt) {
207 Kernel.prototype._ws_opened = function (evt) {
210 // send the session id so the Session object Python-side
208 // send the session id so the Session object Python-side
211 // has the same identity
209 // has the same identity
212 evt.target.send(this.session_id + ':' + document.cookie);
210 evt.target.send(this.session_id + ':' + document.cookie);
213
211
214 var channels = [this.shell_channel, this.iopub_channel, this.stdin_channel];
212 var channels = [this.shell_channel, this.iopub_channel, this.stdin_channel];
215 for (var i=0; i < channels.length; i++) {
213 for (var i=0; i < channels.length; i++) {
216 // if any channel is not ready, don't trigger event.
214 // if any channel is not ready, don't trigger event.
217 if ( !channels[i].readyState ) return;
215 if ( !channels[i].readyState ) return;
218 }
216 }
219 // all events ready, trigger started event.
217 // all events ready, trigger started event.
220 $([IPython.events]).trigger('status_started.Kernel', {kernel: this});
218 $([IPython.events]).trigger('status_started.Kernel', {kernel: this});
221 };
219 };
222
220
223 /**
221 /**
224 * Stop the websocket channels.
222 * Stop the websocket channels.
225 * @method stop_channels
223 * @method stop_channels
226 */
224 */
227 Kernel.prototype.stop_channels = function () {
225 Kernel.prototype.stop_channels = function () {
228 var channels = [this.shell_channel, this.iopub_channel, this.stdin_channel];
226 var channels = [this.shell_channel, this.iopub_channel, this.stdin_channel];
229 for (var i=0; i < channels.length; i++) {
227 for (var i=0; i < channels.length; i++) {
230 if ( channels[i] !== null ) {
228 if ( channels[i] !== null ) {
231 channels[i].onclose = null;
229 channels[i].onclose = null;
232 channels[i].close();
230 channels[i].close();
233 }
231 }
234 }
232 }
235 this.shell_channel = this.iopub_channel = this.stdin_channel = null;
233 this.shell_channel = this.iopub_channel = this.stdin_channel = null;
236 };
234 };
237
235
238 // Main public methods.
236 // Main public methods.
239
237
240 // send a message on the Kernel's shell channel
238 // send a message on the Kernel's shell channel
241 Kernel.prototype.send_shell_message = function (msg_type, content, callbacks, metadata) {
239 Kernel.prototype.send_shell_message = function (msg_type, content, callbacks, metadata) {
242 var msg = this._get_msg(msg_type, content, metadata);
240 var msg = this._get_msg(msg_type, content, metadata);
243 this.shell_channel.send(JSON.stringify(msg));
241 this.shell_channel.send(JSON.stringify(msg));
244 this.set_callbacks_for_msg(msg.header.msg_id, callbacks);
242 this.set_callbacks_for_msg(msg.header.msg_id, callbacks);
245 return msg.header.msg_id;
243 return msg.header.msg_id;
246 };
244 };
247
245
248 /**
246 /**
249 * Get info on an object
247 * Get info on an object
250 *
248 *
251 * @param objname {string}
249 * @param objname {string}
252 * @param callback {function}
250 * @param callback {function}
253 * @method object_info
251 * @method object_info
254 *
252 *
255 * When calling this method, pass a callback function that expects one argument.
253 * When calling this method, pass a callback function that expects one argument.
256 * The callback will be passed the complete `object_info_reply` message documented
254 * The callback will be passed the complete `object_info_reply` message documented
257 * [here](http://ipython.org/ipython-doc/dev/development/messaging.html#object-information)
255 * [here](http://ipython.org/ipython-doc/dev/development/messaging.html#object-information)
258 */
256 */
259 Kernel.prototype.object_info = function (objname, callback) {
257 Kernel.prototype.object_info = function (objname, callback) {
260 var callbacks;
258 var callbacks;
261 if (callback) {
259 if (callback) {
262 callbacks = { shell : { reply : callback } };
260 callbacks = { shell : { reply : callback } };
263 }
261 }
264
262
265 if (typeof(objname) !== null && objname !== null) {
263 if (typeof(objname) !== null && objname !== null) {
266 var content = {
264 var content = {
267 oname : objname.toString(),
265 oname : objname.toString(),
268 detail_level : 0,
266 detail_level : 0,
269 };
267 };
270 return this.send_shell_message("object_info_request", content, callbacks);
268 return this.send_shell_message("object_info_request", content, callbacks);
271 }
269 }
272 return;
270 return;
273 };
271 };
274
272
275 /**
273 /**
276 * Execute given code into kernel, and pass result to callback.
274 * Execute given code into kernel, and pass result to callback.
277 *
275 *
278 * @async
276 * @async
279 * @method execute
277 * @method execute
280 * @param {string} code
278 * @param {string} code
281 * @param [callbacks] {Object} With the following keys (all optional)
279 * @param [callbacks] {Object} With the following keys (all optional)
282 * @param callbacks.shell.reply {function}
280 * @param callbacks.shell.reply {function}
283 * @param callbacks.shell.payload.[payload_name] {function}
281 * @param callbacks.shell.payload.[payload_name] {function}
284 * @param callbacks.iopub.output {function}
282 * @param callbacks.iopub.output {function}
285 * @param callbacks.iopub.clear_output {function}
283 * @param callbacks.iopub.clear_output {function}
286 * @param callbacks.input {function}
284 * @param callbacks.input {function}
287 * @param {object} [options]
285 * @param {object} [options]
288 * @param [options.silent=false] {Boolean}
286 * @param [options.silent=false] {Boolean}
289 * @param [options.user_expressions=empty_dict] {Dict}
287 * @param [options.user_expressions=empty_dict] {Dict}
290 * @param [options.user_variables=empty_list] {List od Strings}
288 * @param [options.user_variables=empty_list] {List od Strings}
291 * @param [options.allow_stdin=false] {Boolean} true|false
289 * @param [options.allow_stdin=false] {Boolean} true|false
292 *
290 *
293 * @example
291 * @example
294 *
292 *
295 * The options object should contain the options for the execute call. Its default
293 * The options object should contain the options for the execute call. Its default
296 * values are:
294 * values are:
297 *
295 *
298 * options = {
296 * options = {
299 * silent : true,
297 * silent : true,
300 * user_variables : [],
298 * user_variables : [],
301 * user_expressions : {},
299 * user_expressions : {},
302 * allow_stdin : false
300 * allow_stdin : false
303 * }
301 * }
304 *
302 *
305 * When calling this method pass a callbacks structure of the form:
303 * When calling this method pass a callbacks structure of the form:
306 *
304 *
307 * callbacks = {
305 * callbacks = {
308 * shell : {
306 * shell : {
309 * reply : execute_reply_callback,
307 * reply : execute_reply_callback,
310 * payload : {
308 * payload : {
311 * set_next_input : set_next_input_callback,
309 * set_next_input : set_next_input_callback,
312 * }
310 * }
313 * },
311 * },
314 * iopub : {
312 * iopub : {
315 * output : output_callback,
313 * output : output_callback,
316 * clear_output : clear_output_callback,
314 * clear_output : clear_output_callback,
317 * },
315 * },
318 * input : raw_input_callback
316 * input : raw_input_callback
319 * }
317 * }
320 *
318 *
321 * Each callback will be passed the entire message as a single arugment.
319 * Each callback will be passed the entire message as a single arugment.
322 * Payload handlers will be passed the corresponding payload and the execute_reply message.
320 * Payload handlers will be passed the corresponding payload and the execute_reply message.
323 */
321 */
324 Kernel.prototype.execute = function (code, callbacks, options) {
322 Kernel.prototype.execute = function (code, callbacks, options) {
325
323
326 var content = {
324 var content = {
327 code : code,
325 code : code,
328 silent : true,
326 silent : true,
329 store_history : false,
327 store_history : false,
330 user_variables : [],
328 user_variables : [],
331 user_expressions : {},
329 user_expressions : {},
332 allow_stdin : false
330 allow_stdin : false
333 };
331 };
334 callbacks = callbacks || {};
332 callbacks = callbacks || {};
335 if (callbacks.input !== undefined) {
333 if (callbacks.input !== undefined) {
336 content.allow_stdin = true;
334 content.allow_stdin = true;
337 }
335 }
338 $.extend(true, content, options);
336 $.extend(true, content, options);
339 $([IPython.events]).trigger('execution_request.Kernel', {kernel: this, content:content});
337 $([IPython.events]).trigger('execution_request.Kernel', {kernel: this, content:content});
340 return this.send_shell_message("execute_request", content, callbacks);
338 return this.send_shell_message("execute_request", content, callbacks);
341 };
339 };
342
340
343 /**
341 /**
344 * When calling this method, pass a function to be called with the `complete_reply` message
342 * When calling this method, pass a function to be called with the `complete_reply` message
345 * as its only argument when it arrives.
343 * as its only argument when it arrives.
346 *
344 *
347 * `complete_reply` is documented
345 * `complete_reply` is documented
348 * [here](http://ipython.org/ipython-doc/dev/development/messaging.html#complete)
346 * [here](http://ipython.org/ipython-doc/dev/development/messaging.html#complete)
349 *
347 *
350 * @method complete
348 * @method complete
351 * @param line {integer}
349 * @param line {integer}
352 * @param cursor_pos {integer}
350 * @param cursor_pos {integer}
353 * @param callback {function}
351 * @param callback {function}
354 *
352 *
355 */
353 */
356 Kernel.prototype.complete = function (line, cursor_pos, callback) {
354 Kernel.prototype.complete = function (line, cursor_pos, callback) {
357 var callbacks;
355 var callbacks;
358 if (callback) {
356 if (callback) {
359 callbacks = { shell : { reply : callback } };
357 callbacks = { shell : { reply : callback } };
360 }
358 }
361 var content = {
359 var content = {
362 text : '',
360 text : '',
363 line : line,
361 line : line,
364 block : null,
362 block : null,
365 cursor_pos : cursor_pos
363 cursor_pos : cursor_pos
366 };
364 };
367 return this.send_shell_message("complete_request", content, callbacks);
365 return this.send_shell_message("complete_request", content, callbacks);
368 };
366 };
369
367
370
368
371 Kernel.prototype.interrupt = function () {
369 Kernel.prototype.interrupt = function () {
372 if (this.running) {
370 if (this.running) {
373 $([IPython.events]).trigger('status_interrupting.Kernel', {kernel: this});
371 $([IPython.events]).trigger('status_interrupting.Kernel', {kernel: this});
374 $.post(this.kernel_url + "/interrupt");
372 $.post(this.kernel_url + "/interrupt");
375 }
373 }
376 };
374 };
377
375
378
376
379 Kernel.prototype.kill = function () {
377 Kernel.prototype.kill = function () {
380 if (this.running) {
378 if (this.running) {
381 this.running = false;
379 this.running = false;
382 var settings = {
380 var settings = {
383 cache : false,
381 cache : false,
384 type : "DELETE"
382 type : "DELETE"
385 };
383 };
386 $.ajax(this.kernel_url, settings);
384 $.ajax(this.kernel_url, settings);
387 }
385 }
388 };
386 };
389
387
390 Kernel.prototype.send_input_reply = function (input) {
388 Kernel.prototype.send_input_reply = function (input) {
391 var content = {
389 var content = {
392 value : input,
390 value : input,
393 };
391 };
394 $([IPython.events]).trigger('input_reply.Kernel', {kernel: this, content:content});
392 $([IPython.events]).trigger('input_reply.Kernel', {kernel: this, content:content});
395 var msg = this._get_msg("input_reply", content);
393 var msg = this._get_msg("input_reply", content);
396 this.stdin_channel.send(JSON.stringify(msg));
394 this.stdin_channel.send(JSON.stringify(msg));
397 return msg.header.msg_id;
395 return msg.header.msg_id;
398 };
396 };
399
397
400
398
401 // Reply handlers
399 // Reply handlers
402
400
403 Kernel.prototype.register_iopub_handler = function (msg_type, callback) {
401 Kernel.prototype.register_iopub_handler = function (msg_type, callback) {
404 this._iopub_handlers[msg_type] = callback;
402 this._iopub_handlers[msg_type] = callback;
405 };
403 };
406
404
407 Kernel.prototype.get_iopub_handler = function (msg_type) {
405 Kernel.prototype.get_iopub_handler = function (msg_type) {
408 // get iopub handler for a specific message type
406 // get iopub handler for a specific message type
409 return this._iopub_handlers[msg_type];
407 return this._iopub_handlers[msg_type];
410 };
408 };
411
409
412
410
413 Kernel.prototype.get_callbacks_for_msg = function (msg_id) {
411 Kernel.prototype.get_callbacks_for_msg = function (msg_id) {
414 // get callbacks for a specific message
412 // get callbacks for a specific message
415 return this._msg_callbacks[msg_id];
413 return this._msg_callbacks[msg_id];
416 };
414 };
417
415
418
416
419 Kernel.prototype.clear_callbacks_for_msg = function (msg_id) {
417 Kernel.prototype.clear_callbacks_for_msg = function (msg_id) {
420 if (this._msg_callbacks[msg_id] !== undefined ) {
418 if (this._msg_callbacks[msg_id] !== undefined ) {
421 delete this._msg_callbacks[msg_id];
419 delete this._msg_callbacks[msg_id];
422 }
420 }
423 };
421 };
424
422
425 /* Set callbacks for a particular message.
423 /* Set callbacks for a particular message.
426 * Callbacks should be a struct of the following form:
424 * Callbacks should be a struct of the following form:
427 * shell : {
425 * shell : {
428 *
426 *
429 * }
427 * }
430
428
431 */
429 */
432 Kernel.prototype.set_callbacks_for_msg = function (msg_id, callbacks) {
430 Kernel.prototype.set_callbacks_for_msg = function (msg_id, callbacks) {
433 if (callbacks) {
431 if (callbacks) {
434 // shallow-copy mapping, because we will modify it at the top level
432 // shallow-copy mapping, because we will modify it at the top level
435 var cbcopy = this._msg_callbacks[msg_id] = {};
433 var cbcopy = this._msg_callbacks[msg_id] = {};
436 cbcopy.shell = callbacks.shell;
434 cbcopy.shell = callbacks.shell;
437 cbcopy.iopub = callbacks.iopub;
435 cbcopy.iopub = callbacks.iopub;
438 cbcopy.input = callbacks.input;
436 cbcopy.input = callbacks.input;
439 this._msg_callbacks[msg_id] = cbcopy;
437 this._msg_callbacks[msg_id] = cbcopy;
440 }
438 }
441 };
439 };
442
440
443
441
444 Kernel.prototype._handle_shell_reply = function (e) {
442 Kernel.prototype._handle_shell_reply = function (e) {
445 var reply = $.parseJSON(e.data);
443 var reply = $.parseJSON(e.data);
446 $([IPython.events]).trigger('shell_reply.Kernel', {kernel: this, reply:reply});
444 $([IPython.events]).trigger('shell_reply.Kernel', {kernel: this, reply:reply});
447 var content = reply.content;
445 var content = reply.content;
448 var metadata = reply.metadata;
446 var metadata = reply.metadata;
449 var parent_id = reply.parent_header.msg_id;
447 var parent_id = reply.parent_header.msg_id;
450 var callbacks = this.get_callbacks_for_msg(parent_id);
448 var callbacks = this.get_callbacks_for_msg(parent_id);
451 if (!callbacks || !callbacks.shell) {
449 if (!callbacks || !callbacks.shell) {
452 return;
450 return;
453 }
451 }
454 var shell_callbacks = callbacks.shell;
452 var shell_callbacks = callbacks.shell;
455
453
456 // clear callbacks on shell
454 // clear callbacks on shell
457 delete callbacks.shell;
455 delete callbacks.shell;
458 delete callbacks.input;
456 delete callbacks.input;
459 if (!callbacks.iopub) {
457 if (!callbacks.iopub) {
460 this.clear_callbacks_for_msg(parent_id);
458 this.clear_callbacks_for_msg(parent_id);
461 }
459 }
462
460
463 if (shell_callbacks.reply !== undefined) {
461 if (shell_callbacks.reply !== undefined) {
464 shell_callbacks.reply(reply);
462 shell_callbacks.reply(reply);
465 }
463 }
466 if (content.payload && shell_callbacks.payload) {
464 if (content.payload && shell_callbacks.payload) {
467 this._handle_payloads(content.payload, shell_callbacks.payload, reply);
465 this._handle_payloads(content.payload, shell_callbacks.payload, reply);
468 }
466 }
469 };
467 };
470
468
471
469
472 Kernel.prototype._handle_payloads = function (payloads, payload_callbacks, msg) {
470 Kernel.prototype._handle_payloads = function (payloads, payload_callbacks, msg) {
473 var l = payloads.length;
471 var l = payloads.length;
474 // Payloads are handled by triggering events because we don't want the Kernel
472 // Payloads are handled by triggering events because we don't want the Kernel
475 // to depend on the Notebook or Pager classes.
473 // to depend on the Notebook or Pager classes.
476 for (var i=0; i<l; i++) {
474 for (var i=0; i<l; i++) {
477 var payload = payloads[i];
475 var payload = payloads[i];
478 var callback = payload_callbacks[payload.source];
476 var callback = payload_callbacks[payload.source];
479 if (callback) {
477 if (callback) {
480 callback(payload, msg);
478 callback(payload, msg);
481 }
479 }
482 }
480 }
483 };
481 };
484
482
485 Kernel.prototype._handle_status_message = function (msg) {
483 Kernel.prototype._handle_status_message = function (msg) {
486 var execution_state = msg.content.execution_state;
484 var execution_state = msg.content.execution_state;
487 var parent_id = msg.parent_header.msg_id;
485 var parent_id = msg.parent_header.msg_id;
488
486
489 // dispatch status msg callbacks, if any
487 // dispatch status msg callbacks, if any
490 var callbacks = this.get_callbacks_for_msg(parent_id);
488 var callbacks = this.get_callbacks_for_msg(parent_id);
491 if (callbacks && callbacks.iopub && callbacks.iopub.status) {
489 if (callbacks && callbacks.iopub && callbacks.iopub.status) {
492 try {
490 try {
493 callbacks.iopub.status(msg);
491 callbacks.iopub.status(msg);
494 } catch (e) {
492 } catch (e) {
495 console.log("Exception in status msg handler", e, e.stack);
493 console.log("Exception in status msg handler", e, e.stack);
496 }
494 }
497 }
495 }
498
496
499 if (execution_state === 'busy') {
497 if (execution_state === 'busy') {
500 $([IPython.events]).trigger('status_busy.Kernel', {kernel: this});
498 $([IPython.events]).trigger('status_busy.Kernel', {kernel: this});
501 } else if (execution_state === 'idle') {
499 } else if (execution_state === 'idle') {
502 // clear callbacks on idle, there can be no more
500 // clear callbacks on idle, there can be no more
503 if (callbacks !== undefined) {
501 if (callbacks !== undefined) {
504 delete callbacks.iopub;
502 delete callbacks.iopub;
505 delete callbacks.input;
503 delete callbacks.input;
506 if (!callbacks.shell) {
504 if (!callbacks.shell) {
507 this.clear_callbacks_for_msg(parent_id);
505 this.clear_callbacks_for_msg(parent_id);
508 }
506 }
509 }
507 }
510 // trigger status_idle event
508 // trigger status_idle event
511 $([IPython.events]).trigger('status_idle.Kernel', {kernel: this});
509 $([IPython.events]).trigger('status_idle.Kernel', {kernel: this});
512 } else if (execution_state === 'restarting') {
510 } else if (execution_state === 'restarting') {
513 // autorestarting is distinct from restarting,
511 // autorestarting is distinct from restarting,
514 // in that it means the kernel died and the server is restarting it.
512 // in that it means the kernel died and the server is restarting it.
515 // status_restarting sets the notification widget,
513 // status_restarting sets the notification widget,
516 // autorestart shows the more prominent dialog.
514 // autorestart shows the more prominent dialog.
517 $([IPython.events]).trigger('status_autorestarting.Kernel', {kernel: this});
515 $([IPython.events]).trigger('status_autorestarting.Kernel', {kernel: this});
518 $([IPython.events]).trigger('status_restarting.Kernel', {kernel: this});
516 $([IPython.events]).trigger('status_restarting.Kernel', {kernel: this});
519 } else if (execution_state === 'dead') {
517 } else if (execution_state === 'dead') {
520 this.stop_channels();
518 this.stop_channels();
521 $([IPython.events]).trigger('status_dead.Kernel', {kernel: this});
519 $([IPython.events]).trigger('status_dead.Kernel', {kernel: this});
522 }
520 }
523 };
521 };
524
522
525
523
526 // handle clear_output message
524 // handle clear_output message
527 Kernel.prototype._handle_clear_output = function (msg) {
525 Kernel.prototype._handle_clear_output = function (msg) {
528 var callbacks = this.get_callbacks_for_msg(msg.parent_header.msg_id);
526 var callbacks = this.get_callbacks_for_msg(msg.parent_header.msg_id);
529 if (!callbacks || !callbacks.iopub) {
527 if (!callbacks || !callbacks.iopub) {
530 return;
528 return;
531 }
529 }
532 var callback = callbacks.iopub.clear_output;
530 var callback = callbacks.iopub.clear_output;
533 if (callback) {
531 if (callback) {
534 callback(msg);
532 callback(msg);
535 }
533 }
536 };
534 };
537
535
538
536
539 // handle an output message (pyout, display_data, etc.)
537 // handle an output message (pyout, display_data, etc.)
540 Kernel.prototype._handle_output_message = function (msg) {
538 Kernel.prototype._handle_output_message = function (msg) {
541 var callbacks = this.get_callbacks_for_msg(msg.parent_header.msg_id);
539 var callbacks = this.get_callbacks_for_msg(msg.parent_header.msg_id);
542 if (!callbacks || !callbacks.iopub) {
540 if (!callbacks || !callbacks.iopub) {
543 return;
541 return;
544 }
542 }
545 var callback = callbacks.iopub.output;
543 var callback = callbacks.iopub.output;
546 if (callback) {
544 if (callback) {
547 callback(msg);
545 callback(msg);
548 }
546 }
549 };
547 };
550
548
551 // dispatch IOPub messages to respective handlers.
549 // dispatch IOPub messages to respective handlers.
552 // each message type should have a handler.
550 // each message type should have a handler.
553 Kernel.prototype._handle_iopub_message = function (e) {
551 Kernel.prototype._handle_iopub_message = function (e) {
554 var msg = $.parseJSON(e.data);
552 var msg = $.parseJSON(e.data);
555
553
556 var handler = this.get_iopub_handler(msg.header.msg_type);
554 var handler = this.get_iopub_handler(msg.header.msg_type);
557 if (handler !== undefined) {
555 if (handler !== undefined) {
558 handler(msg);
556 handler(msg);
559 }
557 }
560 };
558 };
561
559
562
560
563 Kernel.prototype._handle_input_request = function (e) {
561 Kernel.prototype._handle_input_request = function (e) {
564 var request = $.parseJSON(e.data);
562 var request = $.parseJSON(e.data);
565 var header = request.header;
563 var header = request.header;
566 var content = request.content;
564 var content = request.content;
567 var metadata = request.metadata;
565 var metadata = request.metadata;
568 var msg_type = header.msg_type;
566 var msg_type = header.msg_type;
569 if (msg_type !== 'input_request') {
567 if (msg_type !== 'input_request') {
570 console.log("Invalid input request!", request);
568 console.log("Invalid input request!", request);
571 return;
569 return;
572 }
570 }
573 var callbacks = this.get_callbacks_for_msg(request.parent_header.msg_id);
571 var callbacks = this.get_callbacks_for_msg(request.parent_header.msg_id);
574 if (callbacks) {
572 if (callbacks) {
575 if (callbacks.input) {
573 if (callbacks.input) {
576 callbacks.input(request);
574 callbacks.input(request);
577 }
575 }
578 }
576 }
579 };
577 };
580
578
581
579
582 IPython.Kernel = Kernel;
580 IPython.Kernel = Kernel;
583
581
584 return IPython;
582 return IPython;
585
583
586 }(IPython));
584 }(IPython));
587
585
General Comments 0
You need to be logged in to leave comments. Login now