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