pyodide 0.18.0 → 0.19.0
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/README.md +4 -4
- package/api.js +113 -53
- package/index.test-d.ts +12 -9
- package/load-pyodide.js +141 -112
- package/module.js +37 -9
- package/package.json +1 -1
- package/pyodide.js +145 -157
- package/pyproxy.gen.js +36 -88
package/pyproxy.gen.js
CHANGED
|
@@ -132,11 +132,8 @@
|
|
|
132
132
|
* the callPyObject method, but of course one can also execute arbitrary code
|
|
133
133
|
* via the various __dundermethods__ associated to classes.
|
|
134
134
|
*
|
|
135
|
-
* The only entrypoint into Python that avoids this file is our bootstrap method
|
|
136
|
-
* runPythonSimple which is defined in main.c
|
|
137
|
-
*
|
|
138
135
|
* Any time we call into wasm, the call should be wrapped in a try catch block.
|
|
139
|
-
* This way if a
|
|
136
|
+
* This way if a JavaScript error emerges from the wasm, we can escalate it to a
|
|
140
137
|
* fatal error.
|
|
141
138
|
*
|
|
142
139
|
* This is file is preprocessed with -imacros "pyproxy.c". As a result of this,
|
|
@@ -160,6 +157,7 @@ Module.isPyProxy = isPyProxy;
|
|
|
160
157
|
|
|
161
158
|
if (globalThis.FinalizationRegistry) {
|
|
162
159
|
Module.finalizationRegistry = new FinalizationRegistry(([ptr, cache]) => {
|
|
160
|
+
cache.leaked = (!!1);
|
|
163
161
|
pyproxy_decref_cache(cache);
|
|
164
162
|
try {
|
|
165
163
|
Module._Py_DecRef(ptr);
|
|
@@ -172,7 +170,7 @@ if (globalThis.FinalizationRegistry) {
|
|
|
172
170
|
// For some unclear reason this code screws up selenium FirefoxDriver. Works
|
|
173
171
|
// fine in chrome and when I test it in browser. It seems to be sensitive to
|
|
174
172
|
// changes that don't make a difference to the semantics.
|
|
175
|
-
// TODO: after
|
|
173
|
+
// TODO: after 0.18.0, fix selenium issues with this code.
|
|
176
174
|
// Module.bufferFinalizationRegistry = new FinalizationRegistry((ptr) => {
|
|
177
175
|
// try {
|
|
178
176
|
// Module._PyBuffer_Release(ptr);
|
|
@@ -248,7 +246,7 @@ Module.pyproxy_new = function (ptrobj, cache) {
|
|
|
248
246
|
}
|
|
249
247
|
cache.refcnt++;
|
|
250
248
|
Object.defineProperty(target, "$$", {
|
|
251
|
-
value: { ptr: ptrobj, type: "PyProxy",
|
|
249
|
+
value: { ptr: ptrobj, type: "PyProxy", cache },
|
|
252
250
|
});
|
|
253
251
|
Module._Py_IncRef(ptrobj);
|
|
254
252
|
let proxy = new Proxy(target, PyProxyHandlers);
|
|
@@ -318,9 +316,6 @@ Module.getPyProxyClass = function (flags) {
|
|
|
318
316
|
|
|
319
317
|
// Static methods
|
|
320
318
|
Module.PyProxy_getPtr = _getPtr;
|
|
321
|
-
Module.pyproxy_mark_borrowed = function (proxy) {
|
|
322
|
-
proxy.$$.borrowed = (!!1);
|
|
323
|
-
};
|
|
324
319
|
|
|
325
320
|
const pyproxy_cache_destroyed_msg =
|
|
326
321
|
"This borrowed attribute proxy was automatically destroyed in the " +
|
|
@@ -334,18 +329,21 @@ function pyproxy_decref_cache(cache) {
|
|
|
334
329
|
if (cache.refcnt === 0) {
|
|
335
330
|
let cache_map = Module.hiwire.pop_value(cache.cacheId);
|
|
336
331
|
for (let proxy_id of cache_map.values()) {
|
|
337
|
-
Module.
|
|
338
|
-
|
|
339
|
-
pyproxy_cache_destroyed_msg
|
|
340
|
-
|
|
332
|
+
const cache_entry = Module.hiwire.pop_value(proxy_id);
|
|
333
|
+
if (!cache.leaked) {
|
|
334
|
+
Module.pyproxy_destroy(cache_entry, pyproxy_cache_destroyed_msg);
|
|
335
|
+
}
|
|
341
336
|
}
|
|
342
337
|
}
|
|
343
338
|
}
|
|
344
339
|
|
|
345
340
|
Module.pyproxy_destroy = function (proxy, destroyed_msg) {
|
|
341
|
+
if (proxy.$$.ptr === null) {
|
|
342
|
+
return;
|
|
343
|
+
}
|
|
346
344
|
let ptrobj = _getPtr(proxy);
|
|
347
345
|
Module.finalizationRegistry.unregister(proxy);
|
|
348
|
-
// Maybe the destructor will call
|
|
346
|
+
// Maybe the destructor will call JavaScript code that will somehow try
|
|
349
347
|
// to use this proxy. Mark it deleted before decrementing reference count
|
|
350
348
|
// just in case!
|
|
351
349
|
proxy.$$.ptr = null;
|
|
@@ -360,7 +358,7 @@ Module.pyproxy_destroy = function (proxy, destroyed_msg) {
|
|
|
360
358
|
};
|
|
361
359
|
|
|
362
360
|
// Now a lot of boilerplate to wrap the abstract Object protocol wrappers
|
|
363
|
-
// defined in pyproxy.c in
|
|
361
|
+
// defined in pyproxy.c in JavaScript functions.
|
|
364
362
|
|
|
365
363
|
Module.callPyObjectKwargs = function (ptrobj, ...jsargs) {
|
|
366
364
|
// We don't do any checking for kwargs, checks are in PyProxy.callKwargs
|
|
@@ -462,9 +460,7 @@ class PyProxyClass {
|
|
|
462
460
|
* destroyed".
|
|
463
461
|
*/
|
|
464
462
|
destroy(destroyed_msg) {
|
|
465
|
-
|
|
466
|
-
Module.pyproxy_destroy(this, destroyed_msg);
|
|
467
|
-
}
|
|
463
|
+
Module.pyproxy_destroy(this, destroyed_msg);
|
|
468
464
|
}
|
|
469
465
|
/**
|
|
470
466
|
* Make a new PyProxy pointing to the same Python object.
|
|
@@ -476,7 +472,7 @@ class PyProxyClass {
|
|
|
476
472
|
return Module.pyproxy_new(ptrobj, this.$$.cache);
|
|
477
473
|
}
|
|
478
474
|
/**
|
|
479
|
-
* Converts the ``PyProxy`` into a
|
|
475
|
+
* Converts the ``PyProxy`` into a JavaScript object as best as possible. By
|
|
480
476
|
* default does a deep conversion, if a shallow conversion is desired, you can
|
|
481
477
|
* use ``proxy.toJs({depth : 1})``. See :ref:`Explicit Conversion of PyProxy
|
|
482
478
|
* <type-translations-pyproxy-to-js>` for more info.
|
|
@@ -490,14 +486,14 @@ class PyProxyClass {
|
|
|
490
486
|
* generated structure. The most common use case is to create a new empty
|
|
491
487
|
* list, pass the list as `pyproxies`, and then later iterate over `pyproxies`
|
|
492
488
|
* to destroy all of created proxies.
|
|
493
|
-
* @param {
|
|
489
|
+
* @param {boolean} [options.create_pyproxies] If false, ``toJs`` will throw a
|
|
494
490
|
* ``ConversionError`` rather than producing a ``PyProxy``.
|
|
495
|
-
* @param {
|
|
491
|
+
* @param {boolean} [options.dict_converter] A function to be called on an
|
|
496
492
|
* iterable of pairs ``[key, value]``. Convert this iterable of pairs to the
|
|
497
493
|
* desired output. For instance, ``Object.fromEntries`` would convert the dict
|
|
498
494
|
* to an object, ``Array.from`` converts it to an array of entries, and ``(it) =>
|
|
499
495
|
* new Map(it)`` converts it to a ``Map`` (which is the default behavior).
|
|
500
|
-
* @return {any} The
|
|
496
|
+
* @return {any} The JavaScript object resulting from the conversion.
|
|
501
497
|
*/
|
|
502
498
|
toJs({
|
|
503
499
|
depth = -1,
|
|
@@ -768,8 +764,6 @@ class PyProxyContainsMethods {
|
|
|
768
764
|
}
|
|
769
765
|
}
|
|
770
766
|
|
|
771
|
-
class TempError extends Error {}
|
|
772
|
-
|
|
773
767
|
/**
|
|
774
768
|
* A helper for [Symbol.iterator].
|
|
775
769
|
*
|
|
@@ -788,26 +782,19 @@ class TempError extends Error {}
|
|
|
788
782
|
*/
|
|
789
783
|
function* iter_helper(iterptr, token) {
|
|
790
784
|
try {
|
|
791
|
-
if (iterptr === 0) {
|
|
792
|
-
throw new TempError();
|
|
793
|
-
}
|
|
794
785
|
let item;
|
|
795
786
|
while ((item = Module.__pyproxy_iter_next(iterptr))) {
|
|
796
787
|
yield Module.hiwire.pop_value(item);
|
|
797
788
|
}
|
|
798
|
-
if (Module._PyErr_Occurred()) {
|
|
799
|
-
throw new TempError();
|
|
800
|
-
}
|
|
801
789
|
} catch (e) {
|
|
802
|
-
|
|
803
|
-
Module._pythonexc2js();
|
|
804
|
-
} else {
|
|
805
|
-
Module.fatal_error(e);
|
|
806
|
-
}
|
|
790
|
+
Module.fatal_error(e);
|
|
807
791
|
} finally {
|
|
808
792
|
Module.finalizationRegistry.unregister(token);
|
|
809
793
|
Module._Py_DecRef(iterptr);
|
|
810
794
|
}
|
|
795
|
+
if (Module._PyErr_Occurred()) {
|
|
796
|
+
Module._pythonexc2js();
|
|
797
|
+
}
|
|
811
798
|
}
|
|
812
799
|
|
|
813
800
|
/**
|
|
@@ -840,6 +827,9 @@ class PyProxyIterableMethods {
|
|
|
840
827
|
} catch (e) {
|
|
841
828
|
Module.fatal_error(e);
|
|
842
829
|
}
|
|
830
|
+
if (iterptr === 0) {
|
|
831
|
+
Module._pythonexc2js();
|
|
832
|
+
}
|
|
843
833
|
|
|
844
834
|
let result = iter_helper(iterptr, token);
|
|
845
835
|
Module.finalizationRegistry.register(result, [iterptr, undefined], token);
|
|
@@ -1004,7 +994,7 @@ let PyProxyHandlers = {
|
|
|
1004
994
|
},
|
|
1005
995
|
get(jsobj, jskey) {
|
|
1006
996
|
// Preference order:
|
|
1007
|
-
// 1. stuff from
|
|
997
|
+
// 1. stuff from JavaScript
|
|
1008
998
|
// 2. the result of Python getattr
|
|
1009
999
|
|
|
1010
1000
|
// python_getattr will crash if given a Symbol.
|
|
@@ -1050,7 +1040,7 @@ let PyProxyHandlers = {
|
|
|
1050
1040
|
}
|
|
1051
1041
|
python_delattr(jsobj, jskey);
|
|
1052
1042
|
// Must return "false" if "jskey" is a nonconfigurable own property.
|
|
1053
|
-
// Otherwise
|
|
1043
|
+
// Otherwise JavaScript will throw a TypeError.
|
|
1054
1044
|
return !descr || descr.configurable;
|
|
1055
1045
|
},
|
|
1056
1046
|
ownKeys(jsobj) {
|
|
@@ -1078,7 +1068,7 @@ let PyProxyHandlers = {
|
|
|
1078
1068
|
*/
|
|
1079
1069
|
|
|
1080
1070
|
/**
|
|
1081
|
-
* The Promise /
|
|
1071
|
+
* The Promise / JavaScript awaitable API.
|
|
1082
1072
|
* @private
|
|
1083
1073
|
*/
|
|
1084
1074
|
class PyProxyAwaitableMethods {
|
|
@@ -1089,6 +1079,9 @@ class PyProxyAwaitableMethods {
|
|
|
1089
1079
|
* @private
|
|
1090
1080
|
*/
|
|
1091
1081
|
_ensure_future() {
|
|
1082
|
+
if (this.$$.promise) {
|
|
1083
|
+
return this.$$.promise;
|
|
1084
|
+
}
|
|
1092
1085
|
let ptrobj = _getPtr(this);
|
|
1093
1086
|
let resolveHandle;
|
|
1094
1087
|
let rejectHandle;
|
|
@@ -1114,6 +1107,8 @@ class PyProxyAwaitableMethods {
|
|
|
1114
1107
|
if (errcode === -1) {
|
|
1115
1108
|
Module._pythonexc2js();
|
|
1116
1109
|
}
|
|
1110
|
+
this.$$.promise = promise;
|
|
1111
|
+
this.destroy();
|
|
1117
1112
|
return promise;
|
|
1118
1113
|
}
|
|
1119
1114
|
/**
|
|
@@ -1238,14 +1233,14 @@ let type_to_array_map = new Map([
|
|
|
1238
1233
|
*/
|
|
1239
1234
|
class PyProxyBufferMethods {
|
|
1240
1235
|
/**
|
|
1241
|
-
* Get a view of the buffer data which is usable from
|
|
1236
|
+
* Get a view of the buffer data which is usable from JavaScript. No copy is
|
|
1242
1237
|
* ever performed.
|
|
1243
1238
|
*
|
|
1244
1239
|
* Present only if the proxied Python object supports the `Python Buffer
|
|
1245
1240
|
* Protocol <https://docs.python.org/3/c-api/buffer.html>`_.
|
|
1246
1241
|
*
|
|
1247
1242
|
* We do not support suboffsets, if the buffer requires suboffsets we will
|
|
1248
|
-
* throw an error.
|
|
1243
|
+
* throw an error. JavaScript nd array libraries can't handle suboffsets
|
|
1249
1244
|
* anyways. In this case, you should use the :any:`toJs` api or copy the
|
|
1250
1245
|
* buffer to one that doesn't use suboffets (using e.g.,
|
|
1251
1246
|
* `numpy.ascontiguousarray
|
|
@@ -1391,7 +1386,7 @@ class PyProxyBufferMethods {
|
|
|
1391
1386
|
*/
|
|
1392
1387
|
|
|
1393
1388
|
/**
|
|
1394
|
-
* A class to allow access to a Python data buffers from
|
|
1389
|
+
* A class to allow access to a Python data buffers from JavaScript. These are
|
|
1395
1390
|
* produced by :any:`PyProxy.getBuffer` and cannot be constructed directly.
|
|
1396
1391
|
* When you are done, release it with the :any:`release <PyBuffer.release>`
|
|
1397
1392
|
* method. See
|
|
@@ -1562,50 +1557,3 @@ export class PyBuffer {
|
|
|
1562
1557
|
this.data = null;
|
|
1563
1558
|
}
|
|
1564
1559
|
}
|
|
1565
|
-
|
|
1566
|
-
// A special proxy that we use to wrap pyodide.globals to allow property
|
|
1567
|
-
// access like `pyodide.globals.x`.
|
|
1568
|
-
let globalsPropertyAccessWarned = (!!0);
|
|
1569
|
-
let globalsPropertyAccessWarningMsg =
|
|
1570
|
-
"Access to pyodide.globals via pyodide.globals.key is deprecated and " +
|
|
1571
|
-
"will be removed in version 0.18.0. Use pyodide.globals.get('key'), " +
|
|
1572
|
-
"pyodide.globals.set('key', value), pyodide.globals.delete('key') instead.";
|
|
1573
|
-
let NamespaceProxyHandlers = {
|
|
1574
|
-
has(obj, key) {
|
|
1575
|
-
return Reflect.has(obj, key) || obj.has(key);
|
|
1576
|
-
},
|
|
1577
|
-
get(obj, key) {
|
|
1578
|
-
if (Reflect.has(obj, key)) {
|
|
1579
|
-
return Reflect.get(obj, key);
|
|
1580
|
-
}
|
|
1581
|
-
let result = obj.get(key);
|
|
1582
|
-
if (!globalsPropertyAccessWarned && result !== undefined) {
|
|
1583
|
-
console.warn(globalsPropertyAccessWarningMsg);
|
|
1584
|
-
globalsPropertyAccessWarned = (!!1);
|
|
1585
|
-
}
|
|
1586
|
-
return result;
|
|
1587
|
-
},
|
|
1588
|
-
set(obj, key, value) {
|
|
1589
|
-
if (Reflect.has(obj, key)) {
|
|
1590
|
-
throw new Error(`Cannot set read only field ${key}`);
|
|
1591
|
-
}
|
|
1592
|
-
if (!globalsPropertyAccessWarned) {
|
|
1593
|
-
globalsPropertyAccessWarned = (!!1);
|
|
1594
|
-
console.warn(globalsPropertyAccessWarningMsg);
|
|
1595
|
-
}
|
|
1596
|
-
obj.set(key, value);
|
|
1597
|
-
},
|
|
1598
|
-
ownKeys(obj) {
|
|
1599
|
-
let result = new Set(Reflect.ownKeys(obj));
|
|
1600
|
-
let iter = obj.keys();
|
|
1601
|
-
for (let key of iter) {
|
|
1602
|
-
result.add(key);
|
|
1603
|
-
}
|
|
1604
|
-
iter.destroy();
|
|
1605
|
-
return Array.from(result);
|
|
1606
|
-
},
|
|
1607
|
-
};
|
|
1608
|
-
|
|
1609
|
-
export function wrapNamespace(ns) {
|
|
1610
|
-
return new Proxy(ns, NamespaceProxyHandlers);
|
|
1611
|
-
}
|