@jupyterlite/xeus-python-kernel
Version:
A Python kernel for JupyterLite, powered by Xeus
148 lines (147 loc) • 4.3 kB
JavaScript
// Copyright (c) Thorsten Beier
// Copyright (c) JupyterLite Contributors
// Distributed under the terms of the Modified BSD License.
import { wrap } from 'comlink';
import { Signal } from '@lumino/signaling';
import { PromiseDelegate } from '@lumino/coreutils';
import { PageConfig } from '@jupyterlab/coreutils';
export class WebWorkerKernel {
/**
* Instantiate a new WebWorkerKernel
*
* @param options The instantiation options for a new WebWorkerKernel
*/
constructor(options) {
this._isDisposed = false;
this._disposed = new Signal(this);
this._executeDelegate = new PromiseDelegate();
this._parentHeader = undefined;
this._parent = undefined;
const { id, name, sendMessage, location } = options;
this._id = id;
this._name = name;
this._location = location;
this._sendMessage = sendMessage;
this._worker = new Worker(new URL('./worker.js', import.meta.url), {
type: 'module'
});
this._worker.onmessage = e => {
this._processWorkerMessage(e.data);
};
this._remote = wrap(this._worker);
this.initFileSystem(options);
}
async handleMessage(msg) {
this._parent = msg;
this._parentHeader = msg.header;
await this._sendMessageToWorker(msg);
}
async _sendMessageToWorker(msg) {
// TODO Remove this??
if (msg.header.msg_type !== 'input_reply') {
this._executeDelegate = new PromiseDelegate();
}
await this._remote.processMessage({ msg, parent: this.parent });
if (msg.header.msg_type !== 'input_reply') {
return await this._executeDelegate.promise;
}
}
/**
* Get the last parent header
*/
get parentHeader() {
return this._parentHeader;
}
/**
* Get the last parent message (mimick ipykernel's get_parent)
*/
get parent() {
return this._parent;
}
/**
* Get the kernel location
*/
get location() {
return this._location;
}
/**
* Process a message coming from the pyodide web worker.
*
* @param msg The worker message to process.
*/
_processWorkerMessage(msg) {
var _a, _b, _c, _d;
if (!msg.header) {
return;
}
msg.header.session = (_b = (_a = this._parentHeader) === null || _a === void 0 ? void 0 : _a.session) !== null && _b !== void 0 ? _b : '';
msg.session = (_d = (_c = this._parentHeader) === null || _c === void 0 ? void 0 : _c.session) !== null && _d !== void 0 ? _d : '';
this._sendMessage(msg);
// resolve promise
if (msg.header.msg_type === 'status' &&
msg.content.execution_state === 'idle') {
this._executeDelegate.resolve();
}
}
/**
* A promise that is fulfilled when the kernel is ready.
*/
get ready() {
return Promise.resolve();
}
/**
* Return whether the kernel is disposed.
*/
get isDisposed() {
return this._isDisposed;
}
/**
* A signal emitted when the kernel is disposed.
*/
get disposed() {
return this._disposed;
}
/**
* Dispose the kernel.
*/
dispose() {
if (this.isDisposed) {
return;
}
this._worker.terminate();
this._worker = null;
this._remote = null;
this._isDisposed = true;
this._disposed.emit(void 0);
}
/**
* Get the kernel id
*/
get id() {
return this._id;
}
/**
* Get the name of the kernel
*/
get name() {
return this._name;
}
async initFileSystem(options) {
let driveName;
let localPath;
if (options.location.includes(':')) {
const parts = options.location.split(':');
driveName = parts[0];
localPath = parts[1];
}
else {
driveName = '';
localPath = options.location;
}
await this._remote.ready();
if (options.mountDrive) {
await this._remote.mount(driveName, '/drive', PageConfig.getBaseUrl());
await this._remote.cd(localPath);
}
}
}