pyodide 0.19.0 → 0.20.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/api.ts +495 -0
- package/compat.ts +146 -0
- package/error_handling.gen.ts +335 -0
- package/index.test-d.ts +25 -20
- package/load-package.ts +414 -0
- package/{module.js → module.ts} +21 -13
- package/package.json +13 -6
- package/pyodide.ts +309 -0
- package/pyodide.umd.ts +3 -0
- package/{pyproxy.gen.js → pyproxy.gen.ts} +391 -443
- package/rollup.config.js +16 -4
- package/test/conftest.js +1 -1
- package/tsconfig.json +8 -6
- package/api.js +0 -421
- package/load-pyodide.js +0 -426
- package/pyodide.js +0 -302
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// This file is generated by applying the C preprocessor to core/pyproxy.
|
|
1
|
+
// This file is generated by applying the C preprocessor to core/pyproxy.ts
|
|
2
2
|
// It uses the macros defined in core/pyproxy.c
|
|
3
3
|
// Do not edit it directly!
|
|
4
4
|
|
|
@@ -84,28 +84,6 @@
|
|
|
84
84
|
|
|
85
85
|
|
|
86
86
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
87
|
|
|
110
88
|
|
|
111
89
|
|
|
@@ -140,33 +118,34 @@
|
|
|
140
118
|
* any macros available in pyproxy.c are available here. We only need the flags
|
|
141
119
|
* macros HAS_LENGTH, etc.
|
|
142
120
|
*
|
|
143
|
-
* See Makefile recipe for src/js/pyproxy.
|
|
121
|
+
* See Makefile recipe for src/js/pyproxy.gen.ts
|
|
144
122
|
*/
|
|
145
|
-
|
|
146
|
-
import { Module } from "./module.js";
|
|
147
|
-
|
|
123
|
+
import { Module, API, Hiwire } from "./module.js";
|
|
148
124
|
/**
|
|
149
125
|
* Is the argument a :any:`PyProxy`?
|
|
150
|
-
* @param jsobj
|
|
151
|
-
* @returns
|
|
126
|
+
* @param jsobj Object to test.
|
|
127
|
+
* @returns Is ``jsobj`` a :any:`PyProxy`?
|
|
152
128
|
*/
|
|
153
|
-
export function isPyProxy(jsobj) {
|
|
129
|
+
export function isPyProxy(jsobj: any): jsobj is PyProxy {
|
|
154
130
|
return !!jsobj && jsobj.$$ !== undefined && jsobj.$$.type === "PyProxy";
|
|
155
131
|
}
|
|
156
|
-
|
|
157
|
-
|
|
132
|
+
API.isPyProxy = isPyProxy;
|
|
133
|
+
declare var FinalizationRegistry: any;
|
|
134
|
+
declare var globalThis: any;
|
|
158
135
|
if (globalThis.FinalizationRegistry) {
|
|
159
|
-
Module.finalizationRegistry = new FinalizationRegistry(
|
|
160
|
-
cache
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
136
|
+
Module.finalizationRegistry = new FinalizationRegistry(
|
|
137
|
+
([ptr, cache]: [ptr: number, cache: PyProxyCache]) => {
|
|
138
|
+
cache.leaked = (!!1);
|
|
139
|
+
pyproxy_decref_cache(cache);
|
|
140
|
+
try {
|
|
141
|
+
Module._Py_DecRef(ptr);
|
|
142
|
+
} catch (e) {
|
|
143
|
+
// I'm not really sure what happens if an error occurs inside of a
|
|
144
|
+
// finalizer...
|
|
145
|
+
API.fatal_error(e);
|
|
146
|
+
}
|
|
168
147
|
}
|
|
169
|
-
|
|
148
|
+
);
|
|
170
149
|
// For some unclear reason this code screws up selenium FirefoxDriver. Works
|
|
171
150
|
// fine in chrome and when I test it in browser. It seems to be sensitive to
|
|
172
151
|
// changes that don't make a difference to the semantics.
|
|
@@ -176,35 +155,33 @@ if (globalThis.FinalizationRegistry) {
|
|
|
176
155
|
// Module._PyBuffer_Release(ptr);
|
|
177
156
|
// Module._PyMem_Free(ptr);
|
|
178
157
|
// } catch (e) {
|
|
179
|
-
//
|
|
158
|
+
// API.fatal_error(e);
|
|
180
159
|
// }
|
|
181
160
|
// });
|
|
182
161
|
} else {
|
|
183
162
|
Module.finalizationRegistry = { register() {}, unregister() {} };
|
|
184
163
|
// Module.bufferFinalizationRegistry = finalizationRegistry;
|
|
185
164
|
}
|
|
186
|
-
|
|
187
165
|
let pyproxy_alloc_map = new Map();
|
|
188
166
|
Module.pyproxy_alloc_map = pyproxy_alloc_map;
|
|
189
|
-
let trace_pyproxy_alloc;
|
|
190
|
-
let trace_pyproxy_dealloc;
|
|
191
|
-
|
|
167
|
+
let trace_pyproxy_alloc: (proxy: any) => void;
|
|
168
|
+
let trace_pyproxy_dealloc: (proxy: any) => void;
|
|
192
169
|
Module.enable_pyproxy_allocation_tracing = function () {
|
|
193
|
-
trace_pyproxy_alloc = function (proxy) {
|
|
170
|
+
trace_pyproxy_alloc = function (proxy: any) {
|
|
194
171
|
pyproxy_alloc_map.set(proxy, Error().stack);
|
|
195
172
|
};
|
|
196
|
-
trace_pyproxy_dealloc = function (proxy) {
|
|
173
|
+
trace_pyproxy_dealloc = function (proxy: any) {
|
|
197
174
|
pyproxy_alloc_map.delete(proxy);
|
|
198
175
|
};
|
|
199
176
|
};
|
|
200
177
|
Module.disable_pyproxy_allocation_tracing = function () {
|
|
201
|
-
trace_pyproxy_alloc = function (proxy) {};
|
|
202
|
-
trace_pyproxy_dealloc = function (proxy) {};
|
|
178
|
+
trace_pyproxy_alloc = function (proxy: any) {};
|
|
179
|
+
trace_pyproxy_dealloc = function (proxy: any) {};
|
|
203
180
|
};
|
|
204
181
|
Module.disable_pyproxy_allocation_tracing();
|
|
205
|
-
|
|
182
|
+
type PyProxyCache = { cacheId: number; refcnt: number; leaked?: boolean };
|
|
206
183
|
/**
|
|
207
|
-
* Create a new PyProxy
|
|
184
|
+
* Create a new PyProxy wrapping ptrobj which is a PyObject*.
|
|
208
185
|
*
|
|
209
186
|
* The argument cache is only needed to implement the PyProxy.copy API, it
|
|
210
187
|
* allows the copy of the PyProxy to share its attribute cache with the original
|
|
@@ -216,7 +193,7 @@ Module.disable_pyproxy_allocation_tracing();
|
|
|
216
193
|
* many as possible.
|
|
217
194
|
* @private
|
|
218
195
|
*/
|
|
219
|
-
Module.pyproxy_new = function (ptrobj, cache) {
|
|
196
|
+
Module.pyproxy_new = function (ptrobj: number, cache?: PyProxyCache) {
|
|
220
197
|
let flags = Module._pyproxy_getflags(ptrobj);
|
|
221
198
|
let cls = Module.getPyProxyClass(flags);
|
|
222
199
|
// Reflect.construct calls the constructor of Module.PyProxyClass but sets
|
|
@@ -241,7 +218,7 @@ Module.pyproxy_new = function (ptrobj, cache) {
|
|
|
241
218
|
if (!cache) {
|
|
242
219
|
// The cache needs to be accessed primarily from the C function
|
|
243
220
|
// _pyproxy_getattr so we make a hiwire id.
|
|
244
|
-
let cacheId =
|
|
221
|
+
let cacheId = Hiwire.new_value(new Map());
|
|
245
222
|
cache = { cacheId, refcnt: 0 };
|
|
246
223
|
}
|
|
247
224
|
cache.refcnt++;
|
|
@@ -254,33 +231,24 @@ Module.pyproxy_new = function (ptrobj, cache) {
|
|
|
254
231
|
Module.finalizationRegistry.register(proxy, [ptrobj, cache], proxy);
|
|
255
232
|
return proxy;
|
|
256
233
|
};
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
throw new Error(
|
|
262
|
-
jsobj.$$.destroyed_msg || "Object has already been destroyed"
|
|
263
|
-
);
|
|
234
|
+
function _getPtr(jsobj: any) {
|
|
235
|
+
let ptr: number = jsobj.$$.ptr;
|
|
236
|
+
if (ptr === 0) {
|
|
237
|
+
throw new Error(jsobj.$$.destroyed_msg);
|
|
264
238
|
}
|
|
265
239
|
return ptr;
|
|
266
240
|
}
|
|
267
|
-
|
|
268
241
|
let pyproxyClassMap = new Map();
|
|
269
242
|
/**
|
|
270
|
-
*
|
|
243
|
+
* Retrieve the appropriate mixins based on the features requested in flags.
|
|
271
244
|
* Used by pyproxy_new. The "flags" variable is produced by the C function
|
|
272
245
|
* pyproxy_getflags. Multiple PyProxies with the same set of feature flags
|
|
273
246
|
* will share the same prototype, so the memory footprint of each individual
|
|
274
247
|
* PyProxy is minimal.
|
|
275
248
|
* @private
|
|
276
249
|
*/
|
|
277
|
-
Module.getPyProxyClass = function (flags) {
|
|
278
|
-
|
|
279
|
-
if (result) {
|
|
280
|
-
return result;
|
|
281
|
-
}
|
|
282
|
-
let descriptors = {};
|
|
283
|
-
for (let [feature_flag, methods] of [
|
|
250
|
+
Module.getPyProxyClass = function (flags: number) {
|
|
251
|
+
const FLAG_TYPE_PAIRS: [number, any][] = [
|
|
284
252
|
[(1 << 0), PyProxyLengthMethods],
|
|
285
253
|
[(1 << 1), PyProxyGetItemMethods],
|
|
286
254
|
[(1 << 2), PyProxySetItemMethods],
|
|
@@ -290,7 +258,13 @@ Module.getPyProxyClass = function (flags) {
|
|
|
290
258
|
[(1 << 6), PyProxyAwaitableMethods],
|
|
291
259
|
[(1 << 7), PyProxyBufferMethods],
|
|
292
260
|
[(1 << 8), PyProxyCallableMethods],
|
|
293
|
-
]
|
|
261
|
+
];
|
|
262
|
+
let result = pyproxyClassMap.get(flags);
|
|
263
|
+
if (result) {
|
|
264
|
+
return result;
|
|
265
|
+
}
|
|
266
|
+
let descriptors: any = {};
|
|
267
|
+
for (let [feature_flag, methods] of FLAG_TYPE_PAIRS) {
|
|
294
268
|
if (flags & feature_flag) {
|
|
295
269
|
Object.assign(
|
|
296
270
|
descriptors,
|
|
@@ -313,54 +287,64 @@ Module.getPyProxyClass = function (flags) {
|
|
|
313
287
|
pyproxyClassMap.set(flags, NewPyProxyClass);
|
|
314
288
|
return NewPyProxyClass;
|
|
315
289
|
};
|
|
316
|
-
|
|
317
290
|
// Static methods
|
|
318
291
|
Module.PyProxy_getPtr = _getPtr;
|
|
319
|
-
|
|
320
292
|
const pyproxy_cache_destroyed_msg =
|
|
321
293
|
"This borrowed attribute proxy was automatically destroyed in the " +
|
|
322
294
|
"process of destroying the proxy it was borrowed from. Try using the 'copy' method.";
|
|
323
|
-
|
|
324
|
-
function pyproxy_decref_cache(cache) {
|
|
295
|
+
function pyproxy_decref_cache(cache: PyProxyCache) {
|
|
325
296
|
if (!cache) {
|
|
326
297
|
return;
|
|
327
298
|
}
|
|
328
299
|
cache.refcnt--;
|
|
329
300
|
if (cache.refcnt === 0) {
|
|
330
|
-
let cache_map =
|
|
301
|
+
let cache_map = Hiwire.pop_value(cache.cacheId);
|
|
331
302
|
for (let proxy_id of cache_map.values()) {
|
|
332
|
-
const cache_entry =
|
|
303
|
+
const cache_entry = Hiwire.pop_value(proxy_id);
|
|
333
304
|
if (!cache.leaked) {
|
|
334
305
|
Module.pyproxy_destroy(cache_entry, pyproxy_cache_destroyed_msg);
|
|
335
306
|
}
|
|
336
307
|
}
|
|
337
308
|
}
|
|
338
309
|
}
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
if (proxy.$$.ptr === null) {
|
|
310
|
+
Module.pyproxy_destroy = function (proxy: PyProxy, destroyed_msg: string) {
|
|
311
|
+
if (proxy.$$.ptr === 0) {
|
|
342
312
|
return;
|
|
343
313
|
}
|
|
344
314
|
let ptrobj = _getPtr(proxy);
|
|
345
315
|
Module.finalizationRegistry.unregister(proxy);
|
|
316
|
+
destroyed_msg = destroyed_msg || "Object has already been destroyed";
|
|
317
|
+
let proxy_type = proxy.type;
|
|
318
|
+
let proxy_repr;
|
|
319
|
+
try {
|
|
320
|
+
proxy_repr = proxy.toString();
|
|
321
|
+
} catch (e) {
|
|
322
|
+
if (e.pyodide_fatal_error) {
|
|
323
|
+
throw e;
|
|
324
|
+
}
|
|
325
|
+
}
|
|
346
326
|
// Maybe the destructor will call JavaScript code that will somehow try
|
|
347
327
|
// to use this proxy. Mark it deleted before decrementing reference count
|
|
348
328
|
// just in case!
|
|
349
|
-
proxy.$$.ptr =
|
|
329
|
+
proxy.$$.ptr = 0;
|
|
330
|
+
destroyed_msg += "\n" + `The object was of type "${proxy_type}" and `;
|
|
331
|
+
if (proxy_repr) {
|
|
332
|
+
destroyed_msg += `had repr "${proxy_repr}"`;
|
|
333
|
+
} else {
|
|
334
|
+
destroyed_msg += "an error was raised when trying to generate its repr";
|
|
335
|
+
}
|
|
350
336
|
proxy.$$.destroyed_msg = destroyed_msg;
|
|
351
337
|
pyproxy_decref_cache(proxy.$$.cache);
|
|
352
338
|
try {
|
|
353
339
|
Module._Py_DecRef(ptrobj);
|
|
354
340
|
trace_pyproxy_dealloc(proxy);
|
|
355
341
|
} catch (e) {
|
|
356
|
-
|
|
342
|
+
API.fatal_error(e);
|
|
357
343
|
}
|
|
358
344
|
};
|
|
359
|
-
|
|
360
345
|
// Now a lot of boilerplate to wrap the abstract Object protocol wrappers
|
|
361
346
|
// defined in pyproxy.c in JavaScript functions.
|
|
362
|
-
|
|
363
|
-
Module.callPyObjectKwargs = function (ptrobj, ...jsargs) {
|
|
347
|
+
Module.callPyObjectKwargs = function (ptrobj: number, ...jsargs: any) {
|
|
364
348
|
// We don't do any checking for kwargs, checks are in PyProxy.callKwargs
|
|
365
349
|
// which only is used when the keyword arguments come from the user.
|
|
366
350
|
let kwargs = jsargs.pop();
|
|
@@ -369,9 +353,8 @@ Module.callPyObjectKwargs = function (ptrobj, ...jsargs) {
|
|
|
369
353
|
let kwargs_values = Object.values(kwargs);
|
|
370
354
|
let num_kwargs = kwargs_names.length;
|
|
371
355
|
jsargs.push(...kwargs_values);
|
|
372
|
-
|
|
373
|
-
let
|
|
374
|
-
let idkwnames = Module.hiwire.new_value(kwargs_names);
|
|
356
|
+
let idargs = Hiwire.new_value(jsargs);
|
|
357
|
+
let idkwnames = Hiwire.new_value(kwargs_names);
|
|
375
358
|
let idresult;
|
|
376
359
|
try {
|
|
377
360
|
idresult = Module.__pyproxy_apply(
|
|
@@ -382,30 +365,32 @@ Module.callPyObjectKwargs = function (ptrobj, ...jsargs) {
|
|
|
382
365
|
num_kwargs
|
|
383
366
|
);
|
|
384
367
|
} catch (e) {
|
|
385
|
-
|
|
368
|
+
API.fatal_error(e);
|
|
386
369
|
} finally {
|
|
387
|
-
|
|
388
|
-
|
|
370
|
+
Hiwire.decref(idargs);
|
|
371
|
+
Hiwire.decref(idkwnames);
|
|
389
372
|
}
|
|
390
373
|
if (idresult === 0) {
|
|
391
374
|
Module._pythonexc2js();
|
|
392
375
|
}
|
|
393
|
-
|
|
376
|
+
let result = Hiwire.pop_value(idresult);
|
|
377
|
+
// Automatically schedule coroutines
|
|
378
|
+
if (result && result.type === "coroutine" && result._ensure_future) {
|
|
379
|
+
result._ensure_future();
|
|
380
|
+
}
|
|
381
|
+
return result;
|
|
394
382
|
};
|
|
395
|
-
|
|
396
|
-
Module.callPyObject = function (ptrobj, ...jsargs) {
|
|
383
|
+
Module.callPyObject = function (ptrobj: number, ...jsargs: any) {
|
|
397
384
|
return Module.callPyObjectKwargs(ptrobj, ...jsargs, {});
|
|
398
385
|
};
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
*/
|
|
404
|
-
class PyProxyClass {
|
|
386
|
+
export type PyProxy = PyProxyClass & { [x: string]: any };
|
|
387
|
+
export class PyProxyClass {
|
|
388
|
+
$$: { ptr: number; cache: PyProxyCache; destroyed_msg?: string };
|
|
389
|
+
$$flags: number;
|
|
390
|
+
/** @private */
|
|
405
391
|
constructor() {
|
|
406
392
|
throw new TypeError("PyProxy is not a constructor");
|
|
407
393
|
}
|
|
408
|
-
|
|
409
394
|
get [Symbol.toStringTag]() {
|
|
410
395
|
return "PyProxy";
|
|
411
396
|
}
|
|
@@ -423,51 +408,45 @@ class PyProxyClass {
|
|
|
423
408
|
* else:
|
|
424
409
|
* ty.__module__ + "." + ty.__name__
|
|
425
410
|
*
|
|
426
|
-
* @type {string}
|
|
427
411
|
*/
|
|
428
|
-
get type() {
|
|
412
|
+
get type(): string {
|
|
429
413
|
let ptrobj = _getPtr(this);
|
|
430
|
-
return
|
|
414
|
+
return Hiwire.pop_value(Module.__pyproxy_type(ptrobj));
|
|
431
415
|
}
|
|
432
|
-
|
|
433
|
-
* @returns {string}
|
|
434
|
-
*/
|
|
435
|
-
toString() {
|
|
416
|
+
toString(): string {
|
|
436
417
|
let ptrobj = _getPtr(this);
|
|
437
418
|
let jsref_repr;
|
|
438
419
|
try {
|
|
439
420
|
jsref_repr = Module.__pyproxy_repr(ptrobj);
|
|
440
421
|
} catch (e) {
|
|
441
|
-
|
|
422
|
+
API.fatal_error(e);
|
|
442
423
|
}
|
|
443
424
|
if (jsref_repr === 0) {
|
|
444
425
|
Module._pythonexc2js();
|
|
445
426
|
}
|
|
446
|
-
return
|
|
427
|
+
return Hiwire.pop_value(jsref_repr);
|
|
447
428
|
}
|
|
448
429
|
/**
|
|
449
|
-
* Destroy the ``PyProxy``. This will release the memory. Any further
|
|
450
|
-
*
|
|
430
|
+
* Destroy the ``PyProxy``. This will release the memory. Any further attempt
|
|
431
|
+
* to use the object will raise an error.
|
|
451
432
|
*
|
|
452
433
|
* In a browser supporting `FinalizationRegistry
|
|
453
434
|
* <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/FinalizationRegistry>`_
|
|
454
435
|
* Pyodide will automatically destroy the ``PyProxy`` when it is garbage
|
|
455
|
-
* collected, however there is no guarantee that the finalizer will be run
|
|
456
|
-
*
|
|
436
|
+
* collected, however there is no guarantee that the finalizer will be run in
|
|
437
|
+
* a timely manner so it is better to ``destroy`` the proxy explicitly.
|
|
457
438
|
*
|
|
458
|
-
* @param
|
|
459
|
-
*
|
|
460
|
-
* destroyed".
|
|
439
|
+
* @param destroyed_msg The error message to print if use is attempted after
|
|
440
|
+
* destroying. Defaults to "Object has already been destroyed".
|
|
461
441
|
*/
|
|
462
|
-
destroy(destroyed_msg) {
|
|
442
|
+
destroy(destroyed_msg?: string) {
|
|
463
443
|
Module.pyproxy_destroy(this, destroyed_msg);
|
|
464
444
|
}
|
|
465
445
|
/**
|
|
466
446
|
* Make a new PyProxy pointing to the same Python object.
|
|
467
447
|
* Useful if the PyProxy is destroyed somewhere else.
|
|
468
|
-
* @returns {PyProxy}
|
|
469
448
|
*/
|
|
470
|
-
copy() {
|
|
449
|
+
copy(): PyProxy {
|
|
471
450
|
let ptrobj = _getPtr(this);
|
|
472
451
|
return Module.pyproxy_new(ptrobj, this.$$.cache);
|
|
473
452
|
}
|
|
@@ -476,125 +455,141 @@ class PyProxyClass {
|
|
|
476
455
|
* default does a deep conversion, if a shallow conversion is desired, you can
|
|
477
456
|
* use ``proxy.toJs({depth : 1})``. See :ref:`Explicit Conversion of PyProxy
|
|
478
457
|
* <type-translations-pyproxy-to-js>` for more info.
|
|
479
|
-
*
|
|
480
|
-
* @
|
|
481
|
-
* @param {number} [options.depth] How many layers deep to perform the
|
|
482
|
-
* conversion. Defaults to infinite.
|
|
483
|
-
* @param {array} [options.pyproxies] If provided, ``toJs`` will store all
|
|
484
|
-
* PyProxies created in this list. This allows you to easily destroy all the
|
|
485
|
-
* PyProxies by iterating the list without having to recurse over the
|
|
486
|
-
* generated structure. The most common use case is to create a new empty
|
|
487
|
-
* list, pass the list as `pyproxies`, and then later iterate over `pyproxies`
|
|
488
|
-
* to destroy all of created proxies.
|
|
489
|
-
* @param {boolean} [options.create_pyproxies] If false, ``toJs`` will throw a
|
|
490
|
-
* ``ConversionError`` rather than producing a ``PyProxy``.
|
|
491
|
-
* @param {boolean} [options.dict_converter] A function to be called on an
|
|
492
|
-
* iterable of pairs ``[key, value]``. Convert this iterable of pairs to the
|
|
493
|
-
* desired output. For instance, ``Object.fromEntries`` would convert the dict
|
|
494
|
-
* to an object, ``Array.from`` converts it to an array of entries, and ``(it) =>
|
|
495
|
-
* new Map(it)`` converts it to a ``Map`` (which is the default behavior).
|
|
496
|
-
* @return {any} The JavaScript object resulting from the conversion.
|
|
458
|
+
* @param options
|
|
459
|
+
* @return The JavaScript object resulting from the conversion.
|
|
497
460
|
*/
|
|
498
461
|
toJs({
|
|
499
462
|
depth = -1,
|
|
500
|
-
pyproxies,
|
|
463
|
+
pyproxies = undefined,
|
|
501
464
|
create_pyproxies = (!!1),
|
|
502
|
-
dict_converter,
|
|
503
|
-
|
|
465
|
+
dict_converter = undefined,
|
|
466
|
+
default_converter = undefined,
|
|
467
|
+
}: {
|
|
468
|
+
/** How many layers deep to perform the conversion. Defaults to infinite */
|
|
469
|
+
depth?: number;
|
|
470
|
+
/**
|
|
471
|
+
* If provided, ``toJs`` will store all PyProxies created in this list. This
|
|
472
|
+
* allows you to easily destroy all the PyProxies by iterating the list
|
|
473
|
+
* without having to recurse over the generated structure. The most common
|
|
474
|
+
* use case is to create a new empty list, pass the list as `pyproxies`, and
|
|
475
|
+
* then later iterate over `pyproxies` to destroy all of created proxies.
|
|
476
|
+
*/
|
|
477
|
+
pyproxies?: PyProxy[];
|
|
478
|
+
/**
|
|
479
|
+
* If false, ``toJs`` will throw a ``ConversionError`` rather than
|
|
480
|
+
* producing a ``PyProxy``.
|
|
481
|
+
*/
|
|
482
|
+
create_pyproxies?: boolean;
|
|
483
|
+
/**
|
|
484
|
+
* A function to be called on an iterable of pairs ``[key, value]``. Convert
|
|
485
|
+
* this iterable of pairs to the desired output. For instance,
|
|
486
|
+
* ``Object.fromEntries`` would convert the dict to an object, ``Array.from``
|
|
487
|
+
* converts it to an array of entries, and ``(it) => new Map(it)`` converts
|
|
488
|
+
* it to a ``Map`` (which is the default behavior).
|
|
489
|
+
*/
|
|
490
|
+
dict_converter?: (array: Iterable<[key: string, value: any]>) => any;
|
|
491
|
+
/**
|
|
492
|
+
* Optional argument to convert objects with no default conversion. See the
|
|
493
|
+
* documentation of :any:`pyodide.to_js`.
|
|
494
|
+
*/
|
|
495
|
+
default_converter?: (
|
|
496
|
+
obj: PyProxy,
|
|
497
|
+
convert: (obj: PyProxy) => any,
|
|
498
|
+
cacheConversion: (obj: PyProxy, result: any) => void
|
|
499
|
+
) => any;
|
|
500
|
+
} = {}): any {
|
|
504
501
|
let ptrobj = _getPtr(this);
|
|
505
502
|
let idresult;
|
|
506
503
|
let proxies_id;
|
|
507
504
|
let dict_converter_id = 0;
|
|
505
|
+
let default_converter_id = 0;
|
|
508
506
|
if (!create_pyproxies) {
|
|
509
507
|
proxies_id = 0;
|
|
510
508
|
} else if (pyproxies) {
|
|
511
|
-
proxies_id =
|
|
509
|
+
proxies_id = Hiwire.new_value(pyproxies);
|
|
512
510
|
} else {
|
|
513
|
-
proxies_id =
|
|
511
|
+
proxies_id = Hiwire.new_value([]);
|
|
514
512
|
}
|
|
515
513
|
if (dict_converter) {
|
|
516
|
-
dict_converter_id =
|
|
514
|
+
dict_converter_id = Hiwire.new_value(dict_converter);
|
|
515
|
+
}
|
|
516
|
+
if (default_converter) {
|
|
517
|
+
default_converter_id = Hiwire.new_value(default_converter);
|
|
517
518
|
}
|
|
518
519
|
try {
|
|
519
|
-
idresult = Module.
|
|
520
|
+
idresult = Module._python2js_custom(
|
|
520
521
|
ptrobj,
|
|
521
522
|
depth,
|
|
522
523
|
proxies_id,
|
|
523
|
-
dict_converter_id
|
|
524
|
+
dict_converter_id,
|
|
525
|
+
default_converter_id
|
|
524
526
|
);
|
|
525
527
|
} catch (e) {
|
|
526
|
-
|
|
528
|
+
API.fatal_error(e);
|
|
527
529
|
} finally {
|
|
528
|
-
|
|
529
|
-
|
|
530
|
+
Hiwire.decref(proxies_id);
|
|
531
|
+
Hiwire.decref(dict_converter_id);
|
|
532
|
+
Hiwire.decref(default_converter_id);
|
|
530
533
|
}
|
|
531
534
|
if (idresult === 0) {
|
|
532
535
|
Module._pythonexc2js();
|
|
533
536
|
}
|
|
534
|
-
return
|
|
537
|
+
return Hiwire.pop_value(idresult);
|
|
535
538
|
}
|
|
536
539
|
/**
|
|
537
540
|
* Check whether the :any:`PyProxy.length` getter is available on this PyProxy. A
|
|
538
541
|
* Typescript type guard.
|
|
539
|
-
* @returns {this is PyProxyWithLength}
|
|
540
542
|
*/
|
|
541
|
-
supportsLength() {
|
|
543
|
+
supportsLength(): this is PyProxyWithLength {
|
|
542
544
|
return !!(this.$$flags & (1 << 0));
|
|
543
545
|
}
|
|
544
546
|
/**
|
|
545
547
|
* Check whether the :any:`PyProxy.get` method is available on this PyProxy. A
|
|
546
548
|
* Typescript type guard.
|
|
547
|
-
* @returns {this is PyProxyWithGet}
|
|
548
549
|
*/
|
|
549
|
-
supportsGet() {
|
|
550
|
+
supportsGet(): this is PyProxyWithGet {
|
|
550
551
|
return !!(this.$$flags & (1 << 1));
|
|
551
552
|
}
|
|
552
553
|
/**
|
|
553
554
|
* Check whether the :any:`PyProxy.set` method is available on this PyProxy. A
|
|
554
555
|
* Typescript type guard.
|
|
555
|
-
* @returns {this is PyProxyWithSet}
|
|
556
556
|
*/
|
|
557
|
-
supportsSet() {
|
|
557
|
+
supportsSet(): this is PyProxyWithSet {
|
|
558
558
|
return !!(this.$$flags & (1 << 2));
|
|
559
559
|
}
|
|
560
560
|
/**
|
|
561
561
|
* Check whether the :any:`PyProxy.has` method is available on this PyProxy. A
|
|
562
562
|
* Typescript type guard.
|
|
563
|
-
* @returns {this is PyProxyWithHas}
|
|
564
563
|
*/
|
|
565
|
-
supportsHas() {
|
|
564
|
+
supportsHas(): this is PyProxyWithHas {
|
|
566
565
|
return !!(this.$$flags & (1 << 3));
|
|
567
566
|
}
|
|
568
567
|
/**
|
|
569
568
|
* Check whether the PyProxy is iterable. A Typescript type guard for
|
|
570
|
-
* :any:`PyProxy.[
|
|
571
|
-
* @returns {this is PyProxyIterable}
|
|
569
|
+
* :any:`PyProxy.[iterator]`.
|
|
572
570
|
*/
|
|
573
|
-
isIterable() {
|
|
571
|
+
isIterable(): this is PyProxyIterable {
|
|
574
572
|
return !!(this.$$flags & ((1 << 4) | (1 << 5)));
|
|
575
573
|
}
|
|
576
574
|
/**
|
|
577
575
|
* Check whether the PyProxy is iterable. A Typescript type guard for
|
|
578
576
|
* :any:`PyProxy.next`.
|
|
579
|
-
* @returns {this is PyProxyIterator}
|
|
580
577
|
*/
|
|
581
|
-
isIterator() {
|
|
578
|
+
isIterator(): this is PyProxyIterator {
|
|
582
579
|
return !!(this.$$flags & (1 << 5));
|
|
583
580
|
}
|
|
584
581
|
/**
|
|
585
582
|
* Check whether the PyProxy is awaitable. A Typescript type guard, if this
|
|
586
583
|
* function returns true Typescript considers the PyProxy to be a ``Promise``.
|
|
587
|
-
* @returns {this is PyProxyAwaitable}
|
|
588
584
|
*/
|
|
589
|
-
isAwaitable() {
|
|
585
|
+
isAwaitable(): this is PyProxyAwaitable {
|
|
590
586
|
return !!(this.$$flags & (1 << 6));
|
|
591
587
|
}
|
|
592
588
|
/**
|
|
593
589
|
* Check whether the PyProxy is a buffer. A Typescript type guard for
|
|
594
590
|
* :any:`PyProxy.getBuffer`.
|
|
595
|
-
* @returns {this is PyProxyBuffer}
|
|
596
591
|
*/
|
|
597
|
-
isBuffer() {
|
|
592
|
+
isBuffer(): this is PyProxyBuffer {
|
|
598
593
|
return !!(this.$$flags & (1 << 7));
|
|
599
594
|
}
|
|
600
595
|
/**
|
|
@@ -602,32 +597,27 @@ class PyProxyClass {
|
|
|
602
597
|
* returns true then Typescript considers the Proxy to be callable of
|
|
603
598
|
* signature ``(args... : any[]) => PyProxy | number | bigint | string |
|
|
604
599
|
* boolean | undefined``.
|
|
605
|
-
* @returns {this is PyProxyCallable}
|
|
606
600
|
*/
|
|
607
|
-
isCallable() {
|
|
601
|
+
isCallable(): this is PyProxyCallable {
|
|
608
602
|
return !!(this.$$flags & (1 << 8));
|
|
609
603
|
}
|
|
610
604
|
}
|
|
611
|
-
|
|
612
|
-
/**
|
|
613
|
-
* @typedef { PyProxy & PyProxyLengthMethods } PyProxyWithLength
|
|
614
|
-
*/
|
|
605
|
+
export type PyProxyWithLength = PyProxy & PyProxyLengthMethods;
|
|
615
606
|
// Controlled by HAS_LENGTH, appears for any object with __len__ or sq_length
|
|
616
607
|
// or mp_length methods
|
|
617
|
-
class PyProxyLengthMethods {
|
|
608
|
+
export class PyProxyLengthMethods {
|
|
618
609
|
/**
|
|
619
610
|
* The length of the object.
|
|
620
611
|
*
|
|
621
612
|
* Present only if the proxied Python object has a ``__len__`` method.
|
|
622
|
-
* @returns {number}
|
|
623
613
|
*/
|
|
624
|
-
get length() {
|
|
614
|
+
get length(): number {
|
|
625
615
|
let ptrobj = _getPtr(this);
|
|
626
616
|
let length;
|
|
627
617
|
try {
|
|
628
618
|
length = Module._PyObject_Size(ptrobj);
|
|
629
619
|
} catch (e) {
|
|
630
|
-
|
|
620
|
+
API.fatal_error(e);
|
|
631
621
|
}
|
|
632
622
|
if (length === -1) {
|
|
633
623
|
Module._pythonexc2js();
|
|
@@ -635,35 +625,28 @@ class PyProxyLengthMethods {
|
|
|
635
625
|
return length;
|
|
636
626
|
}
|
|
637
627
|
}
|
|
638
|
-
|
|
639
|
-
/**
|
|
640
|
-
* @typedef {PyProxy & PyProxyGetItemMethods} PyProxyWithGet
|
|
641
|
-
*/
|
|
642
|
-
|
|
628
|
+
export type PyProxyWithGet = PyProxy & PyProxyGetItemMethods;
|
|
643
629
|
// Controlled by HAS_GET, appears for any class with __getitem__,
|
|
644
630
|
// mp_subscript, or sq_item methods
|
|
645
|
-
|
|
646
|
-
* @interface
|
|
647
|
-
*/
|
|
648
|
-
class PyProxyGetItemMethods {
|
|
631
|
+
export class PyProxyGetItemMethods {
|
|
649
632
|
/**
|
|
650
633
|
* This translates to the Python code ``obj[key]``.
|
|
651
634
|
*
|
|
652
635
|
* Present only if the proxied Python object has a ``__getitem__`` method.
|
|
653
636
|
*
|
|
654
|
-
* @param
|
|
655
|
-
* @returns
|
|
637
|
+
* @param key The key to look up.
|
|
638
|
+
* @returns The corresponding value.
|
|
656
639
|
*/
|
|
657
|
-
get(key) {
|
|
640
|
+
get(key: any): any {
|
|
658
641
|
let ptrobj = _getPtr(this);
|
|
659
|
-
let idkey =
|
|
642
|
+
let idkey = Hiwire.new_value(key);
|
|
660
643
|
let idresult;
|
|
661
644
|
try {
|
|
662
645
|
idresult = Module.__pyproxy_getitem(ptrobj, idkey);
|
|
663
646
|
} catch (e) {
|
|
664
|
-
|
|
647
|
+
API.fatal_error(e);
|
|
665
648
|
} finally {
|
|
666
|
-
|
|
649
|
+
Hiwire.decref(idkey);
|
|
667
650
|
}
|
|
668
651
|
if (idresult === 0) {
|
|
669
652
|
if (Module._PyErr_Occurred()) {
|
|
@@ -672,36 +655,33 @@ class PyProxyGetItemMethods {
|
|
|
672
655
|
return undefined;
|
|
673
656
|
}
|
|
674
657
|
}
|
|
675
|
-
return
|
|
658
|
+
return Hiwire.pop_value(idresult);
|
|
676
659
|
}
|
|
677
660
|
}
|
|
678
|
-
|
|
679
|
-
/**
|
|
680
|
-
* @typedef {PyProxy & PyProxySetItemMethods} PyProxyWithSet
|
|
681
|
-
*/
|
|
661
|
+
export type PyProxyWithSet = PyProxy & PyProxySetItemMethods;
|
|
682
662
|
// Controlled by HAS_SET, appears for any class with __setitem__, __delitem__,
|
|
683
663
|
// mp_ass_subscript, or sq_ass_item.
|
|
684
|
-
class PyProxySetItemMethods {
|
|
664
|
+
export class PyProxySetItemMethods {
|
|
685
665
|
/**
|
|
686
666
|
* This translates to the Python code ``obj[key] = value``.
|
|
687
667
|
*
|
|
688
668
|
* Present only if the proxied Python object has a ``__setitem__`` method.
|
|
689
669
|
*
|
|
690
|
-
* @param
|
|
691
|
-
* @param
|
|
670
|
+
* @param key The key to set.
|
|
671
|
+
* @param value The value to set it to.
|
|
692
672
|
*/
|
|
693
|
-
set(key, value) {
|
|
673
|
+
set(key: any, value: any) {
|
|
694
674
|
let ptrobj = _getPtr(this);
|
|
695
|
-
let idkey =
|
|
696
|
-
let idval =
|
|
675
|
+
let idkey = Hiwire.new_value(key);
|
|
676
|
+
let idval = Hiwire.new_value(value);
|
|
697
677
|
let errcode;
|
|
698
678
|
try {
|
|
699
679
|
errcode = Module.__pyproxy_setitem(ptrobj, idkey, idval);
|
|
700
680
|
} catch (e) {
|
|
701
|
-
|
|
681
|
+
API.fatal_error(e);
|
|
702
682
|
} finally {
|
|
703
|
-
|
|
704
|
-
|
|
683
|
+
Hiwire.decref(idkey);
|
|
684
|
+
Hiwire.decref(idval);
|
|
705
685
|
}
|
|
706
686
|
if (errcode === -1) {
|
|
707
687
|
Module._pythonexc2js();
|
|
@@ -712,50 +692,46 @@ class PyProxySetItemMethods {
|
|
|
712
692
|
*
|
|
713
693
|
* Present only if the proxied Python object has a ``__delitem__`` method.
|
|
714
694
|
*
|
|
715
|
-
* @param
|
|
695
|
+
* @param key The key to delete.
|
|
716
696
|
*/
|
|
717
|
-
delete(key) {
|
|
697
|
+
delete(key: any) {
|
|
718
698
|
let ptrobj = _getPtr(this);
|
|
719
|
-
let idkey =
|
|
699
|
+
let idkey = Hiwire.new_value(key);
|
|
720
700
|
let errcode;
|
|
721
701
|
try {
|
|
722
702
|
errcode = Module.__pyproxy_delitem(ptrobj, idkey);
|
|
723
703
|
} catch (e) {
|
|
724
|
-
|
|
704
|
+
API.fatal_error(e);
|
|
725
705
|
} finally {
|
|
726
|
-
|
|
706
|
+
Hiwire.decref(idkey);
|
|
727
707
|
}
|
|
728
708
|
if (errcode === -1) {
|
|
729
709
|
Module._pythonexc2js();
|
|
730
710
|
}
|
|
731
711
|
}
|
|
732
712
|
}
|
|
733
|
-
|
|
734
|
-
/**
|
|
735
|
-
* @typedef {PyProxy & PyProxyContainsMethods} PyProxyWithHas
|
|
736
|
-
*/
|
|
737
|
-
|
|
713
|
+
export type PyProxyWithHas = PyProxy & PyProxyContainsMethods;
|
|
738
714
|
// Controlled by HAS_CONTAINS flag, appears for any class with __contains__ or
|
|
739
715
|
// sq_contains
|
|
740
|
-
class PyProxyContainsMethods {
|
|
716
|
+
export class PyProxyContainsMethods {
|
|
741
717
|
/**
|
|
742
718
|
* This translates to the Python code ``key in obj``.
|
|
743
719
|
*
|
|
744
720
|
* Present only if the proxied Python object has a ``__contains__`` method.
|
|
745
721
|
*
|
|
746
|
-
* @param
|
|
747
|
-
* @returns
|
|
722
|
+
* @param key The key to check for.
|
|
723
|
+
* @returns Is ``key`` present?
|
|
748
724
|
*/
|
|
749
|
-
has(key) {
|
|
725
|
+
has(key: any): boolean {
|
|
750
726
|
let ptrobj = _getPtr(this);
|
|
751
|
-
let idkey =
|
|
727
|
+
let idkey = Hiwire.new_value(key);
|
|
752
728
|
let result;
|
|
753
729
|
try {
|
|
754
730
|
result = Module.__pyproxy_contains(ptrobj, idkey);
|
|
755
731
|
} catch (e) {
|
|
756
|
-
|
|
732
|
+
API.fatal_error(e);
|
|
757
733
|
} finally {
|
|
758
|
-
|
|
734
|
+
Hiwire.decref(idkey);
|
|
759
735
|
}
|
|
760
736
|
if (result === -1) {
|
|
761
737
|
Module._pythonexc2js();
|
|
@@ -763,7 +739,6 @@ class PyProxyContainsMethods {
|
|
|
763
739
|
return result === 1;
|
|
764
740
|
}
|
|
765
741
|
}
|
|
766
|
-
|
|
767
742
|
/**
|
|
768
743
|
* A helper for [Symbol.iterator].
|
|
769
744
|
*
|
|
@@ -780,14 +755,14 @@ class PyProxyContainsMethods {
|
|
|
780
755
|
*
|
|
781
756
|
* @private
|
|
782
757
|
*/
|
|
783
|
-
function* iter_helper(iterptr, token) {
|
|
758
|
+
function* iter_helper(iterptr: number, token: {}): Generator<any> {
|
|
784
759
|
try {
|
|
785
760
|
let item;
|
|
786
761
|
while ((item = Module.__pyproxy_iter_next(iterptr))) {
|
|
787
|
-
yield
|
|
762
|
+
yield Hiwire.pop_value(item);
|
|
788
763
|
}
|
|
789
764
|
} catch (e) {
|
|
790
|
-
|
|
765
|
+
API.fatal_error(e);
|
|
791
766
|
} finally {
|
|
792
767
|
Module.finalizationRegistry.unregister(token);
|
|
793
768
|
Module._Py_DecRef(iterptr);
|
|
@@ -796,16 +771,12 @@ function* iter_helper(iterptr, token) {
|
|
|
796
771
|
Module._pythonexc2js();
|
|
797
772
|
}
|
|
798
773
|
}
|
|
799
|
-
|
|
800
|
-
/**
|
|
801
|
-
* @typedef {PyProxy & PyProxyIterableMethods} PyProxyIterable
|
|
802
|
-
*/
|
|
803
|
-
|
|
774
|
+
export type PyProxyIterable = PyProxy & PyProxyIterableMethods;
|
|
804
775
|
// Controlled by IS_ITERABLE, appears for any object with __iter__ or tp_iter,
|
|
805
776
|
// unless they are iterators. See: https://docs.python.org/3/c-api/iter.html
|
|
806
777
|
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols
|
|
807
778
|
// This avoids allocating a PyProxy wrapper for the temporary iterator.
|
|
808
|
-
class PyProxyIterableMethods {
|
|
779
|
+
export class PyProxyIterableMethods {
|
|
809
780
|
/**
|
|
810
781
|
* This translates to the Python code ``iter(obj)``. Return an iterator
|
|
811
782
|
* associated to the proxy. See the documentation for `Symbol.iterator
|
|
@@ -815,117 +786,110 @@ class PyProxyIterableMethods {
|
|
|
815
786
|
* ``__iter__`` method).
|
|
816
787
|
*
|
|
817
788
|
* This will be used implicitly by ``for(let x of proxy){}``.
|
|
818
|
-
*
|
|
819
|
-
* @returns {Iterator<Py2JsResult, Py2JsResult, any>} An iterator for the proxied Python object.
|
|
820
789
|
*/
|
|
821
|
-
[Symbol.iterator]() {
|
|
790
|
+
[Symbol.iterator](): Iterator<any, any, any> {
|
|
822
791
|
let ptrobj = _getPtr(this);
|
|
823
792
|
let token = {};
|
|
824
793
|
let iterptr;
|
|
825
794
|
try {
|
|
826
795
|
iterptr = Module._PyObject_GetIter(ptrobj);
|
|
827
796
|
} catch (e) {
|
|
828
|
-
|
|
797
|
+
API.fatal_error(e);
|
|
829
798
|
}
|
|
830
799
|
if (iterptr === 0) {
|
|
831
800
|
Module._pythonexc2js();
|
|
832
801
|
}
|
|
833
|
-
|
|
834
802
|
let result = iter_helper(iterptr, token);
|
|
835
803
|
Module.finalizationRegistry.register(result, [iterptr, undefined], token);
|
|
836
804
|
return result;
|
|
837
805
|
}
|
|
838
806
|
}
|
|
839
|
-
|
|
840
|
-
/**
|
|
841
|
-
* @typedef {PyProxy & PyProxyIteratorMethods} PyProxyIterator
|
|
842
|
-
*/
|
|
843
|
-
|
|
807
|
+
export type PyProxyIterator = PyProxy & PyProxyIteratorMethods;
|
|
844
808
|
// Controlled by IS_ITERATOR, appears for any object with a __next__ or
|
|
845
809
|
// tp_iternext method.
|
|
846
|
-
class PyProxyIteratorMethods {
|
|
810
|
+
export class PyProxyIteratorMethods {
|
|
811
|
+
/** @private */
|
|
847
812
|
[Symbol.iterator]() {
|
|
848
813
|
return this;
|
|
849
814
|
}
|
|
850
815
|
/**
|
|
851
|
-
* This translates to the Python code ``next(obj)``. Returns the next value
|
|
852
|
-
*
|
|
816
|
+
* This translates to the Python code ``next(obj)``. Returns the next value of
|
|
817
|
+
* the generator. See the documentation for `Generator.prototype.next
|
|
853
818
|
* <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Generator/next>`_.
|
|
854
819
|
* The argument will be sent to the Python generator.
|
|
855
820
|
*
|
|
856
821
|
* This will be used implicitly by ``for(let x of proxy){}``.
|
|
857
822
|
*
|
|
858
|
-
* Present only if the proxied Python object is a generator or iterator
|
|
859
|
-
*
|
|
823
|
+
* Present only if the proxied Python object is a generator or iterator (i.e.,
|
|
824
|
+
* has a ``send`` or ``__next__`` method).
|
|
860
825
|
*
|
|
861
|
-
* @param
|
|
862
|
-
*
|
|
863
|
-
* @returns
|
|
864
|
-
*
|
|
865
|
-
*
|
|
866
|
-
*
|
|
867
|
-
* true, value : result_value}``.
|
|
826
|
+
* @param any The value to send to the generator. The value will be assigned
|
|
827
|
+
* as a result of a yield expression.
|
|
828
|
+
* @returns An Object with two properties: ``done`` and ``value``. When the
|
|
829
|
+
* generator yields ``some_value``, ``next`` returns ``{done : false, value :
|
|
830
|
+
* some_value}``. When the generator raises a ``StopIteration(result_value)``
|
|
831
|
+
* exception, ``next`` returns ``{done : true, value : result_value}``.
|
|
868
832
|
*/
|
|
869
|
-
next(arg = undefined) {
|
|
870
|
-
let idresult;
|
|
833
|
+
next(arg: any = undefined): IteratorResult<any, any> {
|
|
871
834
|
// Note: arg is optional, if arg is not supplied, it will be undefined
|
|
872
835
|
// which gets converted to "Py_None". This is as intended.
|
|
873
|
-
let idarg =
|
|
836
|
+
let idarg = Hiwire.new_value(arg);
|
|
837
|
+
let status;
|
|
874
838
|
let done;
|
|
839
|
+
let stackTop = Module.stackSave();
|
|
840
|
+
let res_ptr = Module.stackAlloc(4);
|
|
875
841
|
try {
|
|
876
|
-
|
|
877
|
-
done = idresult === 0;
|
|
878
|
-
if (done) {
|
|
879
|
-
idresult = Module.__pyproxyGen_FetchStopIterationValue();
|
|
880
|
-
}
|
|
842
|
+
status = Module.__pyproxyGen_Send(_getPtr(this), idarg, res_ptr);
|
|
881
843
|
} catch (e) {
|
|
882
|
-
|
|
844
|
+
API.fatal_error(e);
|
|
883
845
|
} finally {
|
|
884
|
-
|
|
846
|
+
Hiwire.decref(idarg);
|
|
885
847
|
}
|
|
886
|
-
|
|
848
|
+
let HEAPU32 = Module.HEAPU32;
|
|
849
|
+
let idresult = HEAPU32[(res_ptr >> 2) + 0];
|
|
850
|
+
Module.stackRestore(stackTop);
|
|
851
|
+
if (status === -1) {
|
|
887
852
|
Module._pythonexc2js();
|
|
888
853
|
}
|
|
889
|
-
let value =
|
|
854
|
+
let value = Hiwire.pop_value(idresult);
|
|
855
|
+
done = status === 0;
|
|
890
856
|
return { done, value };
|
|
891
857
|
}
|
|
892
858
|
}
|
|
893
|
-
|
|
894
859
|
// Another layer of boilerplate. The PyProxyHandlers have some annoying logic
|
|
895
860
|
// to deal with straining out the spurious "Function" properties "prototype",
|
|
896
861
|
// "arguments", and "length", to deal with correctly satisfying the Proxy
|
|
897
862
|
// invariants, and to deal with the mro
|
|
898
|
-
function python_hasattr(jsobj, jskey) {
|
|
863
|
+
function python_hasattr(jsobj: PyProxyClass, jskey: any) {
|
|
899
864
|
let ptrobj = _getPtr(jsobj);
|
|
900
|
-
let idkey =
|
|
865
|
+
let idkey = Hiwire.new_value(jskey);
|
|
901
866
|
let result;
|
|
902
867
|
try {
|
|
903
868
|
result = Module.__pyproxy_hasattr(ptrobj, idkey);
|
|
904
869
|
} catch (e) {
|
|
905
|
-
|
|
870
|
+
API.fatal_error(e);
|
|
906
871
|
} finally {
|
|
907
|
-
|
|
872
|
+
Hiwire.decref(idkey);
|
|
908
873
|
}
|
|
909
874
|
if (result === -1) {
|
|
910
875
|
Module._pythonexc2js();
|
|
911
876
|
}
|
|
912
877
|
return result !== 0;
|
|
913
878
|
}
|
|
914
|
-
|
|
915
879
|
// Returns a JsRef in order to allow us to differentiate between "not found"
|
|
916
880
|
// (in which case we return 0) and "found 'None'" (in which case we return
|
|
917
881
|
// Js_undefined).
|
|
918
|
-
function python_getattr(jsobj, jskey) {
|
|
882
|
+
function python_getattr(jsobj: PyProxyClass, jskey: any) {
|
|
919
883
|
let ptrobj = _getPtr(jsobj);
|
|
920
|
-
let idkey =
|
|
884
|
+
let idkey = Hiwire.new_value(jskey);
|
|
921
885
|
let idresult;
|
|
922
886
|
let cacheId = jsobj.$$.cache.cacheId;
|
|
923
887
|
try {
|
|
924
888
|
idresult = Module.__pyproxy_getattr(ptrobj, idkey, cacheId);
|
|
925
889
|
} catch (e) {
|
|
926
|
-
|
|
890
|
+
API.fatal_error(e);
|
|
927
891
|
} finally {
|
|
928
|
-
|
|
892
|
+
Hiwire.decref(idkey);
|
|
929
893
|
}
|
|
930
894
|
if (idresult === 0) {
|
|
931
895
|
if (Module._PyErr_Occurred()) {
|
|
@@ -934,41 +898,38 @@ function python_getattr(jsobj, jskey) {
|
|
|
934
898
|
}
|
|
935
899
|
return idresult;
|
|
936
900
|
}
|
|
937
|
-
|
|
938
|
-
function python_setattr(jsobj, jskey, jsval) {
|
|
901
|
+
function python_setattr(jsobj: PyProxyClass, jskey: any, jsval: any) {
|
|
939
902
|
let ptrobj = _getPtr(jsobj);
|
|
940
|
-
let idkey =
|
|
941
|
-
let idval =
|
|
903
|
+
let idkey = Hiwire.new_value(jskey);
|
|
904
|
+
let idval = Hiwire.new_value(jsval);
|
|
942
905
|
let errcode;
|
|
943
906
|
try {
|
|
944
907
|
errcode = Module.__pyproxy_setattr(ptrobj, idkey, idval);
|
|
945
908
|
} catch (e) {
|
|
946
|
-
|
|
909
|
+
API.fatal_error(e);
|
|
947
910
|
} finally {
|
|
948
|
-
|
|
949
|
-
|
|
911
|
+
Hiwire.decref(idkey);
|
|
912
|
+
Hiwire.decref(idval);
|
|
950
913
|
}
|
|
951
914
|
if (errcode === -1) {
|
|
952
915
|
Module._pythonexc2js();
|
|
953
916
|
}
|
|
954
917
|
}
|
|
955
|
-
|
|
956
|
-
function python_delattr(jsobj, jskey) {
|
|
918
|
+
function python_delattr(jsobj: PyProxyClass, jskey: any) {
|
|
957
919
|
let ptrobj = _getPtr(jsobj);
|
|
958
|
-
let idkey =
|
|
920
|
+
let idkey = Hiwire.new_value(jskey);
|
|
959
921
|
let errcode;
|
|
960
922
|
try {
|
|
961
923
|
errcode = Module.__pyproxy_delattr(ptrobj, idkey);
|
|
962
924
|
} catch (e) {
|
|
963
|
-
|
|
925
|
+
API.fatal_error(e);
|
|
964
926
|
} finally {
|
|
965
|
-
|
|
927
|
+
Hiwire.decref(idkey);
|
|
966
928
|
}
|
|
967
929
|
if (errcode === -1) {
|
|
968
930
|
Module._pythonexc2js();
|
|
969
931
|
}
|
|
970
932
|
}
|
|
971
|
-
|
|
972
933
|
// See explanation of which methods should be defined here and what they do
|
|
973
934
|
// here:
|
|
974
935
|
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy
|
|
@@ -976,7 +937,7 @@ let PyProxyHandlers = {
|
|
|
976
937
|
isExtensible() {
|
|
977
938
|
return (!!1);
|
|
978
939
|
},
|
|
979
|
-
has(jsobj, jskey) {
|
|
940
|
+
has(jsobj: PyProxyClass, jskey: any) {
|
|
980
941
|
// Note: must report "prototype" in proxy when we are callable.
|
|
981
942
|
// (We can return the wrong value from "get" handler though.)
|
|
982
943
|
let objHasKey = Reflect.has(jsobj, jskey);
|
|
@@ -992,11 +953,10 @@ let PyProxyHandlers = {
|
|
|
992
953
|
}
|
|
993
954
|
return python_hasattr(jsobj, jskey);
|
|
994
955
|
},
|
|
995
|
-
get(jsobj, jskey) {
|
|
956
|
+
get(jsobj: PyProxyClass, jskey: any) {
|
|
996
957
|
// Preference order:
|
|
997
958
|
// 1. stuff from JavaScript
|
|
998
959
|
// 2. the result of Python getattr
|
|
999
|
-
|
|
1000
960
|
// python_getattr will crash if given a Symbol.
|
|
1001
961
|
if (jskey in jsobj || typeof jskey === "symbol") {
|
|
1002
962
|
return Reflect.get(jsobj, jskey);
|
|
@@ -1009,10 +969,10 @@ let PyProxyHandlers = {
|
|
|
1009
969
|
// 2. The result of getattr
|
|
1010
970
|
let idresult = python_getattr(jsobj, jskey);
|
|
1011
971
|
if (idresult !== 0) {
|
|
1012
|
-
return
|
|
972
|
+
return Hiwire.pop_value(idresult);
|
|
1013
973
|
}
|
|
1014
974
|
},
|
|
1015
|
-
set(jsobj, jskey, jsval) {
|
|
975
|
+
set(jsobj: PyProxyClass, jskey: any, jsval: any) {
|
|
1016
976
|
let descr = Object.getOwnPropertyDescriptor(jsobj, jskey);
|
|
1017
977
|
if (descr && !descr.writable) {
|
|
1018
978
|
throw new TypeError(`Cannot set read only field '${jskey}'`);
|
|
@@ -1027,7 +987,7 @@ let PyProxyHandlers = {
|
|
|
1027
987
|
python_setattr(jsobj, jskey, jsval);
|
|
1028
988
|
return (!!1);
|
|
1029
989
|
},
|
|
1030
|
-
deleteProperty(jsobj, jskey) {
|
|
990
|
+
deleteProperty(jsobj: PyProxyClass, jskey: any): boolean {
|
|
1031
991
|
let descr = Object.getOwnPropertyDescriptor(jsobj, jskey);
|
|
1032
992
|
if (descr && !descr.writable) {
|
|
1033
993
|
throw new TypeError(`Cannot delete read only field '${jskey}'`);
|
|
@@ -1041,44 +1001,41 @@ let PyProxyHandlers = {
|
|
|
1041
1001
|
python_delattr(jsobj, jskey);
|
|
1042
1002
|
// Must return "false" if "jskey" is a nonconfigurable own property.
|
|
1043
1003
|
// Otherwise JavaScript will throw a TypeError.
|
|
1044
|
-
return !descr || descr.configurable;
|
|
1004
|
+
return !descr || !!descr.configurable;
|
|
1045
1005
|
},
|
|
1046
|
-
ownKeys(jsobj) {
|
|
1006
|
+
ownKeys(jsobj: PyProxyClass) {
|
|
1047
1007
|
let ptrobj = _getPtr(jsobj);
|
|
1048
1008
|
let idresult;
|
|
1049
1009
|
try {
|
|
1050
1010
|
idresult = Module.__pyproxy_ownKeys(ptrobj);
|
|
1051
1011
|
} catch (e) {
|
|
1052
|
-
|
|
1012
|
+
API.fatal_error(e);
|
|
1053
1013
|
}
|
|
1054
1014
|
if (idresult === 0) {
|
|
1055
1015
|
Module._pythonexc2js();
|
|
1056
1016
|
}
|
|
1057
|
-
let result =
|
|
1017
|
+
let result = Hiwire.pop_value(idresult);
|
|
1058
1018
|
result.push(...Reflect.ownKeys(jsobj));
|
|
1059
1019
|
return result;
|
|
1060
1020
|
},
|
|
1061
|
-
apply(jsobj, jsthis, jsargs) {
|
|
1021
|
+
apply(jsobj: PyProxyClass & Function, jsthis: any, jsargs: any) {
|
|
1062
1022
|
return jsobj.apply(jsthis, jsargs);
|
|
1063
1023
|
},
|
|
1064
1024
|
};
|
|
1065
|
-
|
|
1066
|
-
/**
|
|
1067
|
-
* @typedef {PyProxy & Promise<Py2JsResult>} PyProxyAwaitable
|
|
1068
|
-
*/
|
|
1069
|
-
|
|
1025
|
+
export type PyProxyAwaitable = PyProxy & Promise<any>;
|
|
1070
1026
|
/**
|
|
1071
1027
|
* The Promise / JavaScript awaitable API.
|
|
1072
1028
|
* @private
|
|
1073
1029
|
*/
|
|
1074
|
-
class PyProxyAwaitableMethods {
|
|
1030
|
+
export class PyProxyAwaitableMethods {
|
|
1031
|
+
$$: any;
|
|
1075
1032
|
/**
|
|
1076
1033
|
* This wraps __pyproxy_ensure_future and makes a function that converts a
|
|
1077
1034
|
* Python awaitable to a promise, scheduling the awaitable on the Python
|
|
1078
1035
|
* event loop if necessary.
|
|
1079
1036
|
* @private
|
|
1080
1037
|
*/
|
|
1081
|
-
_ensure_future() {
|
|
1038
|
+
_ensure_future(): Promise<any> {
|
|
1082
1039
|
if (this.$$.promise) {
|
|
1083
1040
|
return this.$$.promise;
|
|
1084
1041
|
}
|
|
@@ -1089,8 +1046,8 @@ class PyProxyAwaitableMethods {
|
|
|
1089
1046
|
resolveHandle = resolve;
|
|
1090
1047
|
rejectHandle = reject;
|
|
1091
1048
|
});
|
|
1092
|
-
let resolve_handle_id =
|
|
1093
|
-
let reject_handle_id =
|
|
1049
|
+
let resolve_handle_id = Hiwire.new_value(resolveHandle);
|
|
1050
|
+
let reject_handle_id = Hiwire.new_value(rejectHandle);
|
|
1094
1051
|
let errcode;
|
|
1095
1052
|
try {
|
|
1096
1053
|
errcode = Module.__pyproxy_ensure_future(
|
|
@@ -1099,15 +1056,16 @@ class PyProxyAwaitableMethods {
|
|
|
1099
1056
|
reject_handle_id
|
|
1100
1057
|
);
|
|
1101
1058
|
} catch (e) {
|
|
1102
|
-
|
|
1059
|
+
API.fatal_error(e);
|
|
1103
1060
|
} finally {
|
|
1104
|
-
|
|
1105
|
-
|
|
1061
|
+
Hiwire.decref(reject_handle_id);
|
|
1062
|
+
Hiwire.decref(resolve_handle_id);
|
|
1106
1063
|
}
|
|
1107
1064
|
if (errcode === -1) {
|
|
1108
1065
|
Module._pythonexc2js();
|
|
1109
1066
|
}
|
|
1110
1067
|
this.$$.promise = promise;
|
|
1068
|
+
// @ts-ignore
|
|
1111
1069
|
this.destroy();
|
|
1112
1070
|
return promise;
|
|
1113
1071
|
}
|
|
@@ -1115,7 +1073,7 @@ class PyProxyAwaitableMethods {
|
|
|
1115
1073
|
* Runs ``asyncio.ensure_future(awaitable)``, executes
|
|
1116
1074
|
* ``onFulfilled(result)`` when the ``Future`` resolves successfully,
|
|
1117
1075
|
* executes ``onRejected(error)`` when the ``Future`` fails. Will be used
|
|
1118
|
-
*
|
|
1076
|
+
* implicitly by ``await obj``.
|
|
1119
1077
|
*
|
|
1120
1078
|
* See the documentation for
|
|
1121
1079
|
* `Promise.then
|
|
@@ -1124,13 +1082,16 @@ class PyProxyAwaitableMethods {
|
|
|
1124
1082
|
* Present only if the proxied Python object is `awaitable
|
|
1125
1083
|
* <https://docs.python.org/3/library/asyncio-task.html?highlight=awaitable#awaitables>`_.
|
|
1126
1084
|
*
|
|
1127
|
-
* @param
|
|
1085
|
+
* @param onFulfilled A handler called with the result as an
|
|
1128
1086
|
* argument if the awaitable succeeds.
|
|
1129
|
-
* @param
|
|
1087
|
+
* @param onRejected A handler called with the error as an
|
|
1130
1088
|
* argument if the awaitable fails.
|
|
1131
|
-
* @returns
|
|
1089
|
+
* @returns The resulting Promise.
|
|
1132
1090
|
*/
|
|
1133
|
-
then(
|
|
1091
|
+
then(
|
|
1092
|
+
onFulfilled: (value: any) => any,
|
|
1093
|
+
onRejected: (reason: any) => any
|
|
1094
|
+
): Promise<any> {
|
|
1134
1095
|
let promise = this._ensure_future();
|
|
1135
1096
|
return promise.then(onFulfilled, onRejected);
|
|
1136
1097
|
}
|
|
@@ -1145,11 +1106,11 @@ class PyProxyAwaitableMethods {
|
|
|
1145
1106
|
* Present only if the proxied Python object is `awaitable
|
|
1146
1107
|
* <https://docs.python.org/3/library/asyncio-task.html?highlight=awaitable#awaitables>`_.
|
|
1147
1108
|
*
|
|
1148
|
-
* @param
|
|
1109
|
+
* @param onRejected A handler called with the error as an
|
|
1149
1110
|
* argument if the awaitable fails.
|
|
1150
|
-
* @returns
|
|
1111
|
+
* @returns The resulting Promise.
|
|
1151
1112
|
*/
|
|
1152
|
-
catch(onRejected) {
|
|
1113
|
+
catch(onRejected: (reason: any) => any) {
|
|
1153
1114
|
let promise = this._ensure_future();
|
|
1154
1115
|
return promise.catch(onRejected);
|
|
1155
1116
|
}
|
|
@@ -1165,33 +1126,32 @@ class PyProxyAwaitableMethods {
|
|
|
1165
1126
|
* <https://docs.python.org/3/library/asyncio-task.html?highlight=awaitable#awaitables>`_.
|
|
1166
1127
|
*
|
|
1167
1128
|
*
|
|
1168
|
-
* @param
|
|
1129
|
+
* @param onFinally A handler that is called with zero arguments
|
|
1169
1130
|
* when the awaitable resolves.
|
|
1170
|
-
* @returns
|
|
1131
|
+
* @returns A Promise that resolves or rejects with the same
|
|
1171
1132
|
* result as the original Promise, but only after executing the
|
|
1172
1133
|
* ``onFinally`` handler.
|
|
1173
1134
|
*/
|
|
1174
|
-
finally(onFinally) {
|
|
1135
|
+
finally(onFinally: () => void) {
|
|
1175
1136
|
let promise = this._ensure_future();
|
|
1176
1137
|
return promise.finally(onFinally);
|
|
1177
1138
|
}
|
|
1178
1139
|
}
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
apply(jsthis, jsargs) {
|
|
1140
|
+
export type PyProxyCallable = PyProxy &
|
|
1141
|
+
PyProxyCallableMethods &
|
|
1142
|
+
((...args: any[]) => any);
|
|
1143
|
+
export class PyProxyCallableMethods {
|
|
1144
|
+
apply(jsthis: PyProxyClass, jsargs: any) {
|
|
1185
1145
|
return Module.callPyObject(_getPtr(this), ...jsargs);
|
|
1186
1146
|
}
|
|
1187
|
-
call(jsthis, ...jsargs) {
|
|
1147
|
+
call(jsthis: PyProxyClass, ...jsargs: any) {
|
|
1188
1148
|
return Module.callPyObject(_getPtr(this), ...jsargs);
|
|
1189
1149
|
}
|
|
1190
1150
|
/**
|
|
1191
1151
|
* Call the function with key word arguments.
|
|
1192
1152
|
* The last argument must be an object with the keyword arguments.
|
|
1193
1153
|
*/
|
|
1194
|
-
callKwargs(...jsargs) {
|
|
1154
|
+
callKwargs(...jsargs: any) {
|
|
1195
1155
|
if (jsargs.length === 0) {
|
|
1196
1156
|
throw new TypeError(
|
|
1197
1157
|
"callKwargs requires at least one argument (the key word argument object)"
|
|
@@ -1207,9 +1167,10 @@ class PyProxyCallableMethods {
|
|
|
1207
1167
|
return Module.callPyObjectKwargs(_getPtr(this), ...jsargs);
|
|
1208
1168
|
}
|
|
1209
1169
|
}
|
|
1170
|
+
// @ts-ignore
|
|
1210
1171
|
PyProxyCallableMethods.prototype.prototype = Function.prototype;
|
|
1211
|
-
|
|
1212
|
-
let type_to_array_map = new Map([
|
|
1172
|
+
// @ts-ignore
|
|
1173
|
+
let type_to_array_map: Map<string, any> = new Map([
|
|
1213
1174
|
["i8", Int8Array],
|
|
1214
1175
|
["u8", Uint8Array],
|
|
1215
1176
|
["u8clamped", Uint8ClampedArray],
|
|
@@ -1227,11 +1188,8 @@ let type_to_array_map = new Map([
|
|
|
1227
1188
|
["f64", Float64Array],
|
|
1228
1189
|
["dataview", DataView],
|
|
1229
1190
|
]);
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
* @typedef {PyProxy & PyProxyBufferMethods} PyProxyBuffer
|
|
1233
|
-
*/
|
|
1234
|
-
class PyProxyBufferMethods {
|
|
1191
|
+
export type PyProxyBuffer = PyProxy & PyProxyBufferMethods;
|
|
1192
|
+
export class PyProxyBufferMethods {
|
|
1235
1193
|
/**
|
|
1236
1194
|
* Get a view of the buffer data which is usable from JavaScript. No copy is
|
|
1237
1195
|
* ever performed.
|
|
@@ -1253,16 +1211,16 @@ class PyProxyBufferMethods {
|
|
|
1253
1211
|
* have support for big endian data, so you might want to pass
|
|
1254
1212
|
* ``'dataview'`` as the type argument in that case.
|
|
1255
1213
|
*
|
|
1256
|
-
* @param
|
|
1214
|
+
* @param type The type of the :any:`PyBuffer.data <pyodide.PyBuffer.data>` field in the
|
|
1257
1215
|
* output. Should be one of: ``"i8"``, ``"u8"``, ``"u8clamped"``, ``"i16"``,
|
|
1258
1216
|
* ``"u16"``, ``"i32"``, ``"u32"``, ``"i32"``, ``"u32"``, ``"i64"``,
|
|
1259
1217
|
* ``"u64"``, ``"f32"``, ``"f64``, or ``"dataview"``. This argument is
|
|
1260
1218
|
* optional, if absent ``getBuffer`` will try to determine the appropriate
|
|
1261
1219
|
* output type based on the buffer `format string
|
|
1262
1220
|
* <https://docs.python.org/3/library/struct.html#format-strings>`_.
|
|
1263
|
-
* @returns
|
|
1221
|
+
* @returns :any:`PyBuffer <pyodide.PyBuffer>`
|
|
1264
1222
|
*/
|
|
1265
|
-
getBuffer(type) {
|
|
1223
|
+
getBuffer(type?: string): PyBuffer {
|
|
1266
1224
|
let ArrayType = undefined;
|
|
1267
1225
|
if (type) {
|
|
1268
1226
|
ArrayType = type_to_array_map.get(type);
|
|
@@ -1280,30 +1238,25 @@ class PyProxyBufferMethods {
|
|
|
1280
1238
|
try {
|
|
1281
1239
|
errcode = Module.__pyproxy_get_buffer(buffer_struct_ptr, this_ptr);
|
|
1282
1240
|
} catch (e) {
|
|
1283
|
-
|
|
1241
|
+
API.fatal_error(e);
|
|
1284
1242
|
}
|
|
1285
1243
|
if (errcode === -1) {
|
|
1286
1244
|
Module._pythonexc2js();
|
|
1287
1245
|
}
|
|
1288
|
-
|
|
1289
1246
|
// This has to match the fields in buffer_struct
|
|
1290
1247
|
let startByteOffset = HEAPU32[(buffer_struct_ptr >> 2) + 0];
|
|
1291
1248
|
let minByteOffset = HEAPU32[(buffer_struct_ptr >> 2) + 1];
|
|
1292
1249
|
let maxByteOffset = HEAPU32[(buffer_struct_ptr >> 2) + 2];
|
|
1293
|
-
|
|
1294
1250
|
let readonly = !!HEAPU32[(buffer_struct_ptr >> 2) + 3];
|
|
1295
1251
|
let format_ptr = HEAPU32[(buffer_struct_ptr >> 2) + 4];
|
|
1296
1252
|
let itemsize = HEAPU32[(buffer_struct_ptr >> 2) + 5];
|
|
1297
|
-
let shape =
|
|
1298
|
-
let strides =
|
|
1299
|
-
|
|
1253
|
+
let shape = Hiwire.pop_value(HEAPU32[(buffer_struct_ptr >> 2) + 6]);
|
|
1254
|
+
let strides = Hiwire.pop_value(HEAPU32[(buffer_struct_ptr >> 2) + 7]);
|
|
1300
1255
|
let view_ptr = HEAPU32[(buffer_struct_ptr >> 2) + 8];
|
|
1301
1256
|
let c_contiguous = !!HEAPU32[(buffer_struct_ptr >> 2) + 9];
|
|
1302
1257
|
let f_contiguous = !!HEAPU32[(buffer_struct_ptr >> 2) + 10];
|
|
1303
|
-
|
|
1304
1258
|
let format = Module.UTF8ToString(format_ptr);
|
|
1305
1259
|
Module.stackRestore(orig_stack_ptr);
|
|
1306
|
-
|
|
1307
1260
|
let success = (!!0);
|
|
1308
1261
|
try {
|
|
1309
1262
|
let bigEndian = (!!0);
|
|
@@ -1346,7 +1299,6 @@ class PyProxyBufferMethods {
|
|
|
1346
1299
|
for (let i of strides.keys()) {
|
|
1347
1300
|
strides[i] /= alignment;
|
|
1348
1301
|
}
|
|
1349
|
-
|
|
1350
1302
|
success = (!!1);
|
|
1351
1303
|
let result = Object.create(
|
|
1352
1304
|
PyBuffer.prototype,
|
|
@@ -1374,17 +1326,23 @@ class PyProxyBufferMethods {
|
|
|
1374
1326
|
Module._PyBuffer_Release(view_ptr);
|
|
1375
1327
|
Module._PyMem_Free(view_ptr);
|
|
1376
1328
|
} catch (e) {
|
|
1377
|
-
|
|
1329
|
+
API.fatal_error(e);
|
|
1378
1330
|
}
|
|
1379
1331
|
}
|
|
1380
1332
|
}
|
|
1381
1333
|
}
|
|
1382
1334
|
}
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1335
|
+
export type TypedArray =
|
|
1336
|
+
| Int8Array
|
|
1337
|
+
| Uint8Array
|
|
1338
|
+
| Int16Array
|
|
1339
|
+
| Uint16Array
|
|
1340
|
+
| Int32Array
|
|
1341
|
+
| Uint32Array
|
|
1342
|
+
| Uint8ClampedArray
|
|
1343
|
+
| Float32Array
|
|
1344
|
+
| Float64Array;
|
|
1345
|
+
export type PyProxyDict = PyProxyWithGet & PyProxyWithSet & PyProxyWithHas;
|
|
1388
1346
|
/**
|
|
1389
1347
|
* A class to allow access to a Python data buffers from JavaScript. These are
|
|
1390
1348
|
* produced by :any:`PyProxy.getBuffer` and cannot be constructed directly.
|
|
@@ -1452,93 +1410,82 @@ class PyProxyBufferMethods {
|
|
|
1452
1410
|
* );
|
|
1453
1411
|
*/
|
|
1454
1412
|
export class PyBuffer {
|
|
1413
|
+
/**
|
|
1414
|
+
* The offset of the first entry of the array. For instance if our array
|
|
1415
|
+
* is 3d, then you will find ``array[0,0,0]`` at
|
|
1416
|
+
* ``pybuf.data[pybuf.offset]``
|
|
1417
|
+
*/
|
|
1418
|
+
offset: number;
|
|
1419
|
+
/**
|
|
1420
|
+
* If the data is readonly, you should not modify it. There is no way
|
|
1421
|
+
* for us to enforce this, but it may cause very weird behavior.
|
|
1422
|
+
*/
|
|
1423
|
+
readonly: boolean;
|
|
1424
|
+
/**
|
|
1425
|
+
* The format string for the buffer. See `the Python documentation on
|
|
1426
|
+
* format strings
|
|
1427
|
+
* <https://docs.python.org/3/library/struct.html#format-strings>`_.
|
|
1428
|
+
*/
|
|
1429
|
+
format: string;
|
|
1430
|
+
/**
|
|
1431
|
+
* How large is each entry (in bytes)?
|
|
1432
|
+
*/
|
|
1433
|
+
itemsize: number;
|
|
1434
|
+
/**
|
|
1435
|
+
* The number of dimensions of the buffer. If ``ndim`` is 0, the buffer
|
|
1436
|
+
* represents a single scalar or struct. Otherwise, it represents an
|
|
1437
|
+
* array.
|
|
1438
|
+
*/
|
|
1439
|
+
ndim: number;
|
|
1440
|
+
/**
|
|
1441
|
+
* The total number of bytes the buffer takes up. This is equal to
|
|
1442
|
+
* ``buff.data.byteLength``.
|
|
1443
|
+
*/
|
|
1444
|
+
nbytes: number;
|
|
1445
|
+
/**
|
|
1446
|
+
* The shape of the buffer, that is how long it is in each dimension.
|
|
1447
|
+
* The length will be equal to ``ndim``. For instance, a 2x3x4 array
|
|
1448
|
+
* would have shape ``[2, 3, 4]``.
|
|
1449
|
+
*/
|
|
1450
|
+
shape: number[];
|
|
1451
|
+
/**
|
|
1452
|
+
* An array of of length ``ndim`` giving the number of elements to skip
|
|
1453
|
+
* to get to a new element in each dimension. See the example definition
|
|
1454
|
+
* of a ``multiIndexToIndex`` function above.
|
|
1455
|
+
*/
|
|
1456
|
+
strides: number[];
|
|
1457
|
+
/**
|
|
1458
|
+
* The actual data. A typed array of an appropriate size backed by a
|
|
1459
|
+
* segment of the WASM memory.
|
|
1460
|
+
*
|
|
1461
|
+
* The ``type`` argument of :any:`PyProxy.getBuffer`
|
|
1462
|
+
* determines which sort of ``TypedArray`` this is. By default
|
|
1463
|
+
* :any:`PyProxy.getBuffer` will look at the format string to determine the most
|
|
1464
|
+
* appropriate option.
|
|
1465
|
+
*/
|
|
1466
|
+
data: TypedArray;
|
|
1467
|
+
/**
|
|
1468
|
+
* Is it C contiguous?
|
|
1469
|
+
*/
|
|
1470
|
+
c_contiguous: boolean;
|
|
1471
|
+
/**
|
|
1472
|
+
* Is it Fortran contiguous?
|
|
1473
|
+
*/
|
|
1474
|
+
f_contiguous: boolean;
|
|
1475
|
+
/**
|
|
1476
|
+
* @private
|
|
1477
|
+
*/
|
|
1478
|
+
_released: boolean;
|
|
1479
|
+
/**
|
|
1480
|
+
* @private
|
|
1481
|
+
*/
|
|
1482
|
+
_view_ptr: number;
|
|
1483
|
+
/**
|
|
1484
|
+
* @private
|
|
1485
|
+
*/
|
|
1455
1486
|
constructor() {
|
|
1456
|
-
/**
|
|
1457
|
-
* The offset of the first entry of the array. For instance if our array
|
|
1458
|
-
* is 3d, then you will find ``array[0,0,0]`` at
|
|
1459
|
-
* ``pybuf.data[pybuf.offset]``
|
|
1460
|
-
* @type {number}
|
|
1461
|
-
*/
|
|
1462
|
-
this.offset;
|
|
1463
|
-
|
|
1464
|
-
/**
|
|
1465
|
-
* If the data is readonly, you should not modify it. There is no way
|
|
1466
|
-
* for us to enforce this, but it may cause very weird behavior.
|
|
1467
|
-
* @type {boolean}
|
|
1468
|
-
*/
|
|
1469
|
-
this.readonly;
|
|
1470
|
-
|
|
1471
|
-
/**
|
|
1472
|
-
* The format string for the buffer. See `the Python documentation on
|
|
1473
|
-
* format strings
|
|
1474
|
-
* <https://docs.python.org/3/library/struct.html#format-strings>`_.
|
|
1475
|
-
* @type {string}
|
|
1476
|
-
*/
|
|
1477
|
-
this.format;
|
|
1478
|
-
|
|
1479
|
-
/**
|
|
1480
|
-
* How large is each entry (in bytes)?
|
|
1481
|
-
* @type {number}
|
|
1482
|
-
*/
|
|
1483
|
-
this.itemsize;
|
|
1484
|
-
|
|
1485
|
-
/**
|
|
1486
|
-
* The number of dimensions of the buffer. If ``ndim`` is 0, the buffer
|
|
1487
|
-
* represents a single scalar or struct. Otherwise, it represents an
|
|
1488
|
-
* array.
|
|
1489
|
-
* @type {number}
|
|
1490
|
-
*/
|
|
1491
|
-
this.ndim;
|
|
1492
|
-
|
|
1493
|
-
/**
|
|
1494
|
-
* The total number of bytes the buffer takes up. This is equal to
|
|
1495
|
-
* ``buff.data.byteLength``.
|
|
1496
|
-
* @type {number}
|
|
1497
|
-
*/
|
|
1498
|
-
this.nbytes;
|
|
1499
|
-
|
|
1500
|
-
/**
|
|
1501
|
-
* The shape of the buffer, that is how long it is in each dimension.
|
|
1502
|
-
* The length will be equal to ``ndim``. For instance, a 2x3x4 array
|
|
1503
|
-
* would have shape ``[2, 3, 4]``.
|
|
1504
|
-
* @type {number[]}
|
|
1505
|
-
*/
|
|
1506
|
-
this.shape;
|
|
1507
|
-
|
|
1508
|
-
/**
|
|
1509
|
-
* An array of of length ``ndim`` giving the number of elements to skip
|
|
1510
|
-
* to get to a new element in each dimension. See the example definition
|
|
1511
|
-
* of a ``multiIndexToIndex`` function above.
|
|
1512
|
-
* @type {number[]}
|
|
1513
|
-
*/
|
|
1514
|
-
this.strides;
|
|
1515
|
-
|
|
1516
|
-
/**
|
|
1517
|
-
* The actual data. A typed array of an appropriate size backed by a
|
|
1518
|
-
* segment of the WASM memory.
|
|
1519
|
-
*
|
|
1520
|
-
* The ``type`` argument of :any:`PyProxy.getBuffer`
|
|
1521
|
-
* determines which sort of ``TypedArray`` this is. By default
|
|
1522
|
-
* :any:`PyProxy.getBuffer` will look at the format string to determine the most
|
|
1523
|
-
* appropriate option.
|
|
1524
|
-
* @type {TypedArray}
|
|
1525
|
-
*/
|
|
1526
|
-
this.data;
|
|
1527
|
-
|
|
1528
|
-
/**
|
|
1529
|
-
* Is it C contiguous?
|
|
1530
|
-
* @type {boolean}
|
|
1531
|
-
*/
|
|
1532
|
-
this.c_contiguous;
|
|
1533
|
-
|
|
1534
|
-
/**
|
|
1535
|
-
* Is it Fortran contiguous?
|
|
1536
|
-
* @type {boolean}
|
|
1537
|
-
*/
|
|
1538
|
-
this.f_contiguous;
|
|
1539
1487
|
throw new TypeError("PyBuffer is not a constructor");
|
|
1540
1488
|
}
|
|
1541
|
-
|
|
1542
1489
|
/**
|
|
1543
1490
|
* Release the buffer. This allows the memory to be reclaimed.
|
|
1544
1491
|
*/
|
|
@@ -1551,9 +1498,10 @@ export class PyBuffer {
|
|
|
1551
1498
|
Module._PyBuffer_Release(this._view_ptr);
|
|
1552
1499
|
Module._PyMem_Free(this._view_ptr);
|
|
1553
1500
|
} catch (e) {
|
|
1554
|
-
|
|
1501
|
+
API.fatal_error(e);
|
|
1555
1502
|
}
|
|
1556
1503
|
this._released = (!!1);
|
|
1504
|
+
// @ts-ignore
|
|
1557
1505
|
this.data = null;
|
|
1558
1506
|
}
|
|
1559
1507
|
}
|