Uploaded Test files
This commit is contained in:
parent
f584ad9d97
commit
2e81cb7d99
16627 changed files with 2065359 additions and 102444 deletions
144
venv/Lib/site-packages/notebook/static/services/config.js
Normal file
144
venv/Lib/site-packages/notebook/static/services/config.js
Normal file
|
@ -0,0 +1,144 @@
|
|||
// Copyright (c) Jupyter Development Team.
|
||||
// Distributed under the terms of the Modified BSD License.
|
||||
|
||||
define([
|
||||
'base/js/utils',
|
||||
],
|
||||
function(utils) {
|
||||
"use strict";
|
||||
var ConfigSection = function(section_name, options) {
|
||||
this.section_name = section_name;
|
||||
this.base_url = options.base_url;
|
||||
this.data = {};
|
||||
|
||||
var that = this;
|
||||
|
||||
/* .loaded is a promise, fulfilled the first time the config is loaded
|
||||
* from the server. Code can do:
|
||||
* conf.loaded.then(function() { ... using conf.data ... });
|
||||
*/
|
||||
this._one_load_finished = false;
|
||||
this.loaded = new Promise(function(resolve, reject) {
|
||||
that._finish_firstload = resolve;
|
||||
});
|
||||
};
|
||||
|
||||
ConfigSection.prototype.api_url = function() {
|
||||
return utils.url_path_join(this.base_url, 'api/config',
|
||||
utils.encode_uri_components(this.section_name));
|
||||
};
|
||||
|
||||
ConfigSection.prototype._load_done = function() {
|
||||
if (!this._one_load_finished) {
|
||||
this._one_load_finished = true;
|
||||
this._finish_firstload();
|
||||
}
|
||||
};
|
||||
|
||||
ConfigSection.prototype.load = function() {
|
||||
var that = this;
|
||||
return utils.promising_ajax(this.api_url(), {
|
||||
cache: false,
|
||||
type: "GET",
|
||||
dataType: "json",
|
||||
}).then(function(data) {
|
||||
that.data = data;
|
||||
that._load_done();
|
||||
return data;
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Modify the config values stored. Update the local data immediately,
|
||||
* send the change to the server, and use the updated data from the server
|
||||
* when the reply comes.
|
||||
*/
|
||||
ConfigSection.prototype.update = function(newdata) {
|
||||
$.extend(true, this.data, newdata); // true -> recursive update
|
||||
|
||||
var that = this;
|
||||
return utils.promising_ajax(this.api_url(), {
|
||||
processData: false,
|
||||
type : "PATCH",
|
||||
data: JSON.stringify(newdata),
|
||||
dataType : "json",
|
||||
contentType: 'application/json',
|
||||
}).then(function(data) {
|
||||
that.data = data;
|
||||
that._load_done();
|
||||
return data;
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
var ConfigWithDefaults = function(section, defaults, classname) {
|
||||
this.section = section;
|
||||
this.defaults = defaults;
|
||||
this.classname = classname;
|
||||
};
|
||||
|
||||
ConfigWithDefaults.prototype._class_data = function() {
|
||||
if (this.classname) {
|
||||
return this.section.data[this.classname] || {};
|
||||
} else {
|
||||
return this.section.data;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Wait for config to have loaded, then get a value or the default.
|
||||
* Returns a promise.
|
||||
*/
|
||||
ConfigWithDefaults.prototype.get = function(key) {
|
||||
var that = this;
|
||||
return this.section.loaded.then(function() {
|
||||
return that.get_sync(key);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Return a config value. If config is not yet loaded, return the default
|
||||
* instead of waiting for it to load.
|
||||
*/
|
||||
ConfigWithDefaults.prototype.get_sync = function(key) {
|
||||
var data = this._class_data();
|
||||
if (key === undefined) {
|
||||
// no key specified, return full config data
|
||||
return $.extend(true, {}, this.defaults, data);
|
||||
}
|
||||
|
||||
var value = data[key];
|
||||
if (value !== undefined) {
|
||||
if (typeof value == 'object') {
|
||||
// merge with defaults if it's an object
|
||||
return $.extend(true, {}, this.defaults[key], value);
|
||||
} else {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
return this.defaults[key];
|
||||
};
|
||||
|
||||
/**
|
||||
* Set a config value. Send the update to the server, and change our
|
||||
* local copy of the data immediately.
|
||||
* Returns a promise which is fulfilled when the server replies to the
|
||||
* change.
|
||||
*/
|
||||
ConfigWithDefaults.prototype.set = function(key, value) {
|
||||
var d = {};
|
||||
d[key] = value;
|
||||
if (this.classname) {
|
||||
var d2 = {};
|
||||
d2[this.classname] = d;
|
||||
return this.section.update(d2);
|
||||
} else {
|
||||
return this.section.update(d);
|
||||
}
|
||||
};
|
||||
|
||||
return {ConfigSection: ConfigSection,
|
||||
ConfigWithDefaults: ConfigWithDefaults,
|
||||
};
|
||||
|
||||
});
|
268
venv/Lib/site-packages/notebook/static/services/contents.js
Normal file
268
venv/Lib/site-packages/notebook/static/services/contents.js
Normal file
|
@ -0,0 +1,268 @@
|
|||
// Copyright (c) Jupyter Development Team.
|
||||
// Distributed under the terms of the Modified BSD License.
|
||||
|
||||
define(function(requirejs) {
|
||||
"use strict";
|
||||
|
||||
var $ = requirejs('jquery');
|
||||
var utils = requirejs('base/js/utils');
|
||||
|
||||
var Contents = function(options) {
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* Preliminary documentation for the REST API is at
|
||||
* https://github.com/ipython/ipython/wiki/IPEP-27%3A-Contents-Service
|
||||
*
|
||||
* A contents handles passing file operations
|
||||
* to the back-end. This includes checkpointing
|
||||
* with the normal file operations.
|
||||
*
|
||||
* Parameters:
|
||||
* options: dictionary
|
||||
* Dictionary of keyword arguments.
|
||||
* base_url: string
|
||||
*/
|
||||
this.base_url = options.base_url;
|
||||
};
|
||||
|
||||
/** Error type */
|
||||
Contents.DIRECTORY_NOT_EMPTY_ERROR = 'DirectoryNotEmptyError';
|
||||
|
||||
Contents.DirectoryNotEmptyError = function() {
|
||||
// Constructor
|
||||
//
|
||||
// An error representing the result of attempting to delete a non-empty
|
||||
// directory.
|
||||
this.message = 'A directory must be empty before being deleted.';
|
||||
};
|
||||
|
||||
Contents.DirectoryNotEmptyError.prototype = Object.create(Error.prototype);
|
||||
Contents.DirectoryNotEmptyError.prototype.name =
|
||||
Contents.DIRECTORY_NOT_EMPTY_ERROR;
|
||||
|
||||
|
||||
Contents.prototype.api_url = function() {
|
||||
var url_parts = [
|
||||
this.base_url, 'api/contents',
|
||||
utils.url_join_encode.apply(null, arguments),
|
||||
];
|
||||
return utils.url_path_join.apply(null, url_parts);
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a basic error handler that wraps a jqXHR error as an Error.
|
||||
*
|
||||
* Takes a callback that accepts an Error, and returns a callback that can
|
||||
* be passed directly to $.ajax, which will wrap the error from jQuery
|
||||
* as an Error, and pass that to the original callback.
|
||||
*
|
||||
* @method create_basic_error_handler
|
||||
* @param{Function} callback
|
||||
* @return{Function}
|
||||
*/
|
||||
Contents.prototype.create_basic_error_handler = function(callback) {
|
||||
if (!callback) {
|
||||
return utils.log_ajax_error;
|
||||
}
|
||||
return function(xhr, status, error) {
|
||||
callback(utils.wrap_ajax_error(xhr, status, error));
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* File Functions (including notebook operations)
|
||||
*/
|
||||
|
||||
/**
|
||||
* Get a file.
|
||||
*
|
||||
* @method get
|
||||
* @param {String} path
|
||||
* @param {Object} options
|
||||
* type : 'notebook', 'file', or 'directory'
|
||||
* format: 'text' or 'base64'; only relevant for type: 'file'
|
||||
* content: true or false; // whether to include the content
|
||||
*/
|
||||
Contents.prototype.get = function (path, options) {
|
||||
/**
|
||||
* We do the call with settings so we can set cache to false.
|
||||
*/
|
||||
var settings = {
|
||||
processData : false,
|
||||
cache : false,
|
||||
type : "GET",
|
||||
dataType : "json",
|
||||
};
|
||||
var url = this.api_url(path);
|
||||
var params = {};
|
||||
if (options.type) { params.type = options.type; }
|
||||
if (options.format) { params.format = options.format; }
|
||||
if (options.content === false) { params.content = '0'; }
|
||||
return utils.promising_ajax(url + '?' + $.param(params), settings);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new untitled file or directory in the specified directory path.
|
||||
*
|
||||
* @method new
|
||||
* @param {String} path: the directory in which to create the new file/directory
|
||||
* @param {Object} options:
|
||||
* ext: file extension to use
|
||||
* type: model type to create ('notebook', 'file', or 'directory')
|
||||
*/
|
||||
Contents.prototype.new_untitled = function(path, options) {
|
||||
var data = JSON.stringify({
|
||||
ext: options.ext,
|
||||
type: options.type
|
||||
});
|
||||
|
||||
var settings = {
|
||||
processData : false,
|
||||
type : "POST",
|
||||
data: data,
|
||||
contentType: 'application/json',
|
||||
dataType : "json",
|
||||
};
|
||||
return utils.promising_ajax(this.api_url(path), settings);
|
||||
};
|
||||
|
||||
Contents.prototype.delete = function(path) {
|
||||
var settings = {
|
||||
processData : false,
|
||||
type : "DELETE",
|
||||
dataType : "json",
|
||||
};
|
||||
var url = this.api_url(path);
|
||||
return utils.promising_ajax(url, settings).catch(
|
||||
// Translate certain errors to more specific ones.
|
||||
function(error) {
|
||||
// TODO: update IPEP27 to specify errors more precisely, so
|
||||
// that error types can be detected here with certainty.
|
||||
if (error.xhr.status === 400) {
|
||||
throw new Contents.DirectoryNotEmptyError();
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
Contents.prototype.rename = function(path, new_path) {
|
||||
var data = {path: new_path};
|
||||
var settings = {
|
||||
processData : false,
|
||||
type : "PATCH",
|
||||
data : JSON.stringify(data),
|
||||
dataType: "json",
|
||||
contentType: 'application/json',
|
||||
};
|
||||
var url = this.api_url(path);
|
||||
return utils.promising_ajax(url, settings);
|
||||
};
|
||||
|
||||
Contents.prototype.trust = function(path) {
|
||||
var settings = {
|
||||
processData : false,
|
||||
type : "POST",
|
||||
contentType: 'application/json',
|
||||
};
|
||||
var url = this.api_url(path, "trust");
|
||||
return utils.promising_ajax(url, settings);
|
||||
}
|
||||
|
||||
Contents.prototype.save = function(path, model) {
|
||||
/**
|
||||
* We do the call with settings so we can set cache to false.
|
||||
*/
|
||||
var settings = {
|
||||
processData : false,
|
||||
type : "PUT",
|
||||
dataType: "json",
|
||||
data : JSON.stringify(model),
|
||||
contentType: 'application/json',
|
||||
};
|
||||
var url = this.api_url(path);
|
||||
return utils.promising_ajax(url, settings);
|
||||
};
|
||||
|
||||
Contents.prototype.copy = function(from_file, to_dir) {
|
||||
/**
|
||||
* Copy a file into a given directory via POST
|
||||
* The server will select the name of the copied file
|
||||
*/
|
||||
var url = this.api_url(to_dir);
|
||||
|
||||
var settings = {
|
||||
processData : false,
|
||||
type: "POST",
|
||||
data: JSON.stringify({copy_from: from_file}),
|
||||
contentType: 'application/json',
|
||||
dataType : "json",
|
||||
};
|
||||
return utils.promising_ajax(url, settings);
|
||||
};
|
||||
|
||||
/**
|
||||
* Checkpointing Functions
|
||||
*/
|
||||
|
||||
Contents.prototype.create_checkpoint = function(path) {
|
||||
var url = this.api_url(path, 'checkpoints');
|
||||
var settings = {
|
||||
type : "POST",
|
||||
contentType: false, // no data
|
||||
dataType : "json",
|
||||
};
|
||||
return utils.promising_ajax(url, settings);
|
||||
};
|
||||
|
||||
Contents.prototype.list_checkpoints = function(path) {
|
||||
var url = this.api_url(path, 'checkpoints');
|
||||
var settings = {
|
||||
type : "GET",
|
||||
cache: false,
|
||||
dataType: "json",
|
||||
};
|
||||
return utils.promising_ajax(url, settings);
|
||||
};
|
||||
|
||||
Contents.prototype.restore_checkpoint = function(path, checkpoint_id) {
|
||||
var url = this.api_url(path, 'checkpoints', checkpoint_id);
|
||||
var settings = {
|
||||
type : "POST",
|
||||
contentType: false, // no data
|
||||
};
|
||||
return utils.promising_ajax(url, settings);
|
||||
};
|
||||
|
||||
Contents.prototype.delete_checkpoint = function(path, checkpoint_id) {
|
||||
var url = this.api_url(path, 'checkpoints', checkpoint_id);
|
||||
var settings = {
|
||||
type : "DELETE",
|
||||
};
|
||||
return utils.promising_ajax(url, settings);
|
||||
};
|
||||
|
||||
/**
|
||||
* File management functions
|
||||
*/
|
||||
|
||||
/**
|
||||
* List notebooks and directories at a given path
|
||||
*
|
||||
* On success, load_callback is called with an array of dictionaries
|
||||
* representing individual files or directories. Each dictionary has
|
||||
* the keys:
|
||||
* type: "notebook" or "directory"
|
||||
* created: created date
|
||||
* last_modified: last modified dat
|
||||
* @method list_notebooks
|
||||
* @param {String} path The path to list notebooks in
|
||||
*/
|
||||
Contents.prototype.list_contents = function(path) {
|
||||
return this.get(path, {type: 'directory'});
|
||||
};
|
||||
|
||||
return {'Contents': Contents};
|
||||
});
|
213
venv/Lib/site-packages/notebook/static/services/kernels/comm.js
Normal file
213
venv/Lib/site-packages/notebook/static/services/kernels/comm.js
Normal file
|
@ -0,0 +1,213 @@
|
|||
// Copyright (c) Jupyter Development Team.
|
||||
// Distributed under the terms of the Modified BSD License.
|
||||
|
||||
define([
|
||||
'jquery',
|
||||
'base/js/utils',
|
||||
], function($, utils) {
|
||||
"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, comm_id, buffers) {
|
||||
/**
|
||||
* Create a new Comm, register it, and open its Kernel-side counterpart
|
||||
* Mimics the auto-registration in `Comm.__init__` in the Jupyter Comm.
|
||||
*
|
||||
* argument comm_id is optional
|
||||
*/
|
||||
var comm = new Comm(target_name, comm_id);
|
||||
this.register_comm(comm);
|
||||
comm.open(data, callbacks, metadata, buffers);
|
||||
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] = Promise.resolve(comm);
|
||||
comm.kernel = this.kernel;
|
||||
return comm.comm_id;
|
||||
};
|
||||
|
||||
CommManager.prototype.unregister_comm = function (comm) {
|
||||
/**
|
||||
* Remove a comm from the mapping
|
||||
*/
|
||||
delete this.comms[comm.comm_id];
|
||||
};
|
||||
|
||||
// comm message handlers
|
||||
|
||||
CommManager.prototype.comm_open = function (msg) {
|
||||
var content = msg.content;
|
||||
var that = this;
|
||||
var comm_id = content.comm_id;
|
||||
|
||||
this.comms[comm_id] = utils.load_class(content.target_name, content.target_module,
|
||||
this.targets).then(function(target) {
|
||||
var comm = new Comm(content.target_name, comm_id);
|
||||
comm.kernel = that.kernel;
|
||||
try {
|
||||
var response = target(comm, msg);
|
||||
} catch (e) {
|
||||
comm.close();
|
||||
that.unregister_comm(comm);
|
||||
var wrapped_error = new utils.WrappedError("Exception opening new comm", e);
|
||||
console.error(wrapped_error);
|
||||
return Promise.reject(wrapped_error);
|
||||
}
|
||||
// Regardless of the target return value, we need to
|
||||
// then return the comm
|
||||
return Promise.resolve(response).then(function() {return comm;});
|
||||
}, utils.reject('Could not open comm', true));
|
||||
return this.comms[comm_id];
|
||||
};
|
||||
|
||||
CommManager.prototype.comm_close = function(msg) {
|
||||
var content = msg.content;
|
||||
if (this.comms[content.comm_id] === undefined) {
|
||||
console.error('Comm promise not found for comm id ' + content.comm_id);
|
||||
return;
|
||||
}
|
||||
var that = this;
|
||||
this.comms[content.comm_id] = this.comms[content.comm_id].then(function(comm) {
|
||||
that.unregister_comm(comm);
|
||||
try {
|
||||
comm.handle_close(msg);
|
||||
} catch (e) {
|
||||
console.log("Exception closing comm: ", e, e.stack, msg);
|
||||
}
|
||||
// don't return a comm, so that further .then() functions
|
||||
// get an undefined comm input
|
||||
});
|
||||
return this.comms[content.comm_id];
|
||||
};
|
||||
|
||||
CommManager.prototype.comm_msg = function(msg) {
|
||||
var content = msg.content;
|
||||
if (this.comms[content.comm_id] === undefined) {
|
||||
console.error('Comm promise not found for comm id ' + content.comm_id);
|
||||
return;
|
||||
}
|
||||
|
||||
this.comms[content.comm_id] = this.comms[content.comm_id].then(function(comm) {
|
||||
return (Promise.resolve(comm.handle_msg(msg))
|
||||
.catch(utils.reject('Exception handling comm message'))
|
||||
.then(function() {return comm;}));
|
||||
});
|
||||
return this.comms[content.comm_id];
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
// Comm base class
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
var Comm = function (target_name, comm_id) {
|
||||
this.target_name = target_name;
|
||||
this.comm_id = comm_id || utils.uuid();
|
||||
this._msg_callback = this._close_callback = null;
|
||||
};
|
||||
|
||||
// methods for sending messages
|
||||
Comm.prototype.open = function (data, callbacks, metadata, buffers) {
|
||||
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, buffers);
|
||||
};
|
||||
|
||||
Comm.prototype.send = function (data, callbacks, metadata, buffers) {
|
||||
var content = {
|
||||
comm_id : this.comm_id,
|
||||
data : data || {},
|
||||
};
|
||||
return this.kernel.send_shell_message("comm_msg", content, callbacks, metadata, buffers);
|
||||
};
|
||||
|
||||
Comm.prototype.close = function (data, callbacks, metadata, buffers) {
|
||||
var content = {
|
||||
comm_id : this.comm_id,
|
||||
data : data || {},
|
||||
};
|
||||
return this.kernel.send_shell_message("comm_close", content, callbacks, metadata, buffers);
|
||||
};
|
||||
|
||||
// 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._callback = function (key, msg) {
|
||||
var callback = this['_' + key + '_callback'];
|
||||
if (callback) {
|
||||
try {
|
||||
return callback(msg);
|
||||
} catch (e) {
|
||||
console.log("Exception in Comm callback", e, e.stack, msg);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Comm.prototype.handle_msg = function (msg) {
|
||||
return this._callback('msg', msg);
|
||||
};
|
||||
|
||||
Comm.prototype.handle_close = function (msg) {
|
||||
this._callback('close', msg);
|
||||
};
|
||||
|
||||
return {
|
||||
'CommManager': CommManager,
|
||||
'Comm': Comm
|
||||
};
|
||||
});
|
1263
venv/Lib/site-packages/notebook/static/services/kernels/kernel.js
Normal file
1263
venv/Lib/site-packages/notebook/static/services/kernels/kernel.js
Normal file
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,126 @@
|
|||
// Copyright (c) Jupyter Development Team.
|
||||
// Distributed under the terms of the Modified BSD License.
|
||||
|
||||
define([
|
||||
'underscore',
|
||||
], function (_) {
|
||||
"use strict";
|
||||
|
||||
var _deserialize_array_buffer = function (buf) {
|
||||
var data = new DataView(buf);
|
||||
// read the header: 1 + nbufs 32b integers
|
||||
var nbufs = data.getUint32(0);
|
||||
var offsets = [];
|
||||
var i;
|
||||
for (i = 1; i <= nbufs; i++) {
|
||||
offsets.push(data.getUint32(i * 4));
|
||||
}
|
||||
var json_bytes = new Uint8Array(buf.slice(offsets[0], offsets[1]));
|
||||
var msg = JSON.parse(
|
||||
(new TextDecoder('utf8')).decode(json_bytes)
|
||||
);
|
||||
// the remaining chunks are stored as DataViews in msg.buffers
|
||||
msg.buffers = [];
|
||||
var start, stop;
|
||||
for (i = 1; i < nbufs; i++) {
|
||||
start = offsets[i];
|
||||
stop = offsets[i+1] || buf.byteLength;
|
||||
msg.buffers.push(new DataView(buf.slice(start, stop)));
|
||||
}
|
||||
return msg;
|
||||
};
|
||||
|
||||
var _deserialize_binary = function(data) {
|
||||
/**
|
||||
* deserialize the binary message format
|
||||
* callback will be called with a message whose buffers attribute
|
||||
* will be an array of DataViews.
|
||||
*/
|
||||
if (data instanceof Blob) {
|
||||
// data is Blob, have to deserialize from ArrayBuffer in reader callback
|
||||
var reader = new FileReader();
|
||||
var promise = new Promise(function(resolve, reject) {
|
||||
reader.onload = function () {
|
||||
var msg = _deserialize_array_buffer(this.result);
|
||||
resolve(msg);
|
||||
};
|
||||
});
|
||||
reader.readAsArrayBuffer(data);
|
||||
return promise;
|
||||
} else {
|
||||
// data is ArrayBuffer, can deserialize directly
|
||||
var msg = _deserialize_array_buffer(data);
|
||||
return msg;
|
||||
}
|
||||
};
|
||||
|
||||
var deserialize = function (data) {
|
||||
/**
|
||||
* deserialize a message and return a promise for the unpacked message
|
||||
*/
|
||||
if (typeof data === "string") {
|
||||
// text JSON message
|
||||
return Promise.resolve(JSON.parse(data));
|
||||
} else {
|
||||
// binary message
|
||||
return Promise.resolve(_deserialize_binary(data));
|
||||
}
|
||||
};
|
||||
|
||||
var _serialize_binary = function (msg) {
|
||||
/**
|
||||
* implement the binary serialization protocol
|
||||
* serializes JSON message to ArrayBuffer
|
||||
*/
|
||||
msg = _.clone(msg);
|
||||
var offsets = [];
|
||||
var buffers = [];
|
||||
var i;
|
||||
for (i = 0; i < msg.buffers.length; i++) {
|
||||
// msg.buffers elements could be either views or ArrayBuffers
|
||||
// buffers elements are ArrayBuffers
|
||||
var b = msg.buffers[i];
|
||||
buffers.push(b.buffer instanceof ArrayBuffer ? b.buffer : b);
|
||||
}
|
||||
delete msg.buffers;
|
||||
var json_utf8 = (new TextEncoder('utf8')).encode(JSON.stringify(msg));
|
||||
buffers.unshift(json_utf8);
|
||||
var nbufs = buffers.length;
|
||||
offsets.push(4 * (nbufs + 1));
|
||||
for (i = 0; i + 1 < buffers.length; i++) {
|
||||
offsets.push(offsets[offsets.length-1] + buffers[i].byteLength);
|
||||
}
|
||||
var msg_buf = new Uint8Array(
|
||||
offsets[offsets.length-1] + buffers[buffers.length-1].byteLength
|
||||
);
|
||||
// use DataView.setUint32 for network byte-order
|
||||
var view = new DataView(msg_buf.buffer);
|
||||
// write nbufs to first 4 bytes
|
||||
view.setUint32(0, nbufs);
|
||||
// write offsets to next 4 * nbufs bytes
|
||||
for (i = 0; i < offsets.length; i++) {
|
||||
view.setUint32(4 * (i+1), offsets[i]);
|
||||
}
|
||||
// write all the buffers at their respective offsets
|
||||
for (i = 0; i < buffers.length; i++) {
|
||||
msg_buf.set(new Uint8Array(buffers[i]), offsets[i]);
|
||||
}
|
||||
|
||||
// return raw ArrayBuffer
|
||||
return msg_buf.buffer;
|
||||
};
|
||||
|
||||
var serialize = function (msg) {
|
||||
if (msg.buffers && msg.buffers.length) {
|
||||
return _serialize_binary(msg);
|
||||
} else {
|
||||
return JSON.stringify(msg);
|
||||
}
|
||||
};
|
||||
|
||||
var exports = {
|
||||
deserialize : deserialize,
|
||||
serialize: serialize
|
||||
};
|
||||
return exports;
|
||||
});
|
|
@ -0,0 +1,326 @@
|
|||
// Copyright (c) Jupyter Development Team.
|
||||
// Distributed under the terms of the Modified BSD License.
|
||||
|
||||
define([
|
||||
'jquery',
|
||||
'base/js/utils',
|
||||
'services/kernels/kernel',
|
||||
], function($, utils, kernel) {
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* Session object for accessing the session REST api. The session
|
||||
* should be used to start kernels and then shut them down -- for
|
||||
* all other operations, the kernel object should be used.
|
||||
*
|
||||
* Preliminary documentation for the REST API is at
|
||||
* https://github.com/ipython/ipython/wiki/IPEP-16%3A-Notebook-multi-directory-dashboard-and-URL-mapping#sessions-api
|
||||
*
|
||||
* Options should include:
|
||||
* - notebook_path: the path (not including name) to the notebook
|
||||
* - kernel_name: the type of kernel (e.g. python3)
|
||||
* - base_url: the root url of the notebook server
|
||||
* - ws_url: the url to access websockets
|
||||
* - notebook: Notebook object
|
||||
*
|
||||
* @class Session
|
||||
* @param {Object} options
|
||||
*/
|
||||
var Session = function (options) {
|
||||
this.id = null;
|
||||
this.notebook_model = {
|
||||
path: options.notebook_path
|
||||
};
|
||||
this.kernel_model = {
|
||||
id: null,
|
||||
name: options.kernel_name
|
||||
};
|
||||
|
||||
this.base_url = options.base_url;
|
||||
this.ws_url = options.ws_url;
|
||||
this.session_service_url = utils.url_path_join(this.base_url, 'api/sessions');
|
||||
this.session_url = null;
|
||||
|
||||
this.notebook = options.notebook;
|
||||
this.kernel = null;
|
||||
this.events = options.notebook.events;
|
||||
|
||||
this.bind_events();
|
||||
};
|
||||
|
||||
Session.prototype.bind_events = function () {
|
||||
var that = this;
|
||||
var record_status = function (evt, info) {
|
||||
console.log('Session: ' + evt.type + ' (' + info.session.id + ')');
|
||||
};
|
||||
|
||||
this.events.on('kernel_created.Session', record_status);
|
||||
this.events.on('kernel_dead.Session', record_status);
|
||||
this.events.on('kernel_killed.Session', record_status);
|
||||
|
||||
// if the kernel dies, then also remove the session
|
||||
this.events.on('kernel_dead.Kernel', function () {
|
||||
that.delete();
|
||||
});
|
||||
this.events.on('kernel_failed_restart.Kernel', function () {
|
||||
that.notebook.start_session();
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
// Public REST api functions
|
||||
|
||||
/**
|
||||
* GET /api/sessions
|
||||
*
|
||||
* Get a list of the current sessions.
|
||||
*
|
||||
* @function list
|
||||
* @param {function} [success] - function executed on ajax success
|
||||
* @param {function} [error] - function executed on ajax error
|
||||
*/
|
||||
Session.prototype.list = function (success, error) {
|
||||
utils.ajax(this.session_service_url, {
|
||||
processData: false,
|
||||
cache: false,
|
||||
type: "GET",
|
||||
dataType: "json",
|
||||
success: success,
|
||||
error: this._on_error(error)
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* POST /api/sessions
|
||||
*
|
||||
* Start a new session. This function can only executed once.
|
||||
*
|
||||
* @function start
|
||||
* @param {function} [success] - function executed on ajax success
|
||||
* @param {function} [error] - function executed on ajax error
|
||||
*/
|
||||
Session.prototype.start = function (success, error) {
|
||||
var that = this;
|
||||
var on_success = function (data, status, xhr) {
|
||||
if (that.kernel) {
|
||||
that.kernel.name = that.kernel_model.name;
|
||||
} else {
|
||||
var kernel_service_url = utils.url_path_join(that.base_url, "api/kernels");
|
||||
that.kernel = new kernel.Kernel(kernel_service_url, that.ws_url, that.kernel_model.name);
|
||||
}
|
||||
that.events.trigger('kernel_created.Session', {session: that, kernel: that.kernel});
|
||||
that.kernel._kernel_created(data.kernel);
|
||||
if (success) {
|
||||
success(data, status, xhr);
|
||||
}
|
||||
};
|
||||
var on_error = function (xhr, status, err) {
|
||||
that.events.trigger('kernel_dead.Session', {session: that, xhr: xhr, status: status, error: err});
|
||||
if (error) {
|
||||
error(xhr, status, err);
|
||||
}
|
||||
};
|
||||
|
||||
utils.ajax(this.session_service_url, {
|
||||
processData: false,
|
||||
cache: false,
|
||||
type: "POST",
|
||||
data: JSON.stringify(this._get_model()),
|
||||
contentType: 'application/json',
|
||||
dataType: "json",
|
||||
success: this._on_success(on_success),
|
||||
error: this._on_error(on_error)
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* GET /api/sessions/[:session_id]
|
||||
*
|
||||
* Get information about a session.
|
||||
*
|
||||
* @function get_info
|
||||
* @param {function} [success] - function executed on ajax success
|
||||
* @param {function} [error] - function executed on ajax error
|
||||
*/
|
||||
Session.prototype.get_info = function (success, error) {
|
||||
utils.ajax(this.session_url, {
|
||||
processData: false,
|
||||
cache: false,
|
||||
type: "GET",
|
||||
dataType: "json",
|
||||
success: this._on_success(success),
|
||||
error: this._on_error(error)
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* PATCH /api/sessions/[:session_id]
|
||||
*
|
||||
* Rename or move a notebook. If the given name or path are
|
||||
* undefined, then they will not be changed.
|
||||
*
|
||||
* @function rename_notebook
|
||||
* @param {string} [path] - new notebook path
|
||||
* @param {function} [success] - function executed on ajax success
|
||||
* @param {function} [error] - function executed on ajax error
|
||||
*/
|
||||
Session.prototype.rename_notebook = function (path, success, error) {
|
||||
if (path !== undefined) {
|
||||
this.notebook_model.path = path;
|
||||
}
|
||||
|
||||
utils.ajax(this.session_url, {
|
||||
processData: false,
|
||||
cache: false,
|
||||
type: "PATCH",
|
||||
data: JSON.stringify(this._get_model()),
|
||||
contentType: 'application/json',
|
||||
dataType: "json",
|
||||
success: this._on_success(success),
|
||||
error: this._on_error(error)
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* DELETE /api/sessions/[:session_id]
|
||||
*
|
||||
* Kill the kernel and shutdown the session.
|
||||
*
|
||||
* @function delete
|
||||
* @param {function} [success] - function executed on ajax success
|
||||
* @param {function} [error] - function executed on ajax error
|
||||
*/
|
||||
Session.prototype.delete = function (success, error) {
|
||||
if (this.kernel && this.kernel.is_connected()) {
|
||||
this.events.trigger('kernel_killed.Session', {session: this, kernel: this.kernel});
|
||||
this.kernel._kernel_dead();
|
||||
}
|
||||
|
||||
utils.ajax(this.session_url, {
|
||||
processData: false,
|
||||
cache: false,
|
||||
type: "DELETE",
|
||||
dataType: "json",
|
||||
success: this._on_success(success),
|
||||
error: this._on_error(error)
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Restart the session by deleting it and the starting it
|
||||
* fresh. If options are given, they can include any of the
|
||||
* following:
|
||||
*
|
||||
* - notebook_path - the path to the notebook
|
||||
* - kernel_name - the name (type) of the kernel
|
||||
*
|
||||
* @function restart
|
||||
* @param {Object} [options] - options for the new kernel
|
||||
* @param {function} [success] - function executed on ajax success
|
||||
* @param {function} [error] - function executed on ajax error
|
||||
*/
|
||||
Session.prototype.restart = function (options, success, error) {
|
||||
var that = this;
|
||||
var start = function () {
|
||||
if (options && options.notebook_path) {
|
||||
that.notebook_model.path = options.notebook_path;
|
||||
}
|
||||
if (options && options.kernel_name) {
|
||||
that.kernel_model.name = options.kernel_name;
|
||||
}
|
||||
that.kernel_model.id = null;
|
||||
that.start(success, error);
|
||||
};
|
||||
this.delete(start, start);
|
||||
};
|
||||
|
||||
// Helper functions
|
||||
|
||||
/**
|
||||
* Get the data model for the session, which includes the notebook path
|
||||
* and kernel (name and id).
|
||||
*
|
||||
* @function _get_model
|
||||
* @returns {Object} - the data model
|
||||
*/
|
||||
Session.prototype._get_model = function () {
|
||||
return {
|
||||
path: this.notebook_model.path,
|
||||
type: 'notebook',
|
||||
name: '',
|
||||
kernel: this.kernel_model
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Update the data model from the given JSON object, which should
|
||||
* have attributes of `id`, `notebook`, and/or `kernel`. If
|
||||
* provided, the notebook data must include name and path, and the
|
||||
* kernel data must include name and id.
|
||||
*
|
||||
* @function _update_model
|
||||
* @param {Object} data - updated data model
|
||||
*/
|
||||
Session.prototype._update_model = function (data) {
|
||||
if (data && data.id) {
|
||||
this.id = data.id;
|
||||
this.session_url = utils.url_path_join(this.session_service_url, this.id);
|
||||
}
|
||||
if (data && data.notebook) {
|
||||
this.notebook_model.path = data.path;
|
||||
}
|
||||
if (data && data.kernel) {
|
||||
this.kernel_model.name = data.kernel.name;
|
||||
this.kernel_model.id = data.kernel.id;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Handle a successful AJAX request by updating the session data
|
||||
* model with the response, and then optionally calling a provided
|
||||
* callback.
|
||||
*
|
||||
* @function _on_success
|
||||
* @param {function} success - callback
|
||||
*/
|
||||
Session.prototype._on_success = function (success) {
|
||||
var that = this;
|
||||
return function (data, status, xhr) {
|
||||
that._update_model(data);
|
||||
if (success) {
|
||||
success(data, status, xhr);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Handle a failed AJAX request by logging the error message, and
|
||||
* then optionally calling a provided callback.
|
||||
*
|
||||
* @function _on_error
|
||||
* @param {function} error - callback
|
||||
*/
|
||||
Session.prototype._on_error = function (error) {
|
||||
return function (xhr, status, err) {
|
||||
utils.log_ajax_error(xhr, status, err);
|
||||
if (error) {
|
||||
error(xhr, status, err);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Error type indicating that the session is already starting.
|
||||
*/
|
||||
var SessionAlreadyStarting = function (message) {
|
||||
this.name = "SessionAlreadyStarting";
|
||||
this.message = (message || "");
|
||||
};
|
||||
|
||||
SessionAlreadyStarting.prototype = Error.prototype;
|
||||
|
||||
return {
|
||||
Session: Session,
|
||||
SessionAlreadyStarting: SessionAlreadyStarting
|
||||
};
|
||||
});
|
Loading…
Add table
Add a link
Reference in a new issue