pyodide 0.19.1 → 0.20.1-alpha.1
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/package.json +38 -9
- package/pyodide.ts +301 -0
- package/pyodide.umd.ts +3 -0
- package/api.js +0 -421
- package/error_handling.gen.ts +0 -294
- package/index.d.ts +0 -1
- package/index.test-d.ts +0 -162
- package/load-pyodide.js +0 -426
- package/module.js +0 -109
- package/pyodide.js +0 -302
- package/pyproxy.gen.ts +0 -1418
- package/rollup.config.js +0 -31
- package/test/conftest.js +0 -7
- package/test/filesystem.test.js +0 -12
- package/test/module.test.js +0 -10
- package/test/pyodide.test.mjs +0 -26
- package/tsconfig.json +0 -13
package/index.test-d.ts
DELETED
|
@@ -1,162 +0,0 @@
|
|
|
1
|
-
import { expectType, expectAssignable } from "tsd";
|
|
2
|
-
import {
|
|
3
|
-
loadPyodide,
|
|
4
|
-
Py2JsResult,
|
|
5
|
-
PyProxy,
|
|
6
|
-
PyProxyWithLength,
|
|
7
|
-
PyProxyWithGet,
|
|
8
|
-
PyProxyWithSet,
|
|
9
|
-
PyProxyWithHas,
|
|
10
|
-
PyProxyIterable,
|
|
11
|
-
PyProxyIterator,
|
|
12
|
-
PyProxyAwaitable,
|
|
13
|
-
PyProxyBuffer,
|
|
14
|
-
PyProxyCallable,
|
|
15
|
-
PyBuffer,
|
|
16
|
-
TypedArray,
|
|
17
|
-
} from "../../build/pyodide";
|
|
18
|
-
|
|
19
|
-
async function main() {
|
|
20
|
-
let pyodide = await loadPyodide({ indexURL: "blah" });
|
|
21
|
-
expectType<Promise<typeof pyodide>>(
|
|
22
|
-
loadPyodide({ indexURL: "blah", fullStdLib: true })
|
|
23
|
-
);
|
|
24
|
-
|
|
25
|
-
expectType<Promise<typeof pyodide>>(
|
|
26
|
-
loadPyodide({
|
|
27
|
-
indexURL: "blah",
|
|
28
|
-
fullStdLib: true,
|
|
29
|
-
stdin: () => "a string",
|
|
30
|
-
stdout: (x: string) => {},
|
|
31
|
-
stderr: (err: string) => {},
|
|
32
|
-
})
|
|
33
|
-
);
|
|
34
|
-
|
|
35
|
-
expectType<PyProxy>(pyodide.globals);
|
|
36
|
-
|
|
37
|
-
let x: Py2JsResult;
|
|
38
|
-
expectType<boolean>(pyodide.isPyProxy(x));
|
|
39
|
-
if (pyodide.isPyProxy(x)) {
|
|
40
|
-
expectType<PyProxy>(x);
|
|
41
|
-
} else {
|
|
42
|
-
expectType<number | string | boolean | bigint | undefined>(x);
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
let px: PyProxy = <PyProxy>{};
|
|
46
|
-
|
|
47
|
-
expectType<Py2JsResult>(pyodide.runPython("1+1"));
|
|
48
|
-
expectType<Py2JsResult>(pyodide.runPython("1+1", px));
|
|
49
|
-
|
|
50
|
-
expectType<Promise<void>>(pyodide.loadPackagesFromImports("import some_pkg"));
|
|
51
|
-
expectType<Promise<void>>(
|
|
52
|
-
pyodide.loadPackagesFromImports("import some_pkg", (x: any) =>
|
|
53
|
-
console.log(x)
|
|
54
|
-
)
|
|
55
|
-
);
|
|
56
|
-
expectType<Promise<void>>(
|
|
57
|
-
pyodide.loadPackagesFromImports(
|
|
58
|
-
"import some_pkg",
|
|
59
|
-
(x: any) => console.log(x),
|
|
60
|
-
(x: any) => console.warn(x)
|
|
61
|
-
)
|
|
62
|
-
);
|
|
63
|
-
|
|
64
|
-
expectType<Promise<void>>(pyodide.loadPackage("blah"));
|
|
65
|
-
expectType<Promise<void>>(pyodide.loadPackage(["blah", "blah2"]));
|
|
66
|
-
expectType<Promise<void>>(
|
|
67
|
-
pyodide.loadPackage("blah", (x: any) => console.log(x))
|
|
68
|
-
);
|
|
69
|
-
expectType<Promise<void>>(
|
|
70
|
-
pyodide.loadPackage(
|
|
71
|
-
["blah", "blah2"],
|
|
72
|
-
(x: any) => console.log(x),
|
|
73
|
-
(x: any) => console.warn(x)
|
|
74
|
-
)
|
|
75
|
-
);
|
|
76
|
-
expectType<Promise<void>>(pyodide.loadPackage(px));
|
|
77
|
-
|
|
78
|
-
expectType<PyProxy>(pyodide.pyodide_py);
|
|
79
|
-
expectType<void>(pyodide.registerJsModule("blah", { a: 7 }));
|
|
80
|
-
expectType<void>(pyodide.unregisterJsModule("blah"));
|
|
81
|
-
|
|
82
|
-
pyodide.setInterruptBuffer(new Int32Array(1));
|
|
83
|
-
expectType<PyProxy>(pyodide.toPy({}));
|
|
84
|
-
expectType<string>(pyodide.version);
|
|
85
|
-
|
|
86
|
-
expectType<Py2JsResult>(px.x);
|
|
87
|
-
expectType<PyProxy>(px.copy());
|
|
88
|
-
expectType<void>(px.destroy("blah"));
|
|
89
|
-
expectType<void>(px.destroy());
|
|
90
|
-
expectType<any>(px.toJs());
|
|
91
|
-
expectType<any>(px.toJs({}));
|
|
92
|
-
expectType<any>(px.toJs({ depth: 10 }));
|
|
93
|
-
expectType<any>(px.toJs({ create_pyproxies: false }));
|
|
94
|
-
expectType<any>(px.toJs({ create_pyproxies: true }));
|
|
95
|
-
expectType<any>(px.toJs({ pyproxies: [] }));
|
|
96
|
-
expectType<string>(px.toString());
|
|
97
|
-
expectType<string>(px.type);
|
|
98
|
-
|
|
99
|
-
if (px.supportsGet()) {
|
|
100
|
-
expectType<PyProxyWithGet>(px);
|
|
101
|
-
expectType<(x: any) => Py2JsResult>(px.get);
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
if (px.supportsHas()) {
|
|
105
|
-
expectType<PyProxyWithHas>(px);
|
|
106
|
-
expectType<(x: any) => boolean>(px.has);
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
if (px.supportsLength()) {
|
|
110
|
-
expectType<PyProxyWithLength>(px);
|
|
111
|
-
expectType<number>(px.length);
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
if (px.supportsSet()) {
|
|
115
|
-
expectType<PyProxyWithSet>(px);
|
|
116
|
-
expectType<(x: any, y: any) => void>(px.set);
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
if (px.isAwaitable()) {
|
|
120
|
-
expectType<PyProxyAwaitable>(px);
|
|
121
|
-
expectType<Py2JsResult>(await px);
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
if (px.isBuffer()) {
|
|
125
|
-
expectType<PyProxyBuffer>(px);
|
|
126
|
-
let buf = px.getBuffer();
|
|
127
|
-
expectType<PyBuffer>(buf);
|
|
128
|
-
expectType<boolean>(buf.c_contiguous);
|
|
129
|
-
expectType<TypedArray>(buf.data);
|
|
130
|
-
expectType<boolean>(buf.f_contiguous);
|
|
131
|
-
expectType<string>(buf.format);
|
|
132
|
-
expectType<number>(buf.itemsize);
|
|
133
|
-
expectType<number>(buf.nbytes);
|
|
134
|
-
expectType<number>(buf.ndim);
|
|
135
|
-
expectType<number>(buf.offset);
|
|
136
|
-
expectType<boolean>(buf.readonly);
|
|
137
|
-
expectType<() => void>(buf.release);
|
|
138
|
-
expectType<number[]>(buf.shape);
|
|
139
|
-
expectType<number[]>(buf.strides);
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
if (px.isCallable()) {
|
|
143
|
-
expectType<PyProxyCallable>(px);
|
|
144
|
-
expectType<Py2JsResult>(px(1, 2, 3));
|
|
145
|
-
expectAssignable<(...args: any[]) => Py2JsResult>(px);
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
if (px.isIterable()) {
|
|
149
|
-
expectType<PyProxyIterable>(px);
|
|
150
|
-
for (let x of px) {
|
|
151
|
-
expectType<Py2JsResult>(x);
|
|
152
|
-
}
|
|
153
|
-
let it = px[Symbol.iterator]();
|
|
154
|
-
expectAssignable<{ done?: Py2JsResult; value: Py2JsResult }>(it.next());
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
if (px.isIterator()) {
|
|
158
|
-
expectType<PyProxyIterator>(px);
|
|
159
|
-
expectAssignable<{ done?: Py2JsResult; value: Py2JsResult }>(px.next());
|
|
160
|
-
expectAssignable<{ done?: Py2JsResult; value: Py2JsResult }>(px.next(22));
|
|
161
|
-
}
|
|
162
|
-
}
|
package/load-pyodide.js
DELETED
|
@@ -1,426 +0,0 @@
|
|
|
1
|
-
import { Module } from "./module.js";
|
|
2
|
-
|
|
3
|
-
const IN_NODE =
|
|
4
|
-
typeof process !== "undefined" &&
|
|
5
|
-
process.release &&
|
|
6
|
-
process.release.name === "node" &&
|
|
7
|
-
typeof process.browser ===
|
|
8
|
-
"undefined"; /* This last condition checks if we run the browser shim of process */
|
|
9
|
-
|
|
10
|
-
/** @typedef {import('./pyproxy.js').PyProxy} PyProxy */
|
|
11
|
-
/** @private */
|
|
12
|
-
let baseURL;
|
|
13
|
-
/**
|
|
14
|
-
* @param {string} indexURL
|
|
15
|
-
* @private
|
|
16
|
-
*/
|
|
17
|
-
export async function initializePackageIndex(indexURL) {
|
|
18
|
-
baseURL = indexURL;
|
|
19
|
-
let package_json;
|
|
20
|
-
if (IN_NODE) {
|
|
21
|
-
const fsPromises = await import(/* webpackIgnore: true */ "fs/promises");
|
|
22
|
-
const package_string = await fsPromises.readFile(
|
|
23
|
-
`${indexURL}packages.json`
|
|
24
|
-
);
|
|
25
|
-
package_json = JSON.parse(package_string);
|
|
26
|
-
} else {
|
|
27
|
-
let response = await fetch(`${indexURL}packages.json`);
|
|
28
|
-
package_json = await response.json();
|
|
29
|
-
}
|
|
30
|
-
if (!package_json.packages) {
|
|
31
|
-
throw new Error(
|
|
32
|
-
"Loaded packages.json does not contain the expected key 'packages'."
|
|
33
|
-
);
|
|
34
|
-
}
|
|
35
|
-
Module.packages = package_json.packages;
|
|
36
|
-
|
|
37
|
-
// compute the inverted index for imports to package names
|
|
38
|
-
Module._import_name_to_package_name = new Map();
|
|
39
|
-
for (let name of Object.keys(Module.packages)) {
|
|
40
|
-
for (let import_name of Module.packages[name].imports) {
|
|
41
|
-
Module._import_name_to_package_name.set(import_name, name);
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
export async function _fetchBinaryFile(indexURL, path) {
|
|
47
|
-
if (IN_NODE) {
|
|
48
|
-
const fsPromises = await import(/* webpackIgnore: true */ "fs/promises");
|
|
49
|
-
const tar_buffer = await fsPromises.readFile(`${indexURL}${path}`);
|
|
50
|
-
return tar_buffer.buffer;
|
|
51
|
-
} else {
|
|
52
|
-
let response = await fetch(`${indexURL}${path}`);
|
|
53
|
-
return await response.arrayBuffer();
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
////////////////////////////////////////////////////////////
|
|
58
|
-
// Package loading
|
|
59
|
-
const DEFAULT_CHANNEL = "default channel";
|
|
60
|
-
|
|
61
|
-
// Regexp for validating package name and URI
|
|
62
|
-
const package_uri_regexp = /^.*?([^\/]*)\.js$/;
|
|
63
|
-
|
|
64
|
-
function _uri_to_package_name(package_uri) {
|
|
65
|
-
let match = package_uri_regexp.exec(package_uri);
|
|
66
|
-
if (match) {
|
|
67
|
-
return match[1].toLowerCase();
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
/**
|
|
72
|
-
* @param {string) url
|
|
73
|
-
* @async
|
|
74
|
-
* @private
|
|
75
|
-
*/
|
|
76
|
-
export let loadScript;
|
|
77
|
-
if (globalThis.document) {
|
|
78
|
-
// browser
|
|
79
|
-
loadScript = async (url) => await import(/* webpackIgnore: true */ url);
|
|
80
|
-
} else if (globalThis.importScripts) {
|
|
81
|
-
// webworker
|
|
82
|
-
loadScript = async (url) => {
|
|
83
|
-
// This is async only for consistency
|
|
84
|
-
globalThis.importScripts(url);
|
|
85
|
-
};
|
|
86
|
-
} else if (IN_NODE) {
|
|
87
|
-
const pathPromise = import(/* webpackIgnore: true */ "path").then(
|
|
88
|
-
(M) => M.default
|
|
89
|
-
);
|
|
90
|
-
const fetchPromise = import("node-fetch").then((M) => M.default);
|
|
91
|
-
const vmPromise = import(/* webpackIgnore: true */ "vm").then(
|
|
92
|
-
(M) => M.default
|
|
93
|
-
);
|
|
94
|
-
loadScript = async (url) => {
|
|
95
|
-
if (url.includes("://")) {
|
|
96
|
-
// If it's a url, have to load it with fetch and then eval it.
|
|
97
|
-
const fetch = await fetchPromise;
|
|
98
|
-
const vm = await vmPromise;
|
|
99
|
-
vm.runInThisContext(await (await fetch(url)).text());
|
|
100
|
-
} else {
|
|
101
|
-
// Otherwise, hopefully it is a relative path we can load from the file
|
|
102
|
-
// system.
|
|
103
|
-
const path = await pathPromise;
|
|
104
|
-
await import(path.resolve(url));
|
|
105
|
-
}
|
|
106
|
-
};
|
|
107
|
-
} else {
|
|
108
|
-
throw new Error("Cannot determine runtime environment");
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
function addPackageToLoad(name, toLoad) {
|
|
112
|
-
name = name.toLowerCase();
|
|
113
|
-
if (toLoad.has(name)) {
|
|
114
|
-
return;
|
|
115
|
-
}
|
|
116
|
-
toLoad.set(name, DEFAULT_CHANNEL);
|
|
117
|
-
// If the package is already loaded, we don't add dependencies, but warn
|
|
118
|
-
// the user later. This is especially important if the loaded package is
|
|
119
|
-
// from a custom url, in which case adding dependencies is wrong.
|
|
120
|
-
if (loadedPackages[name] !== undefined) {
|
|
121
|
-
return;
|
|
122
|
-
}
|
|
123
|
-
for (let dep_name of Module.packages[name].depends) {
|
|
124
|
-
addPackageToLoad(dep_name, toLoad);
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
function recursiveDependencies(
|
|
129
|
-
names,
|
|
130
|
-
_messageCallback,
|
|
131
|
-
errorCallback,
|
|
132
|
-
sharedLibsOnly
|
|
133
|
-
) {
|
|
134
|
-
const toLoad = new Map();
|
|
135
|
-
for (let name of names) {
|
|
136
|
-
const pkgname = _uri_to_package_name(name);
|
|
137
|
-
if (toLoad.has(pkgname) && toLoad.get(pkgname) !== name) {
|
|
138
|
-
errorCallback(
|
|
139
|
-
`Loading same package ${pkgname} from ${name} and ${toLoad.get(
|
|
140
|
-
pkgname
|
|
141
|
-
)}`
|
|
142
|
-
);
|
|
143
|
-
continue;
|
|
144
|
-
}
|
|
145
|
-
if (pkgname !== undefined) {
|
|
146
|
-
toLoad.set(pkgname, name);
|
|
147
|
-
continue;
|
|
148
|
-
}
|
|
149
|
-
name = name.toLowerCase();
|
|
150
|
-
if (name in Module.packages) {
|
|
151
|
-
addPackageToLoad(name, toLoad);
|
|
152
|
-
continue;
|
|
153
|
-
}
|
|
154
|
-
errorCallback(`Skipping unknown package '${name}'`);
|
|
155
|
-
}
|
|
156
|
-
if (sharedLibsOnly) {
|
|
157
|
-
let onlySharedLibs = new Map();
|
|
158
|
-
for (let c of toLoad) {
|
|
159
|
-
let name = c[0];
|
|
160
|
-
if (Module.packages[name].shared_library) {
|
|
161
|
-
onlySharedLibs.set(name, toLoad.get(name));
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
return onlySharedLibs;
|
|
165
|
-
}
|
|
166
|
-
return toLoad;
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
// locateFile is the function used by the .js file to locate the .data file
|
|
170
|
-
// given the filename
|
|
171
|
-
Module.locateFile = function (path) {
|
|
172
|
-
// handle packages loaded from custom URLs
|
|
173
|
-
let pkg = path.replace(/\.data$/, "");
|
|
174
|
-
const toLoad = Module.locateFile_packagesToLoad;
|
|
175
|
-
if (toLoad && toLoad.has(pkg)) {
|
|
176
|
-
let package_uri = toLoad.get(pkg);
|
|
177
|
-
if (package_uri != DEFAULT_CHANNEL) {
|
|
178
|
-
return package_uri.replace(/\.js$/, ".data");
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
return baseURL + path;
|
|
182
|
-
};
|
|
183
|
-
|
|
184
|
-
// When the JS loads, it synchronously adds a runDependency to emscripten. It
|
|
185
|
-
// then loads the data file, and removes the runDependency from emscripten.
|
|
186
|
-
// This function returns a promise that resolves when there are no pending
|
|
187
|
-
// runDependencies.
|
|
188
|
-
function waitRunDependency() {
|
|
189
|
-
const promise = new Promise((r) => {
|
|
190
|
-
Module.monitorRunDependencies = (n) => {
|
|
191
|
-
if (n === 0) {
|
|
192
|
-
r();
|
|
193
|
-
}
|
|
194
|
-
};
|
|
195
|
-
});
|
|
196
|
-
// If there are no pending dependencies left, monitorRunDependencies will
|
|
197
|
-
// never be called. Since we can't check the number of dependencies,
|
|
198
|
-
// manually trigger a call.
|
|
199
|
-
Module.addRunDependency("dummy");
|
|
200
|
-
Module.removeRunDependency("dummy");
|
|
201
|
-
return promise;
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
async function _loadPackage(names, messageCallback, errorCallback) {
|
|
205
|
-
// toLoad is a map pkg_name => pkg_uri
|
|
206
|
-
let toLoad = recursiveDependencies(names, messageCallback, errorCallback);
|
|
207
|
-
// Tell Module.locateFile about the packages we're loading
|
|
208
|
-
Module.locateFile_packagesToLoad = toLoad;
|
|
209
|
-
if (toLoad.size === 0) {
|
|
210
|
-
return Promise.resolve("No new packages to load");
|
|
211
|
-
} else {
|
|
212
|
-
let packageNames = Array.from(toLoad.keys()).join(", ");
|
|
213
|
-
messageCallback(`Loading ${packageNames}`);
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
// This is a collection of promises that resolve when the package's JS file is
|
|
217
|
-
// loaded. The promises already handle error and never fail.
|
|
218
|
-
let scriptPromises = [];
|
|
219
|
-
|
|
220
|
-
for (let [pkg, uri] of toLoad) {
|
|
221
|
-
let loaded = loadedPackages[pkg];
|
|
222
|
-
if (loaded !== undefined) {
|
|
223
|
-
// If uri is from the DEFAULT_CHANNEL, we assume it was added as a
|
|
224
|
-
// depedency, which was previously overridden.
|
|
225
|
-
if (loaded === uri || uri === DEFAULT_CHANNEL) {
|
|
226
|
-
messageCallback(`${pkg} already loaded from ${loaded}`);
|
|
227
|
-
continue;
|
|
228
|
-
} else {
|
|
229
|
-
errorCallback(
|
|
230
|
-
`URI mismatch, attempting to load package ${pkg} from ${uri} ` +
|
|
231
|
-
`while it is already loaded from ${loaded}. To override a dependency, ` +
|
|
232
|
-
`load the custom package first.`
|
|
233
|
-
);
|
|
234
|
-
continue;
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
let pkgname = (Module.packages[pkg] && Module.packages[pkg].name) || pkg;
|
|
238
|
-
let scriptSrc = uri === DEFAULT_CHANNEL ? `${baseURL}${pkgname}.js` : uri;
|
|
239
|
-
messageCallback(`Loading ${pkg} from ${scriptSrc}`);
|
|
240
|
-
scriptPromises.push(
|
|
241
|
-
loadScript(scriptSrc).catch((e) => {
|
|
242
|
-
errorCallback(`Couldn't load package from URL ${scriptSrc}`, e);
|
|
243
|
-
toLoad.delete(pkg);
|
|
244
|
-
})
|
|
245
|
-
);
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
// We must start waiting for runDependencies *after* all the JS files are
|
|
249
|
-
// loaded, since the number of runDependencies may happen to equal zero
|
|
250
|
-
// between package files loading.
|
|
251
|
-
try {
|
|
252
|
-
await Promise.all(scriptPromises).then(waitRunDependency);
|
|
253
|
-
} finally {
|
|
254
|
-
delete Module.monitorRunDependencies;
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
let packageList = [];
|
|
258
|
-
for (let [pkg, uri] of toLoad) {
|
|
259
|
-
loadedPackages[pkg] = uri;
|
|
260
|
-
packageList.push(pkg);
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
let resolveMsg;
|
|
264
|
-
if (packageList.length > 0) {
|
|
265
|
-
let packageNames = packageList.join(", ");
|
|
266
|
-
resolveMsg = `Loaded ${packageNames}`;
|
|
267
|
-
} else {
|
|
268
|
-
resolveMsg = "No packages loaded";
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
Module.reportUndefinedSymbols();
|
|
272
|
-
|
|
273
|
-
messageCallback(resolveMsg);
|
|
274
|
-
|
|
275
|
-
// We have to invalidate Python's import caches, or it won't
|
|
276
|
-
// see the new files.
|
|
277
|
-
Module.importlib.invalidate_caches();
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
// This is a promise that is resolved iff there are no pending package loads. It
|
|
281
|
-
// never fails.
|
|
282
|
-
let _package_lock = Promise.resolve();
|
|
283
|
-
|
|
284
|
-
/**
|
|
285
|
-
* An async lock for package loading. Prevents race conditions in loadPackage.
|
|
286
|
-
* @returns A zero argument function that releases the lock.
|
|
287
|
-
* @private
|
|
288
|
-
*/
|
|
289
|
-
async function acquirePackageLock() {
|
|
290
|
-
let old_lock = _package_lock;
|
|
291
|
-
let releaseLock;
|
|
292
|
-
_package_lock = new Promise((resolve) => (releaseLock = resolve));
|
|
293
|
-
await old_lock;
|
|
294
|
-
return releaseLock;
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
/**
|
|
298
|
-
*
|
|
299
|
-
* The list of packages that Pyodide has loaded.
|
|
300
|
-
* Use ``Object.keys(pyodide.loadedPackages)`` to get the list of names of
|
|
301
|
-
* loaded packages, and ``pyodide.loadedPackages[package_name]`` to access
|
|
302
|
-
* install location for a particular ``package_name``.
|
|
303
|
-
*
|
|
304
|
-
* @type {object}
|
|
305
|
-
*/
|
|
306
|
-
export let loadedPackages = {};
|
|
307
|
-
|
|
308
|
-
let sharedLibraryWasmPlugin;
|
|
309
|
-
let origWasmPlugin;
|
|
310
|
-
let wasmPluginIndex;
|
|
311
|
-
function initSharedLibraryWasmPlugin() {
|
|
312
|
-
for (let p in Module.preloadPlugins) {
|
|
313
|
-
if (Module.preloadPlugins[p].canHandle("test.so")) {
|
|
314
|
-
origWasmPlugin = Module.preloadPlugins[p];
|
|
315
|
-
wasmPluginIndex = p;
|
|
316
|
-
break;
|
|
317
|
-
}
|
|
318
|
-
}
|
|
319
|
-
sharedLibraryWasmPlugin = {
|
|
320
|
-
canHandle: origWasmPlugin.canHandle,
|
|
321
|
-
handle(byteArray, name, onload, onerror) {
|
|
322
|
-
origWasmPlugin.handle(byteArray, name, onload, onerror);
|
|
323
|
-
origWasmPlugin.asyncWasmLoadPromise = (async () => {
|
|
324
|
-
await origWasmPlugin.asyncWasmLoadPromise;
|
|
325
|
-
Module.loadDynamicLibrary(name, {
|
|
326
|
-
global: true,
|
|
327
|
-
nodelete: true,
|
|
328
|
-
});
|
|
329
|
-
})();
|
|
330
|
-
},
|
|
331
|
-
};
|
|
332
|
-
}
|
|
333
|
-
|
|
334
|
-
// override the load plugin so that it calls "Module.loadDynamicLibrary" on any
|
|
335
|
-
// .so files.
|
|
336
|
-
// this only needs to be done for shared library packages because we assume that
|
|
337
|
-
// if a package depends on a shared library it needs to have access to it. not
|
|
338
|
-
// needed for .so in standard module because those are linked together
|
|
339
|
-
// correctly, it is only where linking goes across modules that it needs to be
|
|
340
|
-
// done. Hence, we only put this extra preload plugin in during the shared
|
|
341
|
-
// library load
|
|
342
|
-
function useSharedLibraryWasmPlugin() {
|
|
343
|
-
if (!sharedLibraryWasmPlugin) {
|
|
344
|
-
initSharedLibraryWasmPlugin();
|
|
345
|
-
}
|
|
346
|
-
Module.preloadPlugins[wasmPluginIndex] = sharedLibraryWasmPlugin;
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
function restoreOrigWasmPlugin() {
|
|
350
|
-
Module.preloadPlugins[wasmPluginIndex] = origWasmPlugin;
|
|
351
|
-
}
|
|
352
|
-
|
|
353
|
-
/**
|
|
354
|
-
* @callback LogFn
|
|
355
|
-
* @param {string} msg
|
|
356
|
-
* @returns {void}
|
|
357
|
-
* @private
|
|
358
|
-
*/
|
|
359
|
-
|
|
360
|
-
/**
|
|
361
|
-
* Load a package or a list of packages over the network. This installs the
|
|
362
|
-
* package in the virtual filesystem. The package needs to be imported from
|
|
363
|
-
* Python before it can be used.
|
|
364
|
-
*
|
|
365
|
-
* @param {string | string[] | PyProxy} names Either a single package name or
|
|
366
|
-
* URL or a list of them. URLs can be absolute or relative. The URLs must have
|
|
367
|
-
* file name ``<package-name>.js`` and there must be a file called
|
|
368
|
-
* ``<package-name>.data`` in the same directory. The argument can be a
|
|
369
|
-
* ``PyProxy`` of a list, in which case the list will be converted to JavaScript
|
|
370
|
-
* and the ``PyProxy`` will be destroyed.
|
|
371
|
-
* @param {LogFn=} messageCallback A callback, called with progress messages
|
|
372
|
-
* (optional)
|
|
373
|
-
* @param {LogFn=} errorCallback A callback, called with error/warning messages
|
|
374
|
-
* (optional)
|
|
375
|
-
* @async
|
|
376
|
-
*/
|
|
377
|
-
export async function loadPackage(names, messageCallback, errorCallback) {
|
|
378
|
-
if (Module.isPyProxy(names)) {
|
|
379
|
-
let temp;
|
|
380
|
-
try {
|
|
381
|
-
temp = names.toJs();
|
|
382
|
-
} finally {
|
|
383
|
-
names.destroy();
|
|
384
|
-
}
|
|
385
|
-
names = temp;
|
|
386
|
-
}
|
|
387
|
-
|
|
388
|
-
if (!Array.isArray(names)) {
|
|
389
|
-
names = [names];
|
|
390
|
-
}
|
|
391
|
-
// get shared library packages and load those first
|
|
392
|
-
// otherwise bad things happen with linking them in firefox.
|
|
393
|
-
let sharedLibraryNames = [];
|
|
394
|
-
try {
|
|
395
|
-
let sharedLibraryPackagesToLoad = recursiveDependencies(
|
|
396
|
-
names,
|
|
397
|
-
messageCallback,
|
|
398
|
-
errorCallback,
|
|
399
|
-
true
|
|
400
|
-
);
|
|
401
|
-
for (let pkg of sharedLibraryPackagesToLoad) {
|
|
402
|
-
sharedLibraryNames.push(pkg[0]);
|
|
403
|
-
}
|
|
404
|
-
} catch (e) {
|
|
405
|
-
// do nothing - let the main load throw any errors
|
|
406
|
-
}
|
|
407
|
-
|
|
408
|
-
let releaseLock = await acquirePackageLock();
|
|
409
|
-
try {
|
|
410
|
-
useSharedLibraryWasmPlugin();
|
|
411
|
-
await _loadPackage(
|
|
412
|
-
sharedLibraryNames,
|
|
413
|
-
messageCallback || console.log,
|
|
414
|
-
errorCallback || console.error
|
|
415
|
-
);
|
|
416
|
-
restoreOrigWasmPlugin();
|
|
417
|
-
await _loadPackage(
|
|
418
|
-
names,
|
|
419
|
-
messageCallback || console.log,
|
|
420
|
-
errorCallback || console.error
|
|
421
|
-
);
|
|
422
|
-
} finally {
|
|
423
|
-
restoreOrigWasmPlugin();
|
|
424
|
-
releaseLock();
|
|
425
|
-
}
|
|
426
|
-
}
|
package/module.js
DELETED
|
@@ -1,109 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @typedef {import('emscripten').Module} Module
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* The Emscripten Module.
|
|
7
|
-
*
|
|
8
|
-
* @private
|
|
9
|
-
* @type {Module}
|
|
10
|
-
*/
|
|
11
|
-
export let Module = {};
|
|
12
|
-
Module.noImageDecoding = true;
|
|
13
|
-
Module.noAudioDecoding = true;
|
|
14
|
-
Module.noWasmDecoding = false; // we preload wasm using the built in plugin now
|
|
15
|
-
Module.preloadedWasm = {};
|
|
16
|
-
Module.preRun = [];
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
*
|
|
20
|
-
* @param {undefined | function(): string} stdin
|
|
21
|
-
* @param {undefined | function(string)} stdout
|
|
22
|
-
* @param {undefined | function(string)} stderr
|
|
23
|
-
* @private
|
|
24
|
-
*/
|
|
25
|
-
export function setStandardStreams(stdin, stdout, stderr) {
|
|
26
|
-
// For stdout and stderr, emscripten provides convenient wrappers that save us the trouble of converting the bytes into a string
|
|
27
|
-
if (stdout) {
|
|
28
|
-
Module.print = stdout;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
if (stderr) {
|
|
32
|
-
Module.printErr = stderr;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
// For stdin, we have to deal with the low level API ourselves
|
|
36
|
-
if (stdin) {
|
|
37
|
-
Module.preRun.push(function () {
|
|
38
|
-
Module.FS.init(createStdinWrapper(stdin), null, null);
|
|
39
|
-
});
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
function createStdinWrapper(stdin) {
|
|
44
|
-
// When called, it asks the user for one whole line of input (stdin)
|
|
45
|
-
// Then, it passes the individual bytes of the input to emscripten, one after another.
|
|
46
|
-
// And finally, it terminates it with null.
|
|
47
|
-
const encoder = new TextEncoder();
|
|
48
|
-
let input = new Uint8Array(0);
|
|
49
|
-
let inputIndex = -1; // -1 means that we just returned null
|
|
50
|
-
function stdinWrapper() {
|
|
51
|
-
try {
|
|
52
|
-
if (inputIndex === -1) {
|
|
53
|
-
let text = stdin();
|
|
54
|
-
if (text === undefined || text === null) {
|
|
55
|
-
return null;
|
|
56
|
-
}
|
|
57
|
-
if (typeof text !== "string") {
|
|
58
|
-
throw new TypeError(
|
|
59
|
-
`Expected stdin to return string, null, or undefined, got type ${typeof text}.`
|
|
60
|
-
);
|
|
61
|
-
}
|
|
62
|
-
if (!text.endsWith("\n")) {
|
|
63
|
-
text += "\n";
|
|
64
|
-
}
|
|
65
|
-
input = encoder.encode(text);
|
|
66
|
-
inputIndex = 0;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
if (inputIndex < input.length) {
|
|
70
|
-
let character = input[inputIndex];
|
|
71
|
-
inputIndex++;
|
|
72
|
-
return character;
|
|
73
|
-
} else {
|
|
74
|
-
inputIndex = -1;
|
|
75
|
-
return null;
|
|
76
|
-
}
|
|
77
|
-
} catch (e) {
|
|
78
|
-
// emscripten will catch this and set an IOError which is unhelpful for
|
|
79
|
-
// debugging.
|
|
80
|
-
console.error("Error thrown in stdin:");
|
|
81
|
-
console.error(e);
|
|
82
|
-
throw e;
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
return stdinWrapper;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
/**
|
|
89
|
-
* Make the home directory inside the virtual file system,
|
|
90
|
-
* then change the working directory to it.
|
|
91
|
-
*
|
|
92
|
-
* @param {string} path
|
|
93
|
-
* @private
|
|
94
|
-
*/
|
|
95
|
-
export function setHomeDirectory(path) {
|
|
96
|
-
Module.preRun.push(function () {
|
|
97
|
-
const fallbackPath = "/";
|
|
98
|
-
try {
|
|
99
|
-
Module.FS.mkdirTree(path);
|
|
100
|
-
} catch (e) {
|
|
101
|
-
console.error(`Error occurred while making a home directory '${path}':`);
|
|
102
|
-
console.error(e);
|
|
103
|
-
console.error(`Using '${fallbackPath}' for a home directory instead`);
|
|
104
|
-
path = fallbackPath;
|
|
105
|
-
}
|
|
106
|
-
Module.ENV.HOME = path;
|
|
107
|
-
Module.FS.chdir(path);
|
|
108
|
-
});
|
|
109
|
-
}
|