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