Merge pull request #4195 from minrk/widget-msg

IPEP 21:  widget messages
This commit is contained in:
Min RK 2013-10-24 12:19:41 -07:00
commit 0aaafce4af
10 changed files with 792 additions and 225 deletions

View File

@ -390,6 +390,18 @@ IPython.utils = (function (IPython) {
test.remove();
return Math.floor(points*pixel_per_point);
};
var always_new = function (constructor) {
// wrapper around contructor to avoid requiring `var a = new constructor()`
// useful for passing constructors as callbacks,
// not for programmer laziness.
// from http://programmers.stackexchange.com/questions/118798
return function () {
var obj = Object.create(constructor.prototype);
constructor.apply(obj, arguments);
return obj;
};
};
var url_path_join = function () {
@ -447,6 +459,7 @@ IPython.utils = (function (IPython) {
points_to_pixels : points_to_pixels,
url_path_join : url_path_join,
splitext : splitext,
always_new : always_new,
browser : browser
};

View File

@ -17,7 +17,7 @@
/* local util for codemirror */
var posEq = function(a, b) {return a.line == b.line && a.ch == b.ch;}
var posEq = function(a, b) {return a.line == b.line && a.ch == b.ch;};
/**
*
@ -27,16 +27,16 @@ var posEq = function(a, b) {return a.line == b.line && a.ch == b.ch;}
*/
CodeMirror.commands.delSpaceToPrevTabStop = function(cm){
var from = cm.getCursor(true), to = cm.getCursor(false), sel = !posEq(from, to);
if (!posEq(from, to)) {cm.replaceRange("", from, to); return}
if (!posEq(from, to)) { cm.replaceRange("", from, to); return; }
var cur = cm.getCursor(), line = cm.getLine(cur.line);
var tabsize = cm.getOption('tabSize');
var chToPrevTabStop = cur.ch-(Math.ceil(cur.ch/tabsize)-1)*tabsize;
var from = {ch:cur.ch-chToPrevTabStop,line:cur.line}
var select = cm.getRange(from,cur)
if( select.match(/^\ +$/) != null){
cm.replaceRange("",from,cur)
from = {ch:cur.ch-chToPrevTabStop,line:cur.line};
var select = cm.getRange(from,cur);
if( select.match(/^\ +$/) !== null){
cm.replaceRange("",from,cur);
} else {
cm.deleteH(-1,"char")
cm.deleteH(-1,"char");
}
};
@ -104,7 +104,7 @@ var IPython = (function (IPython) {
* @method auto_highlight
*/
CodeCell.prototype.auto_highlight = function () {
this._auto_highlight(IPython.config.cell_magic_highlight)
this._auto_highlight(IPython.config.cell_magic_highlight);
};
/** @method create_element */
@ -117,7 +117,7 @@ var IPython = (function (IPython) {
this.celltoolbar = new IPython.CellToolbar(this);
var input = $('<div></div>').addClass('input');
var vbox = $('<div/>').addClass('vbox box-flex1')
var vbox = $('<div/>').addClass('vbox box-flex1');
input.append($('<div/>').addClass('prompt input_prompt'));
vbox.append(this.celltoolbar.element);
var input_area = $('<div/>').addClass('input_area');
@ -152,7 +152,7 @@ var IPython = (function (IPython) {
// they are sent, and remove tooltip if any, except for tab again
if (event.type === 'keydown' && event.which != key.TAB ) {
IPython.tooltip.remove_and_cancel_tooltip();
};
}
var cur = editor.getCursor();
if (event.keyCode === key.ENTER){
@ -177,7 +177,7 @@ var IPython = (function (IPython) {
return false;
} else {
return true;
};
}
} else if (event.which === key.ESC) {
return IPython.tooltip.remove_and_cancel_tooltip(true);
} else if (event.which === key.DOWNARROW && event.type === 'keydown') {
@ -188,7 +188,7 @@ var IPython = (function (IPython) {
return false;
} else {
return true;
};
}
} else if (event.keyCode === key.TAB && event.type == 'keydown' && event.shiftKey) {
if (editor.somethingSelected()){
var anchor = editor.getCursor("anchor");
@ -203,7 +203,7 @@ var IPython = (function (IPython) {
} else if (event.keyCode === key.TAB && event.type == 'keydown') {
// Tab completion.
//Do not trim here because of tooltip
if (editor.somethingSelected()){return false}
if (editor.somethingSelected()) { return false; }
var pre_cursor = editor.getRange({line:cur.line,ch:0},cur);
if (pre_cursor.trim() === "") {
// Don't autocomplete if the part of the line before the cursor
@ -219,12 +219,12 @@ var IPython = (function (IPython) {
event.stop();
this.completer.startCompletion();
return true;
};
}
} else {
// keypress/keyup also trigger on TAB press, and we don't want to
// use those to disable tab completion.
return false;
};
}
return false;
};
@ -233,7 +233,7 @@ var IPython = (function (IPython) {
CodeCell.prototype.set_kernel = function (kernel) {
this.kernel = kernel;
}
};
/**
* Execute current code cell to the kernel
@ -243,42 +243,65 @@ var IPython = (function (IPython) {
this.output_area.clear_output();
this.set_input_prompt('*');
this.element.addClass("running");
var callbacks = {
'execute_reply': $.proxy(this._handle_execute_reply, this),
'output': $.proxy(this.output_area.handle_output, this.output_area),
'clear_output': $.proxy(this.output_area.handle_clear_output, this.output_area),
'set_next_input': $.proxy(this._handle_set_next_input, this),
'input_request': $.proxy(this._handle_input_request, this)
};
if (this.last_msg_id) {
this.kernel.clear_callbacks_for_msg(this.last_msg_id);
}
var callbacks = this.get_callbacks();
this.last_msg_id = this.kernel.execute(this.get_text(), callbacks, {silent: false, store_history: true});
};
/**
* Construct the default callbacks for
* @method get_callbacks
*/
CodeCell.prototype.get_callbacks = function () {
return {
shell : {
reply : $.proxy(this._handle_execute_reply, this),
payload : {
set_next_input : $.proxy(this._handle_set_next_input, this),
page : $.proxy(this._open_with_pager, this)
}
},
iopub : {
output : $.proxy(this.output_area.handle_output, this.output_area),
clear_output : $.proxy(this.output_area.handle_clear_output, this.output_area),
},
input : $.proxy(this._handle_input_request, this)
};
};
CodeCell.prototype._open_with_pager = function (payload) {
$([IPython.events]).trigger('open_with_text.Pager', payload);
};
/**
* @method _handle_execute_reply
* @private
*/
CodeCell.prototype._handle_execute_reply = function (content) {
this.set_input_prompt(content.execution_count);
CodeCell.prototype._handle_execute_reply = function (msg) {
this.set_input_prompt(msg.content.execution_count);
this.element.removeClass("running");
$([IPython.events]).trigger('set_dirty.Notebook', {value: true});
}
};
/**
* @method _handle_set_next_input
* @private
*/
CodeCell.prototype._handle_set_next_input = function (text) {
var data = {'cell': this, 'text': text}
CodeCell.prototype._handle_set_next_input = function (payload) {
var data = {'cell': this, 'text': payload.text};
$([IPython.events]).trigger('set_next_input.Notebook', data);
}
};
/**
* @method _handle_input_request
* @private
*/
CodeCell.prototype._handle_input_request = function (content) {
this.output_area.append_raw_input(content);
}
CodeCell.prototype._handle_input_request = function (msg) {
this.output_area.append_raw_input(msg);
};
// Basic cell manipulation.
@ -328,21 +351,23 @@ var IPython = (function (IPython) {
CodeCell.input_prompt_classical = function (prompt_value, lines_number) {
var ns = prompt_value || "&nbsp;";
return 'In&nbsp;[' + ns + ']:'
return 'In&nbsp;[' + ns + ']:';
};
CodeCell.input_prompt_continuation = function (prompt_value, lines_number) {
var html = [CodeCell.input_prompt_classical(prompt_value, lines_number)];
for(var i=1; i < lines_number; i++){html.push(['...:'])};
return html.join('</br>')
for(var i=1; i < lines_number; i++) {
html.push(['...:']);
}
return html.join('<br/>');
};
CodeCell.input_prompt_function = CodeCell.input_prompt_classical;
CodeCell.prototype.set_input_prompt = function (number) {
var nline = 1
if( this.code_mirror != undefined) {
var nline = 1;
if (this.code_mirror !== undefined) {
nline = this.code_mirror.lineCount();
}
this.input_prompt_number = number;
@ -407,16 +432,16 @@ var IPython = (function (IPython) {
this.set_input_prompt(data.prompt_number);
} else {
this.set_input_prompt();
};
}
this.output_area.fromJSON(data.outputs);
if (data.collapsed !== undefined) {
if (data.collapsed) {
this.collapse();
} else {
this.expand();
};
};
};
}
}
}
};
@ -426,7 +451,7 @@ var IPython = (function (IPython) {
data.cell_type = 'code';
if (this.input_prompt_number) {
data.prompt_number = this.input_prompt_number;
};
}
var outputs = this.output_area.toJSON();
data.outputs = outputs;
data.language = 'python';
@ -438,4 +463,4 @@ var IPython = (function (IPython) {
IPython.CodeCell = CodeCell;
return IPython;
}(IPython));
}(IPython));

View File

@ -150,16 +150,14 @@ var IPython = (function (IPython) {
matched_text: ""
})
} else {
var callbacks = {
'complete_reply': $.proxy(this.finish_completing, this)
};
this.cell.kernel.complete(line, cur.ch, callbacks);
this.cell.kernel.complete(line, cur.ch, $.proxy(this.finish_completing, this));
}
};
Completer.prototype.finish_completing = function (content) {
Completer.prototype.finish_completing = function (msg) {
// let's build a function that wrap all that stuff into what is needed
// for the new completer:
var content = msg.content;
var matched_text = content.matched_text;
var matches = content.matches;

View File

@ -96,7 +96,7 @@ function (marked) {
// only do this once
$([IPython.events]).off('notebook_loaded.Notebook', first_load);
};
$([IPython.events]).on('notebook_loaded.Notebook', first_load);
$([IPython.events]).trigger('app_initialized.NotebookApp');
IPython.notebook.load_notebook(notebookName, notebookPath);

View File

@ -231,9 +231,10 @@ var IPython = (function (IPython) {
};
OutputArea.prototype.handle_output = function (msg_type, content) {
OutputArea.prototype.handle_output = function (msg) {
var json = {};
json.output_type = msg_type;
var msg_type = json.output_type = msg.header.msg_type;
var content = msg.content;
if (msg_type === "stream") {
json.text = content.data;
json.stream = content.name;
@ -564,9 +565,10 @@ var IPython = (function (IPython) {
element.append(toinsert);
};
OutputArea.prototype.append_raw_input = function (content) {
OutputArea.prototype.append_raw_input = function (msg) {
var that = this;
this.expand();
var content = msg.content;
var area = this.create_output_area();
// disable any other raw_inputs, if they are left around
@ -618,8 +620,8 @@ var IPython = (function (IPython) {
}
OutputArea.prototype.handle_clear_output = function (content) {
this.clear_output(content.wait);
OutputArea.prototype.handle_clear_output = function (msg) {
this.clear_output(msg.content.wait);
};

View File

@ -218,16 +218,15 @@ var IPython = (function (IPython) {
// remove everything after last open bracket
line = line.replace(endBracket, "");
return Tooltip.last_token_re.exec(line)
}
};
Tooltip.prototype._request_tooltip = function (cell, line) {
var callbacks = {
'object_info_reply': $.proxy(this._show, this)
}
var callbacks = { shell : {
reply : $.proxy(this._show, this)
}};
var oir_token = this.extract_oir_token(line);
var msg_id = cell.kernel.object_info_request(oir_token, callbacks);
}
};
// make an imediate completion request
Tooltip.prototype.request = function (cell, hide_if_no_docstring) {
@ -301,7 +300,8 @@ var IPython = (function (IPython) {
Tooltip.prototype._show = function (reply) {
// move the bubble if it is not hidden
// otherwise fade it
this.name = reply.name;
var content = reply.content;
this.name = content.name;
// do some math to have the tooltip arrow on more or less on left or right
// width of the editor
@ -334,20 +334,20 @@ var IPython = (function (IPython) {
});
// build docstring
var defstring = reply.call_def;
var defstring = content.call_def;
if (defstring == null) {
defstring = reply.init_definition;
defstring = content.init_definition;
}
if (defstring == null) {
defstring = reply.definition;
defstring = content.definition;
}
var docstring = reply.call_docstring;
var docstring = content.call_docstring;
if (docstring == null) {
docstring = reply.init_docstring;
docstring = content.init_docstring;
}
if (docstring == null) {
docstring = reply.docstring;
docstring = content.docstring;
}
if (docstring == null) {

View File

@ -0,0 +1,198 @@
//----------------------------------------------------------------------------
// Copyright (C) 2013 The IPython Development Team
//
// Distributed under the terms of the BSD License. The full license is in
// the file COPYING, distributed as part of this software.
//----------------------------------------------------------------------------
//============================================================================
// Comm and CommManager bases
//============================================================================
/**
* Base Comm classes
* @module IPython
* @namespace IPython
* @submodule comm
*/
var IPython = (function (IPython) {
"use strict";
//-----------------------------------------------------------------------
// CommManager class
//-----------------------------------------------------------------------
var CommManager = function (kernel) {
this.comms = {};
this.targets = {};
if (kernel !== undefined) {
this.init_kernel(kernel);
}
};
CommManager.prototype.init_kernel = function (kernel) {
// connect the kernel, and register message handlers
this.kernel = kernel;
var msg_types = ['comm_open', 'comm_msg', 'comm_close'];
for (var i = 0; i < msg_types.length; i++) {
var msg_type = msg_types[i];
kernel.register_iopub_handler(msg_type, $.proxy(this[msg_type], this));
}
};
CommManager.prototype.new_comm = function (target_name, data, callbacks, metadata) {
// Create a new Comm, register it, and open its Kernel-side counterpart
// Mimics the auto-registration in `Comm.__init__` in the IPython Comm
var comm = new Comm(target_name);
this.register_comm(comm);
comm.open(data, callbacks, metadata);
return comm;
};
CommManager.prototype.register_target = function (target_name, f) {
// Register a target function for a given target name
this.targets[target_name] = f;
};
CommManager.prototype.unregister_target = function (target_name, f) {
// Unregister a target function for a given target name
delete this.targets[target_name];
};
CommManager.prototype.register_comm = function (comm) {
// Register a comm in the mapping
this.comms[comm.comm_id] = comm;
comm.kernel = this.kernel;
return comm.comm_id;
};
CommManager.prototype.unregister_comm = function (comm_id) {
// Remove a comm from the mapping
delete this.comms[comm_id];
};
// comm message handlers
CommManager.prototype.comm_open = function (msg) {
var content = msg.content;
var f = this.targets[content.target_name];
if (f === undefined) {
console.log("No such target registered: ", content.target_name);
console.log("Available targets are: ", this.targets);
return;
}
var comm = new Comm(content.target_name, content.comm_id);
this.register_comm(comm);
try {
f(comm, msg);
} catch (e) {
console.log("Exception opening new comm:", e, msg);
comm.close();
this.unregister_comm(comm);
}
};
CommManager.prototype.comm_close = function (msg) {
var content = msg.content;
var comm = this.comms[content.comm_id];
if (comm === undefined) {
return;
}
delete this.comms[content.comm_id];
try {
comm.handle_close(msg);
} catch (e) {
console.log("Exception closing comm: ", e, msg);
}
};
CommManager.prototype.comm_msg = function (msg) {
var content = msg.content;
var comm = this.comms[content.comm_id];
if (comm === undefined) {
return;
}
try {
comm.handle_msg(msg);
} catch (e) {
console.log("Exception handling comm msg: ", e, msg);
}
};
//-----------------------------------------------------------------------
// Comm base class
//-----------------------------------------------------------------------
var Comm = function (target_name, comm_id) {
this.target_name = target_name;
this.comm_id = comm_id || IPython.utils.uuid();
this._msg_callback = this._close_callback = null;
};
// methods for sending messages
Comm.prototype.open = function (data, callbacks, metadata) {
var content = {
comm_id : this.comm_id,
target_name : this.target_name,
data : data || {},
};
return this.kernel.send_shell_message("comm_open", content, callbacks, metadata);
};
Comm.prototype.send = function (data, callbacks, metadata) {
var content = {
comm_id : this.comm_id,
data : data || {},
};
return this.kernel.send_shell_message("comm_msg", content, callbacks, metadata);
};
Comm.prototype.close = function (data, callbacks, metadata) {
var content = {
comm_id : this.comm_id,
data : data || {},
};
return this.kernel.send_shell_message("comm_close", content, callbacks, metadata);
};
// methods for registering callbacks for incoming messages
Comm.prototype._register_callback = function (key, callback) {
this['_' + key + '_callback'] = callback;
};
Comm.prototype.on_msg = function (callback) {
this._register_callback('msg', callback);
};
Comm.prototype.on_close = function (callback) {
this._register_callback('close', callback);
};
// methods for handling incoming messages
Comm.prototype._maybe_callback = function (key, msg) {
var callback = this['_' + key + '_callback'];
if (callback) {
try {
callback(msg);
} catch (e) {
console.log("Exception in Comm callback", e, msg);
}
}
};
Comm.prototype.handle_msg = function (msg) {
this._maybe_callback('msg', msg);
};
Comm.prototype.handle_close = function (msg) {
this._maybe_callback('close', msg);
};
IPython.CommManager = CommManager;
IPython.Comm = Comm;
return IPython;
}(IPython));

View File

@ -16,7 +16,8 @@
*/
var IPython = (function (IPython) {
"use strict";
var utils = IPython.utils;
// Initialization and connection.
@ -41,12 +42,15 @@ var IPython = (function (IPython) {
this.WebSocket = MozWebSocket;
} else {
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.');
};
}
this.bind_events();
this.init_iopub_handlers();
this.comm_manager = new IPython.CommManager(this);
};
Kernel.prototype._get_msg = function (msg_type, content) {
Kernel.prototype._get_msg = function (msg_type, content, metadata) {
var msg = {
header : {
msg_id : utils.uuid(),
@ -54,19 +58,32 @@ var IPython = (function (IPython) {
session : this.session_id,
msg_type : msg_type
},
metadata : {},
metadata : metadata || {},
content : content,
parent_header : {}
};
return msg;
};
Kernel.prototype.bind_events = function() {
Kernel.prototype.bind_events = function () {
var that = this;
$([IPython.events]).on('send_input_reply.Kernel', function(evt, data) {
that.send_input_reply(data);
});
}
};
// Initialize the iopub handlers
Kernel.prototype.init_iopub_handlers = function () {
var output_types = ['stream', 'display_data', 'pyout', 'pyerr'];
this._iopub_handlers = {};
this.register_iopub_handler('status', $.proxy(this._handle_status_message, this));
this.register_iopub_handler('clear_output', $.proxy(this._handle_clear_output, this));
for (var i=0; i < output_types.length; i++) {
this.register_iopub_handler(output_types[i], $.proxy(this._handle_output_message, this));
}
};
/**
* Start the Python kernel
@ -81,7 +98,7 @@ var IPython = (function (IPython) {
$.proxy(this._kernel_started, this),
'json'
);
};
}
};
/**
@ -101,7 +118,7 @@ var IPython = (function (IPython) {
$.proxy(this._kernel_started, this),
'json'
);
};
}
};
@ -110,11 +127,11 @@ var IPython = (function (IPython) {
this.running = true;
this.kernel_id = json.id;
var ws_url = json.ws_url;
if (ws_url.match(/wss?:\/\//) == null) {
if (ws_url.match(/wss?:\/\//) === null) {
// trailing 's' in https will become wss for secure web sockets
prot = location.protocol.replace('http', 'ws') + "//";
var prot = location.protocol.replace('http', 'ws') + "//";
ws_url = prot + location.host + ws_url;
};
}
this.ws_url = ws_url;
this.kernel_url = utils.url_path_join(this.base_url, this.kernel_id);
this.start_channels();
@ -176,7 +193,7 @@ var IPython = (function (IPython) {
}
}, 1000);
this.shell_channel.onmessage = $.proxy(this._handle_shell_reply, this);
this.iopub_channel.onmessage = $.proxy(this._handle_iopub_reply, this);
this.iopub_channel.onmessage = $.proxy(this._handle_iopub_message, this);
this.stdin_channel.onmessage = $.proxy(this._handle_input_request, this);
};
@ -208,64 +225,62 @@ var IPython = (function (IPython) {
var channels = [this.shell_channel, this.iopub_channel, this.stdin_channel];
for (var i=0; i < channels.length; i++) {
if ( channels[i] !== null ) {
channels[i].onclose = function (evt) {};
channels[i].onclose = null;
channels[i].close();
}
};
}
this.shell_channel = this.iopub_channel = this.stdin_channel = null;
};
// Main public methods.
// send a message on the Kernel's shell channel
Kernel.prototype.send_shell_message = function (msg_type, content, callbacks, metadata) {
var msg = this._get_msg(msg_type, content, metadata);
this.shell_channel.send(JSON.stringify(msg));
this.set_callbacks_for_msg(msg.header.msg_id, callbacks);
return msg.header.msg_id;
};
/**
* Get info on object asynchronoulsy
* Get info on an object
*
* @async
* @param objname {string}
* @param callback {dict}
* @method object_info_request
* @param callback {function}
* @method object_info
*
* @example
*
* When calling this method pass a callbacks structure of the form:
*
* callbacks = {
* 'object_info_reply': object_info_reply_callback
* }
*
* The `object_info_reply_callback` will be passed the content object of the
*
* `object_into_reply` message documented in
* [IPython dev documentation](http://ipython.org/ipython-doc/dev/development/messaging.html#object-information)
* When calling this method, pass a callback function that expects one argument.
* The callback will be passed the complete `object_info_reply` message documented
* [here](http://ipython.org/ipython-doc/dev/development/messaging.html#object-information)
*/
Kernel.prototype.object_info_request = function (objname, callbacks) {
if(typeof(objname)!=null && objname!=null)
{
Kernel.prototype.object_info = function (objname, callback) {
var callbacks;
if (callback) {
callbacks = { shell : { reply : callback } };
}
if (typeof(objname) !== null && objname !== null) {
var content = {
oname : objname.toString(),
detail_level : 0,
};
var msg = this._get_msg("object_info_request", content);
this.shell_channel.send(JSON.stringify(msg));
this.set_callbacks_for_msg(msg.header.msg_id, callbacks);
return msg.header.msg_id;
return this.send_shell_message("object_info_request", content, callbacks);
}
return;
}
};
/**
* Execute given code into kernel, and pass result to callback.
*
* TODO: document input_request in callbacks
*
* @async
* @method execute
* @param {string} code
* @param [callbacks] {Object} With the optional following keys
* @param callbacks.'execute_reply' {function}
* @param callbacks.'output' {function}
* @param callbacks.'clear_output' {function}
* @param callbacks.'set_next_input' {function}
* @param [callbacks] {Object} With the following keys (all optional)
* @param callbacks.shell.reply {function}
* @param callbacks.shell.payload.[payload_name] {function}
* @param callbacks.iopub.output {function}
* @param callbacks.iopub.clear_output {function}
* @param callbacks.input {function}
* @param {object} [options]
* @param [options.silent=false] {Boolean}
* @param [options.user_expressions=empty_dict] {Dict}
@ -287,27 +302,21 @@ var IPython = (function (IPython) {
* When calling this method pass a callbacks structure of the form:
*
* callbacks = {
* 'execute_reply': execute_reply_callback,
* 'output': output_callback,
* 'clear_output': clear_output_callback,
* 'set_next_input': set_next_input_callback
* shell : {
* reply : execute_reply_callback,
* payload : {
* set_next_input : set_next_input_callback,
* }
* },
* iopub : {
* output : output_callback,
* clear_output : clear_output_callback,
* },
* input : raw_input_callback
* }
*
* The `execute_reply_callback` will be passed the content and metadata
* objects of the `execute_reply` message documented
* [here](http://ipython.org/ipython-doc/dev/development/messaging.html#execute)
*
* The `output_callback` will be passed `msg_type` ('stream','display_data','pyout','pyerr')
* of the output and the content and metadata objects of the PUB/SUB channel that contains the
* output:
*
* http://ipython.org/ipython-doc/dev/development/messaging.html#messages-on-the-pub-sub-socket
*
* The `clear_output_callback` will be passed a content object that contains
* stdout, stderr and other fields that are booleans, as well as the metadata object.
*
* The `set_next_input_callback` will be passed the text that should become the next
* input cell.
* Each callback will be passed the entire message as a single arugment.
* Payload handlers will be passed the corresponding payload and the execute_reply message.
*/
Kernel.prototype.execute = function (code, callbacks, options) {
@ -320,47 +329,39 @@ var IPython = (function (IPython) {
allow_stdin : false
};
callbacks = callbacks || {};
if (callbacks.input_request !== undefined) {
if (callbacks.input !== undefined) {
content.allow_stdin = true;
}
$.extend(true, content, options)
$.extend(true, content, options);
$([IPython.events]).trigger('execution_request.Kernel', {kernel: this, content:content});
var msg = this._get_msg("execute_request", content);
this.shell_channel.send(JSON.stringify(msg));
this.set_callbacks_for_msg(msg.header.msg_id, callbacks);
return msg.header.msg_id;
return this.send_shell_message("execute_request", content, callbacks);
};
/**
* When calling this method pass a callbacks structure of the form:
* When calling this method, pass a function to be called with the `complete_reply` message
* as its only argument when it arrives.
*
* callbacks = {
* 'complete_reply': complete_reply_callback
* }
*
* The `complete_reply_callback` will be passed the content object of the
* `complete_reply` message documented
* `complete_reply` is documented
* [here](http://ipython.org/ipython-doc/dev/development/messaging.html#complete)
*
* @method complete
* @param line {integer}
* @param cursor_pos {integer}
* @param {dict} callbacks
* @param callbacks.complete_reply {function} `complete_reply_callback`
* @param callback {function}
*
*/
Kernel.prototype.complete = function (line, cursor_pos, callbacks) {
callbacks = callbacks || {};
Kernel.prototype.complete = function (line, cursor_pos, callback) {
var callbacks;
if (callback) {
callbacks = { shell : { reply : callback } };
}
var content = {
text : '',
line : line,
block : null,
cursor_pos : cursor_pos
};
var msg = this._get_msg("complete_request", content);
this.shell_channel.send(JSON.stringify(msg));
this.set_callbacks_for_msg(msg.header.msg_id, callbacks);
return msg.header.msg_id;
return this.send_shell_message("complete_request", content, callbacks);
};
@ -368,7 +369,7 @@ var IPython = (function (IPython) {
if (this.running) {
$([IPython.events]).trigger('status_interrupting.Kernel', {kernel: this});
$.post(this.kernel_url + "/interrupt");
};
}
};
@ -380,7 +381,7 @@ var IPython = (function (IPython) {
type : "DELETE"
};
$.ajax(this.kernel_url, settings);
};
}
};
Kernel.prototype.send_input_reply = function (input) {
@ -396,9 +397,19 @@ var IPython = (function (IPython) {
// Reply handlers
Kernel.prototype.register_iopub_handler = function (msg_type, callback) {
this._iopub_handlers[msg_type] = callback;
};
Kernel.prototype.get_iopub_handler = function (msg_type) {
// get iopub handler for a specific message type
return this._iopub_handlers[msg_type];
};
Kernel.prototype.get_callbacks_for_msg = function (msg_id) {
var callbacks = this._msg_callbacks[msg_id];
return callbacks;
// get callbacks for a specific message
return this._msg_callbacks[msg_id];
};
@ -407,91 +418,142 @@ var IPython = (function (IPython) {
delete this._msg_callbacks[msg_id];
}
};
/* Set callbacks for a particular message.
* Callbacks should be a struct of the following form:
* shell : {
*
* }
*/
Kernel.prototype.set_callbacks_for_msg = function (msg_id, callbacks) {
this._msg_callbacks[msg_id] = callbacks || {};
if (callbacks) {
// shallow-copy mapping, because we will modify it at the top level
var cbcopy = this._msg_callbacks[msg_id] = {};
cbcopy.shell = callbacks.shell;
cbcopy.iopub = callbacks.iopub;
cbcopy.input = callbacks.input;
this._msg_callbacks[msg_id] = cbcopy;
}
};
Kernel.prototype._handle_shell_reply = function (e) {
var reply = $.parseJSON(e.data);
$([IPython.events]).trigger('shell_reply.Kernel', {kernel: this, reply:reply});
var header = reply.header;
var content = reply.content;
var metadata = reply.metadata;
var msg_type = header.msg_type;
var callbacks = this.get_callbacks_for_msg(reply.parent_header.msg_id);
if (callbacks !== undefined) {
var cb = callbacks[msg_type];
if (cb !== undefined) {
cb(content, metadata);
}
};
if (content.payload !== undefined) {
var payload = content.payload || [];
this._handle_payload(callbacks, payload);
var parent_id = reply.parent_header.msg_id;
var callbacks = this.get_callbacks_for_msg(parent_id);
if (!callbacks || !callbacks.shell) {
return;
}
var shell_callbacks = callbacks.shell;
// clear callbacks on shell
delete callbacks.shell;
delete callbacks.input;
if (!callbacks.iopub) {
this.clear_callbacks_for_msg(parent_id);
}
if (shell_callbacks.reply !== undefined) {
shell_callbacks.reply(reply);
}
if (content.payload && shell_callbacks.payload) {
this._handle_payloads(content.payload, shell_callbacks.payload, reply);
}
};
Kernel.prototype._handle_payload = function (callbacks, payload) {
var l = payload.length;
Kernel.prototype._handle_payloads = function (payloads, payload_callbacks, msg) {
var l = payloads.length;
// Payloads are handled by triggering events because we don't want the Kernel
// to depend on the Notebook or Pager classes.
for (var i=0; i<l; i++) {
if (payload[i].source === 'page') {
var data = {'text':payload[i].text}
$([IPython.events]).trigger('open_with_text.Pager', data);
} else if (payload[i].source === 'set_next_input') {
if (callbacks.set_next_input !== undefined) {
callbacks.set_next_input(payload[i].text)
var payload = payloads[i];
var callback = payload_callbacks[payload.source];
if (callback) {
callback(payload, msg);
}
}
};
Kernel.prototype._handle_status_message = function (msg) {
var execution_state = msg.content.execution_state;
var parent_id = msg.parent_header.msg_id;
// dispatch status msg callbacks, if any
var callbacks = this.get_callbacks_for_msg(parent_id);
if (callbacks && callbacks.iopub && callbacks.iopub.status) {
try {
callbacks.iopub.status(msg);
} catch (e) {
console.log("Exception in status msg handler", e);
}
}
if (execution_state === 'busy') {
$([IPython.events]).trigger('status_busy.Kernel', {kernel: this});
} else if (execution_state === 'idle') {
// clear callbacks on idle, there can be no more
if (callbacks !== undefined) {
delete callbacks.iopub;
delete callbacks.input;
if (!callbacks.shell) {
this.clear_callbacks_for_msg(parent_id);
}
}
};
// trigger status_idle event
$([IPython.events]).trigger('status_idle.Kernel', {kernel: this});
} else if (execution_state === 'restarting') {
// autorestarting is distinct from restarting,
// in that it means the kernel died and the server is restarting it.
// status_restarting sets the notification widget,
// autorestart shows the more prominent dialog.
$([IPython.events]).trigger('status_autorestarting.Kernel', {kernel: this});
$([IPython.events]).trigger('status_restarting.Kernel', {kernel: this});
} else if (execution_state === 'dead') {
this.stop_channels();
$([IPython.events]).trigger('status_dead.Kernel', {kernel: this});
}
};
// handle clear_output message
Kernel.prototype._handle_clear_output = function (msg) {
var callbacks = this.get_callbacks_for_msg(msg.parent_header.msg_id);
if (!callbacks || !callbacks.iopub) {
return;
}
var callback = callbacks.iopub.clear_output;
if (callback) {
callback(msg);
}
};
Kernel.prototype._handle_iopub_reply = function (e) {
var reply = $.parseJSON(e.data);
var content = reply.content;
var msg_type = reply.header.msg_type;
var metadata = reply.metadata;
var callbacks = this.get_callbacks_for_msg(reply.parent_header.msg_id);
if (msg_type !== 'status' && callbacks === undefined) {
// Message not from one of this notebook's cells and there are no
// callbacks to handle it.
// handle an output message (pyout, display_data, etc.)
Kernel.prototype._handle_output_message = function (msg) {
var callbacks = this.get_callbacks_for_msg(msg.parent_header.msg_id);
if (!callbacks || !callbacks.iopub) {
return;
}
var output_types = ['stream','display_data','pyout','pyerr'];
if (output_types.indexOf(msg_type) >= 0) {
var cb = callbacks['output'];
if (cb !== undefined) {
cb(msg_type, content, metadata);
}
} else if (msg_type === 'status') {
if (content.execution_state === 'busy') {
$([IPython.events]).trigger('status_busy.Kernel', {kernel: this});
} else if (content.execution_state === 'idle') {
$([IPython.events]).trigger('status_idle.Kernel', {kernel: this});
} else if (content.execution_state === 'restarting') {
// autorestarting is distinct from restarting,
// in that it means the kernel died and the server is restarting it.
// status_restarting sets the notification widget,
// autorestart shows the more prominent dialog.
$([IPython.events]).trigger('status_autorestarting.Kernel', {kernel: this});
$([IPython.events]).trigger('status_restarting.Kernel', {kernel: this});
} else if (content.execution_state === 'dead') {
this.stop_channels();
$([IPython.events]).trigger('status_dead.Kernel', {kernel: this});
};
} else if (msg_type === 'clear_output') {
var cb = callbacks['clear_output'];
if (cb !== undefined) {
cb(content, metadata);
}
};
var callback = callbacks.iopub.output;
if (callback) {
callback(msg);
}
};
// dispatch IOPub messages to respective handlers.
// each message type should have a handler.
Kernel.prototype._handle_iopub_message = function (e) {
var msg = $.parseJSON(e.data);
var handler = this.get_iopub_handler(msg.header.msg_type);
if (handler !== undefined) {
handler(msg);
}
};
@ -506,12 +568,11 @@ var IPython = (function (IPython) {
return;
}
var callbacks = this.get_callbacks_for_msg(request.parent_header.msg_id);
if (callbacks !== undefined) {
var cb = callbacks[msg_type];
if (cb !== undefined) {
cb(content, metadata);
if (callbacks) {
if (callbacks.input) {
callbacks.input(request);
}
};
}
};

View File

@ -232,6 +232,9 @@ class="notebook_app"
<script src="{{ static_url("base/js/events.js") }}" type="text/javascript" charset="utf-8"></script>
<script src="{{ static_url("base/js/utils.js") }}" type="text/javascript" charset="utf-8"></script>
<script src="{{ static_url("base/js/dialog.js") }}" type="text/javascript" charset="utf-8"></script>
<script src="{{ static_url("services/kernels/js/kernel.js") }}" type="text/javascript" charset="utf-8"></script>
<script src="{{ static_url("services/kernels/js/comm.js") }}" type="text/javascript" charset="utf-8"></script>
<script src="{{ static_url("services/sessions/js/session.js") }}" type="text/javascript" charset="utf-8"></script>
<script src="{{ static_url("notebook/js/layoutmanager.js") }}" type="text/javascript" charset="utf-8"></script>
<script src="{{ static_url("notebook/js/mathjaxutils.js") }}" type="text/javascript" charset="utf-8"></script>
<script src="{{ static_url("notebook/js/outputarea.js") }}" type="text/javascript" charset="utf-8"></script>
@ -240,8 +243,6 @@ class="notebook_app"
<script src="{{ static_url("notebook/js/codecell.js") }}" type="text/javascript" charset="utf-8"></script>
<script src="{{ static_url("notebook/js/completer.js") }}" type="text/javascript" charset="utf-8"></script>
<script src="{{ static_url("notebook/js/textcell.js") }}" type="text/javascript" charset="utf-8"></script>
<script src="{{ static_url("services/kernels/js/kernel.js") }}" type="text/javascript" charset="utf-8"></script>
<script src="{{ static_url("services/sessions/js/session.js") }}" type="text/javascript" charset="utf-8"></script>
<script src="{{ static_url("notebook/js/savewidget.js") }}" type="text/javascript" charset="utf-8"></script>
<script src="{{ static_url("notebook/js/quickhelp.js") }}" type="text/javascript" charset="utf-8"></script>
<script src="{{ static_url("notebook/js/pager.js") }}" type="text/javascript" charset="utf-8"></script>

View File

@ -0,0 +1,269 @@
{
"metadata": {
"name": ""
},
"nbformat": 3,
"nbformat_minor": 0,
"worksheets": [
{
"cells": [
{
"cell_type": "heading",
"level": 1,
"metadata": {},
"source": [
"Basic Output"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"from IPython.display import display"
],
"language": "python",
"metadata": {},
"outputs": []
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"print 'hi'"
],
"language": "python",
"metadata": {},
"outputs": []
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"display('hi')"
],
"language": "python",
"metadata": {},
"outputs": []
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"1"
],
"language": "python",
"metadata": {},
"outputs": []
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"%matplotlib inline\n",
"import matplotlib.pyplot as plt\n",
"plt.plot([1,3,2])"
],
"language": "python",
"metadata": {},
"outputs": []
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"%%javascript\n",
"console.log(\"I ran!\");"
],
"language": "python",
"metadata": {},
"outputs": []
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"%%html\n",
"<b>bold</b>"
],
"language": "python",
"metadata": {},
"outputs": []
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"%%latex\n",
"$$\n",
"a = 5\n",
"$$"
],
"language": "python",
"metadata": {},
"outputs": []
},
{
"cell_type": "heading",
"level": 1,
"metadata": {},
"source": [
"input_request"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"raw_input(\"prompt > \")"
],
"language": "python",
"metadata": {},
"outputs": []
},
{
"cell_type": "heading",
"level": 1,
"metadata": {},
"source": [
"set_next_input"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"%%writefile tst.py\n",
"def foo():\n",
" pass\n"
],
"language": "python",
"metadata": {},
"outputs": []
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"%load tst.py"
],
"language": "python",
"metadata": {},
"outputs": []
},
{
"cell_type": "heading",
"level": 1,
"metadata": {},
"source": [
"Pager in execute_reply"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"plt?"
],
"language": "python",
"metadata": {},
"outputs": []
},
{
"cell_type": "heading",
"level": 1,
"metadata": {},
"source": [
"object_info"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"# press tab after parentheses\n",
"int("
],
"language": "python",
"metadata": {},
"outputs": []
},
{
"cell_type": "heading",
"level": 1,
"metadata": {},
"source": [
"complete"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"# pres tab after f\n",
"f"
],
"language": "python",
"metadata": {},
"outputs": []
},
{
"cell_type": "heading",
"level": 1,
"metadata": {},
"source": [
"clear_output"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"import sys\n",
"from IPython.display import clear_output"
],
"language": "python",
"metadata": {},
"outputs": []
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"for i in range(10):\n",
" clear_output()\n",
" time.sleep(0.25)\n",
" print i\n",
" sys.stdout.flush()\n",
" time.sleep(0.25)\n"
],
"language": "python",
"metadata": {},
"outputs": []
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"for i in range(10):\n",
" clear_output(wait=True)\n",
" time.sleep(0.25)\n",
" print i\n",
" sys.stdout.flush()\n"
],
"language": "python",
"metadata": {},
"outputs": []
},
{
"cell_type": "code",
"collapsed": false,
"input": [],
"language": "python",
"metadata": {},
"outputs": []
}
],
"metadata": {}
}
]
}