@jupyterlite/xeus 4.0.0-a0 → 4.0.0-a10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/coincident.worker.d.ts +4 -3
- package/lib/coincident.worker.js +1 -1
- package/lib/coincident.worker.js.map +1 -1
- package/lib/comlink.worker.d.ts +4 -3
- package/lib/comlink.worker.js +1 -1
- package/lib/comlink.worker.js.map +1 -1
- package/lib/index.d.ts +1 -2
- package/lib/index.js +1 -2
- package/lib/interfaces.d.ts +11 -5
- package/lib/web_worker_kernel.d.ts +7 -0
- package/lib/web_worker_kernel.js +72 -12
- package/lib/worker.base.d.ts +76 -0
- package/lib/worker.base.js +185 -0
- package/lib/worker.d.ts +23 -11
- package/lib/worker.js +163 -124
- package/package.json +8 -9
package/lib/worker.js
CHANGED
|
@@ -2,28 +2,8 @@
|
|
|
2
2
|
// Copyright (c) JupyterLite Contributors
|
|
3
3
|
// Distributed under the terms of the Modified BSD License.
|
|
4
4
|
import { URLExt } from '@jupyterlab/coreutils';
|
|
5
|
-
import { bootstrapEmpackPackedEnvironment, bootstrapPython, getPythonVersion, loadShareLibs,
|
|
6
|
-
|
|
7
|
-
// when a toplevel cell uses an await, the cell is implicitly
|
|
8
|
-
// wrapped in a async function. Since the webloop - eventloop
|
|
9
|
-
// implementation does not support `eventloop.run_until_complete(f)`
|
|
10
|
-
// we need to convert the toplevel future in a javascript Promise
|
|
11
|
-
// this `toplevel` promise is then awaited before we
|
|
12
|
-
// execute the next cell. After the promise is awaited we need
|
|
13
|
-
// to do some cleanup and delete the python proxy
|
|
14
|
-
// (ie a js-wrapped python object) to avoid memory leaks
|
|
15
|
-
globalThis.toplevel_promise = null;
|
|
16
|
-
globalThis.toplevel_promise_py_proxy = null;
|
|
17
|
-
let resolveInputReply;
|
|
18
|
-
let kernelReady;
|
|
19
|
-
let rawXKernel;
|
|
20
|
-
let rawXServer;
|
|
21
|
-
async function get_stdin() {
|
|
22
|
-
const replyPromise = new Promise(resolve => {
|
|
23
|
-
resolveInputReply = resolve;
|
|
24
|
-
});
|
|
25
|
-
return replyPromise;
|
|
26
|
-
}
|
|
5
|
+
import { bootstrapEmpackPackedEnvironment, bootstrapPython, getPythonVersion, loadShareLibs, solve, installPackagesToEmscriptenFS, removePackagesFromEmscriptenFS, showPackagesList } from '@emscripten-forge/mambajs';
|
|
6
|
+
import { XeusRemoteKernelBase } from './worker.base';
|
|
27
7
|
async function fetchJson(url) {
|
|
28
8
|
const response = await fetch(url);
|
|
29
9
|
if (!response.ok) {
|
|
@@ -32,131 +12,190 @@ async function fetchJson(url) {
|
|
|
32
12
|
const json = await response.json();
|
|
33
13
|
return json;
|
|
34
14
|
}
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
this.
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
}
|
|
46
|
-
async cd(path) {
|
|
47
|
-
if (!path || !globalThis.Module.FS) {
|
|
48
|
-
return;
|
|
49
|
-
}
|
|
50
|
-
globalThis.Module.FS.chdir(path);
|
|
51
|
-
}
|
|
52
|
-
async isDir(path) {
|
|
53
|
-
try {
|
|
54
|
-
const lookup = globalThis.Module.FS.lookupPath(path);
|
|
55
|
-
return globalThis.Module.FS.isDir(lookup.node.mode);
|
|
56
|
-
}
|
|
57
|
-
catch (e) {
|
|
58
|
-
return false;
|
|
59
|
-
}
|
|
15
|
+
/**
|
|
16
|
+
* A worker kernel that is backed by an empack environment
|
|
17
|
+
*/
|
|
18
|
+
export class EmpackedXeusRemoteKernel extends XeusRemoteKernelBase {
|
|
19
|
+
constructor() {
|
|
20
|
+
super(...arguments);
|
|
21
|
+
this._prefix = '';
|
|
22
|
+
this._pkgRootUrl = '';
|
|
23
|
+
this._installedPackages = {};
|
|
24
|
+
this._paths = {};
|
|
60
25
|
}
|
|
61
|
-
async
|
|
62
|
-
const
|
|
63
|
-
await globalThis.ready;
|
|
64
|
-
if (globalThis.toplevel_promise !== null &&
|
|
65
|
-
globalThis.toplevel_promise_py_proxy !== null) {
|
|
66
|
-
await globalThis.toplevel_promise;
|
|
67
|
-
globalThis.toplevel_promise_py_proxy.delete();
|
|
68
|
-
globalThis.toplevel_promise_py_proxy = null;
|
|
69
|
-
globalThis.toplevel_promise = null;
|
|
70
|
-
}
|
|
71
|
-
if (msg_type === 'input_reply') {
|
|
72
|
-
resolveInputReply(event.msg);
|
|
73
|
-
}
|
|
74
|
-
else {
|
|
75
|
-
rawXServer.notify_listener(event.msg);
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
async initialize(options) {
|
|
79
|
-
const { baseUrl, kernelSpec, empackEnvMetaLink } = options;
|
|
26
|
+
async initializeModule(options) {
|
|
27
|
+
const { baseUrl, kernelSpec } = options;
|
|
80
28
|
// location of the kernel binary on the server
|
|
81
|
-
const
|
|
82
|
-
const
|
|
83
|
-
const
|
|
84
|
-
const
|
|
29
|
+
const binaryJS = URLExt.join(baseUrl, kernelSpec.argv[0]);
|
|
30
|
+
const binaryWASM = binaryJS.replace('.js', '.wasm');
|
|
31
|
+
const binaryDATA = binaryJS.replace('.js', '.data');
|
|
32
|
+
const kernelRootUrl = URLExt.join(baseUrl, 'xeus', kernelSpec.envName);
|
|
85
33
|
const sharedLibs = kernelSpec.metadata && kernelSpec.metadata.shared
|
|
86
34
|
? kernelSpec.metadata.shared
|
|
87
35
|
: {};
|
|
88
|
-
importScripts(
|
|
89
|
-
|
|
36
|
+
importScripts(binaryJS);
|
|
37
|
+
return {
|
|
90
38
|
locateFile: (file) => {
|
|
91
39
|
if (file in sharedLibs) {
|
|
92
|
-
return URLExt.join(
|
|
40
|
+
return URLExt.join(kernelRootUrl, kernelSpec.name, file);
|
|
93
41
|
}
|
|
94
42
|
if (file.endsWith('.wasm')) {
|
|
95
|
-
return
|
|
43
|
+
return binaryWASM;
|
|
96
44
|
}
|
|
97
45
|
else if (file.endsWith('.data')) {
|
|
98
46
|
// Handle the .data file if it exists
|
|
99
|
-
return
|
|
47
|
+
return binaryDATA;
|
|
100
48
|
}
|
|
101
49
|
return file;
|
|
102
50
|
}
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
async initializeFileSystem(options) {
|
|
54
|
+
const { baseUrl, kernelSpec, empackEnvMetaLink } = options;
|
|
55
|
+
if (this.Module.FS === undefined ||
|
|
56
|
+
this.Module.loadDynamicLibrary === undefined) {
|
|
57
|
+
throw new Error('Cannot load kernel without a valid FS');
|
|
58
|
+
}
|
|
59
|
+
// location of the kernel binary on the server
|
|
60
|
+
const kernelRootUrl = URLExt.join(baseUrl, 'xeus', 'kernels', kernelSpec.dir);
|
|
61
|
+
const empackEnvMetaLocation = empackEnvMetaLink || kernelRootUrl;
|
|
62
|
+
const packagesJsonUrl = `${empackEnvMetaLocation}/empack_env_meta.json`;
|
|
63
|
+
this._pkgRootUrl = URLExt.join(baseUrl, `xeus/${kernelSpec.envName}/kernel_packages`);
|
|
64
|
+
const empackEnvMeta = (await fetchJson(packagesJsonUrl));
|
|
65
|
+
// Initialize installed packages from empack env meta
|
|
66
|
+
this._installedPackages = {};
|
|
67
|
+
empackEnvMeta.packages.map(pkg => {
|
|
68
|
+
this._installedPackages[pkg.filename] = {
|
|
69
|
+
name: pkg.name,
|
|
70
|
+
version: pkg.version,
|
|
71
|
+
repo_url: pkg.channel ? pkg.channel : '',
|
|
72
|
+
url: pkg.url ? pkg.url : '',
|
|
73
|
+
repo_name: pkg.channel ? pkg.channel : '',
|
|
74
|
+
build_string: pkg.build
|
|
75
|
+
};
|
|
103
76
|
});
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
pythonVersion: pythonVersion,
|
|
127
|
-
Module: globalThis.Module
|
|
128
|
-
});
|
|
129
|
-
}
|
|
130
|
-
// Load shared libs
|
|
131
|
-
await loadShareLibs({
|
|
132
|
-
sharedLibs,
|
|
133
|
-
prefix: empackEnvMeta.prefix,
|
|
134
|
-
Module: globalThis.Module
|
|
135
|
-
});
|
|
136
|
-
}
|
|
137
|
-
rawXKernel = new globalThis.Module.xkernel();
|
|
138
|
-
rawXServer = rawXKernel.get_server();
|
|
139
|
-
if (!rawXServer) {
|
|
140
|
-
console.error('Failed to start kernel!');
|
|
77
|
+
this._pythonVersion = getPythonVersion(empackEnvMeta.packages);
|
|
78
|
+
this._prefix = empackEnvMeta.prefix;
|
|
79
|
+
const bootstrapped = await bootstrapEmpackPackedEnvironment({
|
|
80
|
+
empackEnvMeta,
|
|
81
|
+
pkgRootUrl: this._pkgRootUrl,
|
|
82
|
+
Module: this.Module,
|
|
83
|
+
logger: this.logger,
|
|
84
|
+
pythonVersion: this._pythonVersion
|
|
85
|
+
});
|
|
86
|
+
this._paths = bootstrapped.paths;
|
|
87
|
+
this._untarjs = bootstrapped.untarjs;
|
|
88
|
+
this._sharedLibs = bootstrapped.sharedLibs;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Initialize the interpreter if needed
|
|
92
|
+
* @param options
|
|
93
|
+
*/
|
|
94
|
+
async initializeInterpreter(options) {
|
|
95
|
+
// Bootstrap Python, if it's xeus-python
|
|
96
|
+
if (options.kernelSpec.name === 'xpython') {
|
|
97
|
+
if (!this._pythonVersion) {
|
|
98
|
+
throw new Error('Python is not installed, cannot start Python!');
|
|
141
99
|
}
|
|
142
|
-
|
|
100
|
+
this.logger.log('Starting Python');
|
|
101
|
+
await bootstrapPython({
|
|
102
|
+
prefix: this._prefix,
|
|
103
|
+
pythonVersion: this._pythonVersion,
|
|
104
|
+
Module: this.Module
|
|
105
|
+
});
|
|
143
106
|
}
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
107
|
+
// Load shared libs
|
|
108
|
+
await loadShareLibs({
|
|
109
|
+
sharedLibs: this._sharedLibs,
|
|
110
|
+
prefix: this._prefix,
|
|
111
|
+
Module: this.Module,
|
|
112
|
+
logger: this.logger
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
async install(channels, specs, pipSpecs) {
|
|
116
|
+
var _a, _b;
|
|
117
|
+
if (specs.length || pipSpecs.length) {
|
|
118
|
+
try {
|
|
119
|
+
this.logger.log(`Collecting ${(_a = (specs || pipSpecs)) === null || _a === void 0 ? void 0 : _a.join(',')}`);
|
|
120
|
+
const newPackages = await solve({
|
|
121
|
+
ymlOrSpecs: specs,
|
|
122
|
+
installedPackages: this._installedPackages,
|
|
123
|
+
pipSpecs,
|
|
124
|
+
channels,
|
|
125
|
+
logger: this.logger
|
|
126
|
+
});
|
|
127
|
+
await this._reloadPackagesInFS({
|
|
128
|
+
...newPackages.condaPackages,
|
|
129
|
+
...newPackages.pipPackages
|
|
130
|
+
});
|
|
148
131
|
}
|
|
149
|
-
|
|
150
|
-
|
|
132
|
+
catch (error) {
|
|
133
|
+
(_b = this.logger) === null || _b === void 0 ? void 0 : _b.error(error.stack);
|
|
151
134
|
}
|
|
152
135
|
}
|
|
153
|
-
kernelReady(1);
|
|
154
136
|
}
|
|
155
137
|
/**
|
|
156
|
-
*
|
|
157
|
-
* @param callback the callback to register
|
|
138
|
+
* Implements dynamic installation of packages
|
|
158
139
|
*/
|
|
159
|
-
|
|
160
|
-
this.
|
|
140
|
+
listInstalledPackages() {
|
|
141
|
+
showPackagesList(this._installedPackages, this.logger);
|
|
142
|
+
return Promise.resolve();
|
|
143
|
+
}
|
|
144
|
+
async _reloadPackagesInFS(newInstalledPackages) {
|
|
145
|
+
const removedPackages = {};
|
|
146
|
+
const newPackages = {};
|
|
147
|
+
// First create structures we can quickly inspect
|
|
148
|
+
const newInstalledPackagesMap = {};
|
|
149
|
+
for (const newInstalledPkg of Object.values(newInstalledPackages)) {
|
|
150
|
+
newInstalledPackagesMap[newInstalledPkg.name] = newInstalledPkg;
|
|
151
|
+
}
|
|
152
|
+
const oldInstalledPackagesMap = {};
|
|
153
|
+
for (const oldInstalledPkg of Object.values(this._installedPackages)) {
|
|
154
|
+
oldInstalledPackagesMap[oldInstalledPkg.name] = oldInstalledPkg;
|
|
155
|
+
}
|
|
156
|
+
// Compare old installed packages with new ones
|
|
157
|
+
for (const filename of Object.keys(this._installedPackages)) {
|
|
158
|
+
const installedPkg = this._installedPackages[filename];
|
|
159
|
+
// Exact same build of the package already installed
|
|
160
|
+
if (installedPkg.name in newInstalledPackagesMap &&
|
|
161
|
+
installedPkg.build_string ===
|
|
162
|
+
newInstalledPackagesMap[installedPkg.name].build_string) {
|
|
163
|
+
continue;
|
|
164
|
+
}
|
|
165
|
+
removedPackages[filename] = installedPkg;
|
|
166
|
+
}
|
|
167
|
+
// Compare new installed packages with old ones
|
|
168
|
+
for (const filename of Object.keys(newInstalledPackages)) {
|
|
169
|
+
const newPkg = newInstalledPackages[filename];
|
|
170
|
+
// Exact same build of the package already installed
|
|
171
|
+
if (newPkg.name in oldInstalledPackagesMap &&
|
|
172
|
+
newPkg.build_string ===
|
|
173
|
+
oldInstalledPackagesMap[newPkg.name].build_string) {
|
|
174
|
+
continue;
|
|
175
|
+
}
|
|
176
|
+
newPackages[filename] = newPkg;
|
|
177
|
+
}
|
|
178
|
+
await removePackagesFromEmscriptenFS({
|
|
179
|
+
removedPackages,
|
|
180
|
+
Module: this.Module,
|
|
181
|
+
paths: this._paths,
|
|
182
|
+
logger: this.logger
|
|
183
|
+
});
|
|
184
|
+
const { sharedLibs, paths } = await installPackagesToEmscriptenFS({
|
|
185
|
+
packages: newPackages,
|
|
186
|
+
pkgRootUrl: this._pkgRootUrl,
|
|
187
|
+
pythonVersion: this._pythonVersion,
|
|
188
|
+
Module: this.Module,
|
|
189
|
+
untarjs: this._untarjs,
|
|
190
|
+
logger: this.logger
|
|
191
|
+
});
|
|
192
|
+
this._paths = { ...this._paths, ...paths };
|
|
193
|
+
await loadShareLibs({
|
|
194
|
+
sharedLibs,
|
|
195
|
+
prefix: this._prefix,
|
|
196
|
+
Module: this.Module,
|
|
197
|
+
logger: this.logger
|
|
198
|
+
});
|
|
199
|
+
this._installedPackages = newInstalledPackages;
|
|
161
200
|
}
|
|
162
201
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jupyterlite/xeus",
|
|
3
|
-
"version": "4.0.0-
|
|
3
|
+
"version": "4.0.0-a10",
|
|
4
4
|
"description": "JupyterLite Xeus kernels",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"jupyter",
|
|
@@ -36,19 +36,18 @@
|
|
|
36
36
|
"watch:src": "tsc -w --sourceMap"
|
|
37
37
|
},
|
|
38
38
|
"dependencies": {
|
|
39
|
-
"@emscripten-forge/mambajs": "^0.
|
|
40
|
-
"@jupyterlab/coreutils": "^6",
|
|
41
|
-
"@jupyterlab/services": "^7.
|
|
42
|
-
"@jupyterlite/contents": "^0.
|
|
43
|
-
"@jupyterlite/kernel": "^0.
|
|
44
|
-
"@jupyterlite/server": "^0.
|
|
39
|
+
"@emscripten-forge/mambajs": "^0.12.0",
|
|
40
|
+
"@jupyterlab/coreutils": "^6.4.2",
|
|
41
|
+
"@jupyterlab/services": "^7.4.2",
|
|
42
|
+
"@jupyterlite/contents": "^0.6.0-beta.0",
|
|
43
|
+
"@jupyterlite/kernel": "^0.6.0-beta.0",
|
|
44
|
+
"@jupyterlite/server": "^0.6.0-beta.0",
|
|
45
45
|
"@lumino/coreutils": "^2",
|
|
46
46
|
"@lumino/signaling": "^2",
|
|
47
47
|
"coincident": "^1.2.3",
|
|
48
48
|
"comlink": "^4.4.1"
|
|
49
49
|
},
|
|
50
50
|
"devDependencies": {
|
|
51
|
-
"@jupyterlab/builder": "^4.1.0",
|
|
52
51
|
"@types/json-schema": "^7.0.11",
|
|
53
52
|
"@types/react": "^18.0.26",
|
|
54
53
|
"@types/react-addons-linked-state-mixin": "^0.14.22",
|
|
@@ -56,7 +55,7 @@
|
|
|
56
55
|
"rimraf": "^5.0.1",
|
|
57
56
|
"source-map-loader": "^1.0.2",
|
|
58
57
|
"ts-loader": "^9.2.6",
|
|
59
|
-
"typescript": "
|
|
58
|
+
"typescript": "^5.5",
|
|
60
59
|
"webpack": "^5.87.0",
|
|
61
60
|
"yjs": "^13.5.0"
|
|
62
61
|
},
|