pyodide 0.19.1 → 0.20.0-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/pyodide.js DELETED
@@ -1,302 +0,0 @@
1
- /**
2
- * The main bootstrap code for loading pyodide.
3
- */
4
- import { Module, setStandardStreams, setHomeDirectory } from "./module.js";
5
- import {
6
- loadScript,
7
- initializePackageIndex,
8
- _fetchBinaryFile,
9
- loadPackage,
10
- } from "./load-pyodide.js";
11
- import { makePublicAPI, registerJsModule } from "./api.js";
12
- import "./pyproxy.gen.js";
13
-
14
- /**
15
- * @typedef {import('./pyproxy.gen').PyProxy} PyProxy
16
- * @typedef {import('./pyproxy.gen').PyProxyWithLength} PyProxyWithLength
17
- * @typedef {import('./pyproxy.gen').PyProxyWithGet} PyProxyWithGet
18
- * @typedef {import('./pyproxy.gen').PyProxyWithSet} PyProxyWithSet
19
- * @typedef {import('./pyproxy.gen').PyProxyWithHas} PyProxyWithHas
20
- * @typedef {import('./pyproxy.gen').PyProxyIterable} PyProxyIterable
21
- * @typedef {import('./pyproxy.gen').PyProxyIterator} PyProxyIterator
22
- * @typedef {import('./pyproxy.gen').PyProxyAwaitable} PyProxyAwaitable
23
- * @typedef {import('./pyproxy.gen').PyProxyBuffer} PyProxyBuffer
24
- * @typedef {import('./pyproxy.gen').PyProxyCallable} PyProxyCallable
25
- *
26
- * @typedef {import('./pyproxy.gen').Py2JsResult} Py2JsResult
27
- *
28
- * @typedef {import('./pyproxy.gen').TypedArray} TypedArray
29
- * @typedef {import('./pyproxy.gen').PyBuffer} PyBuffer
30
- */
31
-
32
- /**
33
- * Dump the Python traceback to the browser console.
34
- *
35
- * @private
36
- */
37
- Module.dump_traceback = function () {
38
- const fd_stdout = 1;
39
- Module.__Py_DumpTraceback(fd_stdout, Module._PyGILState_GetThisThreadState());
40
- };
41
-
42
- let fatal_error_occurred = false;
43
- /**
44
- * Signal a fatal error.
45
- *
46
- * Dumps the Python traceback, shows a JavaScript traceback, and prints a clear
47
- * message indicating a fatal error. It then dummies out the public API so that
48
- * further attempts to use Pyodide will clearly indicate that Pyodide has failed
49
- * and can no longer be used. pyodide._module is left accessible, and it is
50
- * possible to continue using Pyodide for debugging purposes if desired.
51
- *
52
- * @argument e {Error} The cause of the fatal error.
53
- * @private
54
- */
55
- Module.fatal_error = function (e) {
56
- if (e.pyodide_fatal_error) {
57
- return;
58
- }
59
- if (fatal_error_occurred) {
60
- console.error("Recursive call to fatal_error. Inner error was:");
61
- console.error(e);
62
- return;
63
- }
64
- // Mark e so we know not to handle it later in EM_JS wrappers
65
- e.pyodide_fatal_error = true;
66
- fatal_error_occurred = true;
67
- console.error(
68
- "Pyodide has suffered a fatal error. Please report this to the Pyodide maintainers."
69
- );
70
- console.error("The cause of the fatal error was:");
71
- if (Module.inTestHoist) {
72
- // Test hoist won't print the error object in a useful way so convert it to
73
- // string.
74
- console.error(e.toString());
75
- console.error(e.stack);
76
- } else {
77
- console.error(e);
78
- }
79
- try {
80
- Module.dump_traceback();
81
- for (let key of Object.keys(Module.public_api)) {
82
- if (key.startsWith("_") || key === "version") {
83
- continue;
84
- }
85
- Object.defineProperty(Module.public_api, key, {
86
- enumerable: true,
87
- configurable: true,
88
- get: () => {
89
- throw new Error(
90
- "Pyodide already fatally failed and can no longer be used."
91
- );
92
- },
93
- });
94
- }
95
- if (Module.on_fatal) {
96
- Module.on_fatal(e);
97
- }
98
- } catch (err2) {
99
- console.error("Another error occurred while handling the fatal error:");
100
- console.error(err2);
101
- }
102
- throw e;
103
- };
104
-
105
- let runPythonInternal_dict; // Initialized in finalizeBootstrap
106
- /**
107
- * Just like `runPython` except uses a different globals dict and gets
108
- * `eval_code` from `_pyodide` so that it can work before `pyodide` is imported.
109
- * @private
110
- */
111
- Module.runPythonInternal = function (code) {
112
- return Module._pyodide._base.eval_code(code, runPythonInternal_dict);
113
- };
114
-
115
- /**
116
- * A proxy around globals that falls back to checking for a builtin if has or
117
- * get fails to find a global with the given key. Note that this proxy is
118
- * transparent to js2python: it won't notice that this wrapper exists at all and
119
- * will translate this proxy to the globals dictionary.
120
- * @private
121
- */
122
- function wrapPythonGlobals(globals_dict, builtins_dict) {
123
- return new Proxy(globals_dict, {
124
- get(target, symbol) {
125
- if (symbol === "get") {
126
- return (key) => {
127
- let result = target.get(key);
128
- if (result === undefined) {
129
- result = builtins_dict.get(key);
130
- }
131
- return result;
132
- };
133
- }
134
- if (symbol === "has") {
135
- return (key) => target.has(key) || builtins_dict.has(key);
136
- }
137
- return Reflect.get(target, symbol);
138
- },
139
- });
140
- }
141
-
142
- function unpackPyodidePy(pyodide_py_tar) {
143
- const fileName = "/pyodide_py.tar";
144
- let stream = Module.FS.open(fileName, "w");
145
- Module.FS.write(
146
- stream,
147
- new Uint8Array(pyodide_py_tar),
148
- 0,
149
- pyodide_py_tar.byteLength,
150
- undefined,
151
- true
152
- );
153
- Module.FS.close(stream);
154
- const code_ptr = Module.stringToNewUTF8(`
155
- import shutil
156
- shutil.unpack_archive("/pyodide_py.tar", "/lib/python3.9/site-packages/")
157
- del shutil
158
- import importlib
159
- importlib.invalidate_caches()
160
- del importlib
161
- `);
162
- let errcode = Module._PyRun_SimpleString(code_ptr);
163
- if (errcode) {
164
- throw new Error("OOPS!");
165
- }
166
- Module._free(code_ptr);
167
- Module.FS.unlink(fileName);
168
- }
169
-
170
- /**
171
- * This function is called after the emscripten module is finished initializing,
172
- * so eval_code is newly available.
173
- * It finishes the bootstrap so that once it is complete, it is possible to use
174
- * the core `pyodide` apis. (But package loading is not ready quite yet.)
175
- * @private
176
- */
177
- function finalizeBootstrap(config) {
178
- // First make internal dict so that we can use runPythonInternal.
179
- // runPythonInternal uses a separate namespace, so we don't pollute the main
180
- // environment with variables from our setup.
181
- runPythonInternal_dict = Module._pyodide._base.eval_code("{}");
182
- Module.importlib = Module.runPythonInternal("import importlib; importlib");
183
- let import_module = Module.importlib.import_module;
184
-
185
- Module.sys = import_module("sys");
186
- Module.sys.path.insert(0, config.homedir);
187
-
188
- // Set up globals
189
- let globals = Module.runPythonInternal("import __main__; __main__.__dict__");
190
- let builtins = Module.runPythonInternal("import builtins; builtins.__dict__");
191
- Module.globals = wrapPythonGlobals(globals, builtins);
192
-
193
- // Set up key Javascript modules.
194
- let importhook = Module._pyodide._importhook;
195
- importhook.register_js_finder();
196
- importhook.register_js_module("js", config.jsglobals);
197
-
198
- let pyodide = makePublicAPI();
199
- importhook.register_js_module("pyodide_js", pyodide);
200
-
201
- // import pyodide_py. We want to ensure that as much stuff as possible is
202
- // already set up before importing pyodide_py to simplify development of
203
- // pyodide_py code (Otherwise it's very hard to keep track of which things
204
- // aren't set up yet.)
205
- Module.pyodide_py = import_module("pyodide");
206
- Module.version = Module.pyodide_py.__version__;
207
-
208
- // copy some last constants onto public API.
209
- pyodide.pyodide_py = Module.pyodide_py;
210
- pyodide.version = Module.version;
211
- pyodide.globals = Module.globals;
212
- return pyodide;
213
- }
214
-
215
- /**
216
- * Load the main Pyodide wasm module and initialize it.
217
- *
218
- * Only one copy of Pyodide can be loaded in a given JavaScript global scope
219
- * because Pyodide uses global variables to load packages. If an attempt is made
220
- * to load a second copy of Pyodide, :any:`loadPyodide` will throw an error.
221
- * (This can be fixed once `Firefox adopts support for ES6 modules in webworkers
222
- * <https://bugzilla.mozilla.org/show_bug.cgi?id=1247687>`_.)
223
- *
224
- * @param {string} config.indexURL - The URL from which Pyodide will load
225
- * packages
226
- * @param {string} config.homedir - The home directory which Pyodide will use inside virtual file system
227
- * Default: /home/pyodide
228
- * @param {boolean} config.fullStdLib - Load the full Python standard library.
229
- * Setting this to false excludes following modules: distutils.
230
- * Default: true
231
- * @param {undefined | function(): string} config.stdin - Override the standard input callback. Should ask the user for one line of input.
232
- * Default: undefined
233
- * @param {undefined | function(string)} config.stdout - Override the standard output callback.
234
- * Default: undefined
235
- * @param {undefined | function(string)} config.stderr - Override the standard error output callback.
236
- * Default: undefined
237
- * @returns The :ref:`js-api-pyodide` module.
238
- * @memberof globalThis
239
- * @async
240
- */
241
- export async function loadPyodide(config) {
242
- if (globalThis.__pyodide_module) {
243
- throw new Error("Pyodide is already loading.");
244
- }
245
- if (!config.indexURL) {
246
- throw new Error("Please provide indexURL parameter to loadPyodide");
247
- }
248
-
249
- loadPyodide.inProgress = true;
250
- // A global "mount point" for the package loaders to talk to pyodide
251
- // See "--export-name=__pyodide_module" in buildpkg.py
252
- globalThis.__pyodide_module = Module;
253
-
254
- const default_config = {
255
- fullStdLib: true,
256
- jsglobals: globalThis,
257
- stdin: globalThis.prompt ? globalThis.prompt : undefined,
258
- homedir: "/home/pyodide",
259
- };
260
- config = Object.assign(default_config, config);
261
-
262
- if (!config.indexURL.endsWith("/")) {
263
- config.indexURL += "/";
264
- }
265
- Module.indexURL = config.indexURL;
266
- let packageIndexReady = initializePackageIndex(config.indexURL);
267
- let pyodide_py_tar_promise = _fetchBinaryFile(
268
- config.indexURL,
269
- "pyodide_py.tar"
270
- );
271
-
272
- setStandardStreams(config.stdin, config.stdout, config.stderr);
273
- setHomeDirectory(config.homedir);
274
-
275
- let moduleLoaded = new Promise((r) => (Module.postRun = r));
276
-
277
- const scriptSrc = `${config.indexURL}pyodide.asm.js`;
278
- await loadScript(scriptSrc);
279
-
280
- // _createPyodideModule is specified in the Makefile by the linker flag:
281
- // `-s EXPORT_NAME="'_createPyodideModule'"`
282
- await _createPyodideModule(Module);
283
-
284
- // There is some work to be done between the module being "ready" and postRun
285
- // being called.
286
- await moduleLoaded;
287
-
288
- const pyodide_py_tar = await pyodide_py_tar_promise;
289
- unpackPyodidePy(pyodide_py_tar);
290
- Module._pyodide_init();
291
-
292
- let pyodide = finalizeBootstrap(config);
293
- // Module.runPython works starting here.
294
-
295
- await packageIndexReady;
296
- if (config.fullStdLib) {
297
- await loadPackage(["distutils"]);
298
- }
299
- pyodide.runPython("print('Python initialization complete')");
300
- return pyodide;
301
- }
302
- globalThis.loadPyodide = loadPyodide;