##// END OF EJS Templates
Merge pull request #2389 from takluyver/catch-histdb-errors...
Merge pull request #2389 from takluyver/catch-histdb-errors Catch sqlite DatabaseErrors in more places when reading the history database It seems sqlite can encounter corruption and throw an error when reading the database, although it has connected successfully. This borrows the move-and-recreate machinery we already had on connecting to the database. If such an error occurs, the corrupted file is moved and the user get warned of the name of the corrupted file.

File last commit:

r8290:f4616c97 merge
r8503:7904325b merge
Show More
kernel.js
391 lines | 13.5 KiB | application/javascript | JavascriptLexer
//----------------------------------------------------------------------------
// Copyright (C) 2008-2011 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.
//----------------------------------------------------------------------------
//============================================================================
// Kernel
//============================================================================
var IPython = (function (IPython) {
var utils = IPython.utils;
// Initialization and connection.
var Kernel = function (base_url) {
this.kernel_id = null;
this.shell_channel = null;
this.iopub_channel = null;
this.base_url = base_url;
this.running = false;
this.username = "username";
this.session_id = utils.uuid();
this._msg_callbacks = {};
if (typeof(WebSocket) !== 'undefined') {
this.WebSocket = WebSocket;
} else if (typeof(MozWebSocket) !== 'undefined') {
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.');
};
};
Kernel.prototype._get_msg = function (msg_type, content) {
var msg = {
header : {
msg_id : utils.uuid(),
username : this.username,
session : this.session_id,
msg_type : msg_type
},
metadata : {},
content : content,
parent_header : {}
};
return msg;
};
Kernel.prototype.start = function (notebook_id) {
var that = this;
if (!this.running) {
var qs = $.param({notebook:notebook_id});
var url = this.base_url + '?' + qs;
$.post(url,
$.proxy(that._kernel_started,that),
'json'
);
};
};
Kernel.prototype.restart = function () {
$([IPython.events]).trigger({type: 'status_restarting.Kernel', kernel: this});
var that = this;
if (this.running) {
this.stop_channels();
var url = this.kernel_url + "/restart";
$.post(url,
$.proxy(that._kernel_started, that),
'json'
);
};
};
Kernel.prototype._kernel_started = function (json) {
console.log("Kernel started: ", json.kernel_id);
this.running = true;
this.kernel_id = json.kernel_id;
this.ws_url = json.ws_url;
this.kernel_url = this.base_url + "/" + this.kernel_id;
this.start_channels();
this.shell_channel.onmessage = $.proxy(this._handle_shell_reply,this);
this.iopub_channel.onmessage = $.proxy(this._handle_iopub_reply,this);
};
Kernel.prototype._websocket_closed = function(ws_url, early){
var msg;
var parent_item = $('body');
if (early) {
msg = "Websocket connection to " + ws_url + " could not be established." +
" You will NOT be able to run code." +
" Your browser may not be compatible with the websocket version in the server," +
" or if the url does not look right, there could be an error in the" +
" server's configuration.";
} else {
IPython.notification_area.widget('kernel').set_message('Reconnecting Websockets', 1000);
this.start_channels();
return;
}
var dialog = $('<div/>');
dialog.html(msg);
parent_item.append(dialog);
dialog.dialog({
resizable: false,
modal: true,
title: "Websocket closed",
closeText: "",
close: function(event, ui) {$(this).dialog('destroy').remove();},
buttons : {
"OK": function () {
$(this).dialog('close');
}
}
});
};
Kernel.prototype.start_channels = function () {
var that = this;
this.stop_channels();
var ws_url = this.ws_url + this.kernel_url;
console.log("Starting WS:", ws_url);
this.shell_channel = new this.WebSocket(ws_url + "/shell");
this.iopub_channel = new this.WebSocket(ws_url + "/iopub");
send_cookie = function(){
this.send(document.cookie);
};
var already_called_onclose = false; // only alert once
ws_closed_early = function(evt){
if (already_called_onclose){
return;
}
already_called_onclose = true;
if ( ! evt.wasClean ){
that._websocket_closed(ws_url, true);
}
};
ws_closed_late = function(evt){
if (already_called_onclose){
return;
}
already_called_onclose = true;
if ( ! evt.wasClean ){
that._websocket_closed(ws_url, false);
}
};
this.shell_channel.onopen = send_cookie;
this.shell_channel.onclose = ws_closed_early;
this.iopub_channel.onopen = send_cookie;
this.iopub_channel.onclose = ws_closed_early;
// switch from early-close to late-close message after 1s
setTimeout(function(){
that.shell_channel.onclose = ws_closed_late;
that.iopub_channel.onclose = ws_closed_late;
}, 1000);
};
Kernel.prototype.stop_channels = function () {
if (this.shell_channel !== null) {
this.shell_channel.onclose = function (evt) {};
this.shell_channel.close();
this.shell_channel = null;
};
if (this.iopub_channel !== null) {
this.iopub_channel.onclose = function (evt) {};
this.iopub_channel.close();
this.iopub_channel = null;
};
};
// Main public methods.
Kernel.prototype.object_info_request = function (objname, callbacks) {
// When calling this method pass a callbacks structure of the form:
//
// callbacks = {
// 'object_info_reply': object_into_reply_callback
// }
//
// The object_info_reply_callback will be passed the content object of the
// object_into_reply message documented here:
//
// http://ipython.org/ipython-doc/dev/development/messaging.html#object-information
if(typeof(objname)!=null && objname!=null)
{
var content = {
oname : objname.toString(),
};
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;
}
Kernel.prototype.execute = function (code, callbacks, options) {
// The options object should contain the options for the execute call. Its default
// values are:
//
// options = {
// silent : true,
// user_variables : [],
// user_expressions : {},
// allow_stdin : false
// }
//
// 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
// }
//
// 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.
var content = {
code : code,
silent : true,
user_variables : [],
user_expressions : {},
allow_stdin : false
};
$.extend(true, content, options)
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;
};
Kernel.prototype.complete = function (line, cursor_pos, callbacks) {
// When calling this method pass a callbacks structure of the form:
//
// callbacks = {
// 'complete_reply': complete_reply_callback
// }
//
// The complete_reply_callback will be passed the content object of the
// complete_reply message documented here:
//
// http://ipython.org/ipython-doc/dev/development/messaging.html#complete
callbacks = callbacks || {};
var content = {
text : '',
line : line,
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;
};
Kernel.prototype.interrupt = function () {
if (this.running) {
$([IPython.events]).trigger({type: 'status_interrupting.Kernel', kernel: this});
$.post(this.kernel_url + "/interrupt");
};
};
Kernel.prototype.kill = function () {
if (this.running) {
this.running = false;
var settings = {
cache : false,
type : "DELETE"
};
$.ajax(this.kernel_url, settings);
};
};
// Reply handlers.
Kernel.prototype.get_callbacks_for_msg = function (msg_id) {
var callbacks = this._msg_callbacks[msg_id];
return callbacks;
};
Kernel.prototype.set_callbacks_for_msg = function (msg_id, callbacks) {
this._msg_callbacks[msg_id] = callbacks || {};
}
Kernel.prototype._handle_shell_reply = function (e) {
reply = $.parseJSON(e.data);
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);
}
};
Kernel.prototype._handle_payload = function (callbacks, payload) {
var l = payload.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 === 'IPython.zmq.page.page') {
var data = {'text':payload[i].text}
$([IPython.events]).trigger('open_with_text.Pager', data);
} else if (payload[i].source === 'IPython.zmq.zmqshell.ZMQInteractiveShell.set_next_input') {
if (callbacks.set_next_input !== undefined) {
callbacks.set_next_input(payload[i].text)
}
}
};
};
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.
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({type: 'status_busy.Kernel', kernel: this});
} else if (content.execution_state === 'idle') {
$([IPython.events]).trigger({type: 'status_idle.Kernel', kernel: this});
} else if (content.execution_state === 'dead') {
this.stop_channels();
$([IPython.events]).trigger({type: 'status_dead.Kernel', kernel: this});
};
} else if (msg_type === 'clear_output') {
var cb = callbacks['clear_output'];
if (cb !== undefined) {
cb(content, metadata);
}
};
};
IPython.Kernel = Kernel;
return IPython;
}(IPython));