pyodide 0.20.0 → 0.21.0-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/pyproxy.gen.ts DELETED
@@ -1,1507 +0,0 @@
1
- // This file is generated by applying the C preprocessor to core/pyproxy.ts
2
- // It uses the macros defined in core/pyproxy.c
3
- // Do not edit it directly!
4
-
5
-
6
-
7
-
8
-
9
-
10
-
11
-
12
-
13
-
14
-
15
-
16
-
17
-
18
-
19
-
20
-
21
-
22
-
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
- * Every public Python entrypoint goes through this file! The main entrypoint is
110
- * the callPyObject method, but of course one can also execute arbitrary code
111
- * via the various __dundermethods__ associated to classes.
112
- *
113
- * Any time we call into wasm, the call should be wrapped in a try catch block.
114
- * This way if a JavaScript error emerges from the wasm, we can escalate it to a
115
- * fatal error.
116
- *
117
- * This is file is preprocessed with -imacros "pyproxy.c". As a result of this,
118
- * any macros available in pyproxy.c are available here. We only need the flags
119
- * macros HAS_LENGTH, etc.
120
- *
121
- * See Makefile recipe for src/js/pyproxy.gen.ts
122
- */
123
- import { Module, API, Hiwire } from "./module.js";
124
- /**
125
- * Is the argument a :any:`PyProxy`?
126
- * @param jsobj Object to test.
127
- * @returns Is ``jsobj`` a :any:`PyProxy`?
128
- */
129
- export function isPyProxy(jsobj: any): jsobj is PyProxy {
130
- return !!jsobj && jsobj.$$ !== undefined && jsobj.$$.type === "PyProxy";
131
- }
132
- API.isPyProxy = isPyProxy;
133
- declare var FinalizationRegistry: any;
134
- declare var globalThis: any;
135
- if (globalThis.FinalizationRegistry) {
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
- }
147
- }
148
- );
149
- // For some unclear reason this code screws up selenium FirefoxDriver. Works
150
- // fine in chrome and when I test it in browser. It seems to be sensitive to
151
- // changes that don't make a difference to the semantics.
152
- // TODO: after 0.18.0, fix selenium issues with this code.
153
- // Module.bufferFinalizationRegistry = new FinalizationRegistry((ptr) => {
154
- // try {
155
- // Module._PyBuffer_Release(ptr);
156
- // Module._PyMem_Free(ptr);
157
- // } catch (e) {
158
- // API.fatal_error(e);
159
- // }
160
- // });
161
- } else {
162
- Module.finalizationRegistry = { register() {}, unregister() {} };
163
- // Module.bufferFinalizationRegistry = finalizationRegistry;
164
- }
165
- let pyproxy_alloc_map = new Map();
166
- Module.pyproxy_alloc_map = pyproxy_alloc_map;
167
- let trace_pyproxy_alloc: (proxy: any) => void;
168
- let trace_pyproxy_dealloc: (proxy: any) => void;
169
- Module.enable_pyproxy_allocation_tracing = function () {
170
- trace_pyproxy_alloc = function (proxy: any) {
171
- pyproxy_alloc_map.set(proxy, Error().stack);
172
- };
173
- trace_pyproxy_dealloc = function (proxy: any) {
174
- pyproxy_alloc_map.delete(proxy);
175
- };
176
- };
177
- Module.disable_pyproxy_allocation_tracing = function () {
178
- trace_pyproxy_alloc = function (proxy: any) {};
179
- trace_pyproxy_dealloc = function (proxy: any) {};
180
- };
181
- Module.disable_pyproxy_allocation_tracing();
182
- type PyProxyCache = { cacheId: number; refcnt: number; leaked?: boolean };
183
- /**
184
- * Create a new PyProxy wrapping ptrobj which is a PyObject*.
185
- *
186
- * The argument cache is only needed to implement the PyProxy.copy API, it
187
- * allows the copy of the PyProxy to share its attribute cache with the original
188
- * version. In all other cases, pyproxy_new should be called with one argument.
189
- *
190
- * In the case that the Python object is callable, PyProxyClass inherits from
191
- * Function so that PyProxy objects can be callable. In that case we MUST expose
192
- * certain properties inherited from Function, but we do our best to remove as
193
- * many as possible.
194
- * @private
195
- */
196
- Module.pyproxy_new = function (ptrobj: number, cache?: PyProxyCache) {
197
- let flags = Module._pyproxy_getflags(ptrobj);
198
- let cls = Module.getPyProxyClass(flags);
199
- // Reflect.construct calls the constructor of Module.PyProxyClass but sets
200
- // the prototype as cls.prototype. This gives us a way to dynamically create
201
- // subclasses of PyProxyClass (as long as we don't need to use the "new
202
- // cls(ptrobj)" syntax).
203
- let target;
204
- if (flags & (1 << 8)) {
205
- // To make a callable proxy, we must call the Function constructor.
206
- // In this case we are effectively subclassing Function.
207
- target = Reflect.construct(Function, [], cls);
208
- // Remove undesirable properties added by Function constructor. Note: we
209
- // can't remove "arguments" or "caller" because they are not configurable
210
- // and not writable
211
- delete target.length;
212
- delete target.name;
213
- // prototype isn't configurable so we can't delete it but it's writable.
214
- target.prototype = undefined;
215
- } else {
216
- target = Object.create(cls.prototype);
217
- }
218
- if (!cache) {
219
- // The cache needs to be accessed primarily from the C function
220
- // _pyproxy_getattr so we make a hiwire id.
221
- let cacheId = Hiwire.new_value(new Map());
222
- cache = { cacheId, refcnt: 0 };
223
- }
224
- cache.refcnt++;
225
- Object.defineProperty(target, "$$", {
226
- value: { ptr: ptrobj, type: "PyProxy", cache },
227
- });
228
- Module._Py_IncRef(ptrobj);
229
- let proxy = new Proxy(target, PyProxyHandlers);
230
- trace_pyproxy_alloc(proxy);
231
- Module.finalizationRegistry.register(proxy, [ptrobj, cache], proxy);
232
- return proxy;
233
- };
234
- function _getPtr(jsobj: any) {
235
- let ptr: number = jsobj.$$.ptr;
236
- if (ptr === 0) {
237
- throw new Error(jsobj.$$.destroyed_msg);
238
- }
239
- return ptr;
240
- }
241
- let pyproxyClassMap = new Map();
242
- /**
243
- * Retrieve the appropriate mixins based on the features requested in flags.
244
- * Used by pyproxy_new. The "flags" variable is produced by the C function
245
- * pyproxy_getflags. Multiple PyProxies with the same set of feature flags
246
- * will share the same prototype, so the memory footprint of each individual
247
- * PyProxy is minimal.
248
- * @private
249
- */
250
- Module.getPyProxyClass = function (flags: number) {
251
- const FLAG_TYPE_PAIRS: [number, any][] = [
252
- [(1 << 0), PyProxyLengthMethods],
253
- [(1 << 1), PyProxyGetItemMethods],
254
- [(1 << 2), PyProxySetItemMethods],
255
- [(1 << 3), PyProxyContainsMethods],
256
- [(1 << 4), PyProxyIterableMethods],
257
- [(1 << 5), PyProxyIteratorMethods],
258
- [(1 << 6), PyProxyAwaitableMethods],
259
- [(1 << 7), PyProxyBufferMethods],
260
- [(1 << 8), PyProxyCallableMethods],
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) {
268
- if (flags & feature_flag) {
269
- Object.assign(
270
- descriptors,
271
- Object.getOwnPropertyDescriptors(methods.prototype)
272
- );
273
- }
274
- }
275
- // Use base constructor (just throws an error if construction is attempted).
276
- descriptors.constructor = Object.getOwnPropertyDescriptor(
277
- PyProxyClass.prototype,
278
- "constructor"
279
- );
280
- Object.assign(
281
- descriptors,
282
- Object.getOwnPropertyDescriptors({ $$flags: flags })
283
- );
284
- let new_proto = Object.create(PyProxyClass.prototype, descriptors);
285
- function NewPyProxyClass() {}
286
- NewPyProxyClass.prototype = new_proto;
287
- pyproxyClassMap.set(flags, NewPyProxyClass);
288
- return NewPyProxyClass;
289
- };
290
- // Static methods
291
- Module.PyProxy_getPtr = _getPtr;
292
- const pyproxy_cache_destroyed_msg =
293
- "This borrowed attribute proxy was automatically destroyed in the " +
294
- "process of destroying the proxy it was borrowed from. Try using the 'copy' method.";
295
- function pyproxy_decref_cache(cache: PyProxyCache) {
296
- if (!cache) {
297
- return;
298
- }
299
- cache.refcnt--;
300
- if (cache.refcnt === 0) {
301
- let cache_map = Hiwire.pop_value(cache.cacheId);
302
- for (let proxy_id of cache_map.values()) {
303
- const cache_entry = Hiwire.pop_value(proxy_id);
304
- if (!cache.leaked) {
305
- Module.pyproxy_destroy(cache_entry, pyproxy_cache_destroyed_msg);
306
- }
307
- }
308
- }
309
- }
310
- Module.pyproxy_destroy = function (proxy: PyProxy, destroyed_msg: string) {
311
- if (proxy.$$.ptr === 0) {
312
- return;
313
- }
314
- let ptrobj = _getPtr(proxy);
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
- }
326
- // Maybe the destructor will call JavaScript code that will somehow try
327
- // to use this proxy. Mark it deleted before decrementing reference count
328
- // just in case!
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
- }
336
- proxy.$$.destroyed_msg = destroyed_msg;
337
- pyproxy_decref_cache(proxy.$$.cache);
338
- try {
339
- Module._Py_DecRef(ptrobj);
340
- trace_pyproxy_dealloc(proxy);
341
- } catch (e) {
342
- API.fatal_error(e);
343
- }
344
- };
345
- // Now a lot of boilerplate to wrap the abstract Object protocol wrappers
346
- // defined in pyproxy.c in JavaScript functions.
347
- Module.callPyObjectKwargs = function (ptrobj: number, ...jsargs: any) {
348
- // We don't do any checking for kwargs, checks are in PyProxy.callKwargs
349
- // which only is used when the keyword arguments come from the user.
350
- let kwargs = jsargs.pop();
351
- let num_pos_args = jsargs.length;
352
- let kwargs_names = Object.keys(kwargs);
353
- let kwargs_values = Object.values(kwargs);
354
- let num_kwargs = kwargs_names.length;
355
- jsargs.push(...kwargs_values);
356
- let idargs = Hiwire.new_value(jsargs);
357
- let idkwnames = Hiwire.new_value(kwargs_names);
358
- let idresult;
359
- try {
360
- idresult = Module.__pyproxy_apply(
361
- ptrobj,
362
- idargs,
363
- num_pos_args,
364
- idkwnames,
365
- num_kwargs
366
- );
367
- } catch (e) {
368
- API.fatal_error(e);
369
- } finally {
370
- Hiwire.decref(idargs);
371
- Hiwire.decref(idkwnames);
372
- }
373
- if (idresult === 0) {
374
- Module._pythonexc2js();
375
- }
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;
382
- };
383
- Module.callPyObject = function (ptrobj: number, ...jsargs: any) {
384
- return Module.callPyObjectKwargs(ptrobj, ...jsargs, {});
385
- };
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 */
391
- constructor() {
392
- throw new TypeError("PyProxy is not a constructor");
393
- }
394
- get [Symbol.toStringTag]() {
395
- return "PyProxy";
396
- }
397
- /**
398
- * The name of the type of the object.
399
- *
400
- * Usually the value is ``"module.name"`` but for builtins or
401
- * interpreter-defined types it is just ``"name"``. As pseudocode this is:
402
- *
403
- * .. code-block:: python
404
- *
405
- * ty = type(x)
406
- * if ty.__module__ == 'builtins' or ty.__module__ == "__main__":
407
- * return ty.__name__
408
- * else:
409
- * ty.__module__ + "." + ty.__name__
410
- *
411
- */
412
- get type(): string {
413
- let ptrobj = _getPtr(this);
414
- return Hiwire.pop_value(Module.__pyproxy_type(ptrobj));
415
- }
416
- toString(): string {
417
- let ptrobj = _getPtr(this);
418
- let jsref_repr;
419
- try {
420
- jsref_repr = Module.__pyproxy_repr(ptrobj);
421
- } catch (e) {
422
- API.fatal_error(e);
423
- }
424
- if (jsref_repr === 0) {
425
- Module._pythonexc2js();
426
- }
427
- return Hiwire.pop_value(jsref_repr);
428
- }
429
- /**
430
- * Destroy the ``PyProxy``. This will release the memory. Any further attempt
431
- * to use the object will raise an error.
432
- *
433
- * In a browser supporting `FinalizationRegistry
434
- * <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/FinalizationRegistry>`_
435
- * Pyodide will automatically destroy the ``PyProxy`` when it is garbage
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.
438
- *
439
- * @param destroyed_msg The error message to print if use is attempted after
440
- * destroying. Defaults to "Object has already been destroyed".
441
- */
442
- destroy(destroyed_msg?: string) {
443
- Module.pyproxy_destroy(this, destroyed_msg);
444
- }
445
- /**
446
- * Make a new PyProxy pointing to the same Python object.
447
- * Useful if the PyProxy is destroyed somewhere else.
448
- */
449
- copy(): PyProxy {
450
- let ptrobj = _getPtr(this);
451
- return Module.pyproxy_new(ptrobj, this.$$.cache);
452
- }
453
- /**
454
- * Converts the ``PyProxy`` into a JavaScript object as best as possible. By
455
- * default does a deep conversion, if a shallow conversion is desired, you can
456
- * use ``proxy.toJs({depth : 1})``. See :ref:`Explicit Conversion of PyProxy
457
- * <type-translations-pyproxy-to-js>` for more info.
458
- * @param options
459
- * @return The JavaScript object resulting from the conversion.
460
- */
461
- toJs({
462
- depth = -1,
463
- pyproxies = undefined,
464
- create_pyproxies = (!!1),
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 {
501
- let ptrobj = _getPtr(this);
502
- let idresult;
503
- let proxies_id;
504
- let dict_converter_id = 0;
505
- let default_converter_id = 0;
506
- if (!create_pyproxies) {
507
- proxies_id = 0;
508
- } else if (pyproxies) {
509
- proxies_id = Hiwire.new_value(pyproxies);
510
- } else {
511
- proxies_id = Hiwire.new_value([]);
512
- }
513
- if (dict_converter) {
514
- dict_converter_id = Hiwire.new_value(dict_converter);
515
- }
516
- if (default_converter) {
517
- default_converter_id = Hiwire.new_value(default_converter);
518
- }
519
- try {
520
- idresult = Module._python2js_custom(
521
- ptrobj,
522
- depth,
523
- proxies_id,
524
- dict_converter_id,
525
- default_converter_id
526
- );
527
- } catch (e) {
528
- API.fatal_error(e);
529
- } finally {
530
- Hiwire.decref(proxies_id);
531
- Hiwire.decref(dict_converter_id);
532
- Hiwire.decref(default_converter_id);
533
- }
534
- if (idresult === 0) {
535
- Module._pythonexc2js();
536
- }
537
- return Hiwire.pop_value(idresult);
538
- }
539
- /**
540
- * Check whether the :any:`PyProxy.length` getter is available on this PyProxy. A
541
- * Typescript type guard.
542
- */
543
- supportsLength(): this is PyProxyWithLength {
544
- return !!(this.$$flags & (1 << 0));
545
- }
546
- /**
547
- * Check whether the :any:`PyProxy.get` method is available on this PyProxy. A
548
- * Typescript type guard.
549
- */
550
- supportsGet(): this is PyProxyWithGet {
551
- return !!(this.$$flags & (1 << 1));
552
- }
553
- /**
554
- * Check whether the :any:`PyProxy.set` method is available on this PyProxy. A
555
- * Typescript type guard.
556
- */
557
- supportsSet(): this is PyProxyWithSet {
558
- return !!(this.$$flags & (1 << 2));
559
- }
560
- /**
561
- * Check whether the :any:`PyProxy.has` method is available on this PyProxy. A
562
- * Typescript type guard.
563
- */
564
- supportsHas(): this is PyProxyWithHas {
565
- return !!(this.$$flags & (1 << 3));
566
- }
567
- /**
568
- * Check whether the PyProxy is iterable. A Typescript type guard for
569
- * :any:`PyProxy.[iterator]`.
570
- */
571
- isIterable(): this is PyProxyIterable {
572
- return !!(this.$$flags & ((1 << 4) | (1 << 5)));
573
- }
574
- /**
575
- * Check whether the PyProxy is iterable. A Typescript type guard for
576
- * :any:`PyProxy.next`.
577
- */
578
- isIterator(): this is PyProxyIterator {
579
- return !!(this.$$flags & (1 << 5));
580
- }
581
- /**
582
- * Check whether the PyProxy is awaitable. A Typescript type guard, if this
583
- * function returns true Typescript considers the PyProxy to be a ``Promise``.
584
- */
585
- isAwaitable(): this is PyProxyAwaitable {
586
- return !!(this.$$flags & (1 << 6));
587
- }
588
- /**
589
- * Check whether the PyProxy is a buffer. A Typescript type guard for
590
- * :any:`PyProxy.getBuffer`.
591
- */
592
- isBuffer(): this is PyProxyBuffer {
593
- return !!(this.$$flags & (1 << 7));
594
- }
595
- /**
596
- * Check whether the PyProxy is a Callable. A Typescript type guard, if this
597
- * returns true then Typescript considers the Proxy to be callable of
598
- * signature ``(args... : any[]) => PyProxy | number | bigint | string |
599
- * boolean | undefined``.
600
- */
601
- isCallable(): this is PyProxyCallable {
602
- return !!(this.$$flags & (1 << 8));
603
- }
604
- }
605
- export type PyProxyWithLength = PyProxy & PyProxyLengthMethods;
606
- // Controlled by HAS_LENGTH, appears for any object with __len__ or sq_length
607
- // or mp_length methods
608
- export class PyProxyLengthMethods {
609
- /**
610
- * The length of the object.
611
- *
612
- * Present only if the proxied Python object has a ``__len__`` method.
613
- */
614
- get length(): number {
615
- let ptrobj = _getPtr(this);
616
- let length;
617
- try {
618
- length = Module._PyObject_Size(ptrobj);
619
- } catch (e) {
620
- API.fatal_error(e);
621
- }
622
- if (length === -1) {
623
- Module._pythonexc2js();
624
- }
625
- return length;
626
- }
627
- }
628
- export type PyProxyWithGet = PyProxy & PyProxyGetItemMethods;
629
- // Controlled by HAS_GET, appears for any class with __getitem__,
630
- // mp_subscript, or sq_item methods
631
- export class PyProxyGetItemMethods {
632
- /**
633
- * This translates to the Python code ``obj[key]``.
634
- *
635
- * Present only if the proxied Python object has a ``__getitem__`` method.
636
- *
637
- * @param key The key to look up.
638
- * @returns The corresponding value.
639
- */
640
- get(key: any): any {
641
- let ptrobj = _getPtr(this);
642
- let idkey = Hiwire.new_value(key);
643
- let idresult;
644
- try {
645
- idresult = Module.__pyproxy_getitem(ptrobj, idkey);
646
- } catch (e) {
647
- API.fatal_error(e);
648
- } finally {
649
- Hiwire.decref(idkey);
650
- }
651
- if (idresult === 0) {
652
- if (Module._PyErr_Occurred()) {
653
- Module._pythonexc2js();
654
- } else {
655
- return undefined;
656
- }
657
- }
658
- return Hiwire.pop_value(idresult);
659
- }
660
- }
661
- export type PyProxyWithSet = PyProxy & PyProxySetItemMethods;
662
- // Controlled by HAS_SET, appears for any class with __setitem__, __delitem__,
663
- // mp_ass_subscript, or sq_ass_item.
664
- export class PyProxySetItemMethods {
665
- /**
666
- * This translates to the Python code ``obj[key] = value``.
667
- *
668
- * Present only if the proxied Python object has a ``__setitem__`` method.
669
- *
670
- * @param key The key to set.
671
- * @param value The value to set it to.
672
- */
673
- set(key: any, value: any) {
674
- let ptrobj = _getPtr(this);
675
- let idkey = Hiwire.new_value(key);
676
- let idval = Hiwire.new_value(value);
677
- let errcode;
678
- try {
679
- errcode = Module.__pyproxy_setitem(ptrobj, idkey, idval);
680
- } catch (e) {
681
- API.fatal_error(e);
682
- } finally {
683
- Hiwire.decref(idkey);
684
- Hiwire.decref(idval);
685
- }
686
- if (errcode === -1) {
687
- Module._pythonexc2js();
688
- }
689
- }
690
- /**
691
- * This translates to the Python code ``del obj[key]``.
692
- *
693
- * Present only if the proxied Python object has a ``__delitem__`` method.
694
- *
695
- * @param key The key to delete.
696
- */
697
- delete(key: any) {
698
- let ptrobj = _getPtr(this);
699
- let idkey = Hiwire.new_value(key);
700
- let errcode;
701
- try {
702
- errcode = Module.__pyproxy_delitem(ptrobj, idkey);
703
- } catch (e) {
704
- API.fatal_error(e);
705
- } finally {
706
- Hiwire.decref(idkey);
707
- }
708
- if (errcode === -1) {
709
- Module._pythonexc2js();
710
- }
711
- }
712
- }
713
- export type PyProxyWithHas = PyProxy & PyProxyContainsMethods;
714
- // Controlled by HAS_CONTAINS flag, appears for any class with __contains__ or
715
- // sq_contains
716
- export class PyProxyContainsMethods {
717
- /**
718
- * This translates to the Python code ``key in obj``.
719
- *
720
- * Present only if the proxied Python object has a ``__contains__`` method.
721
- *
722
- * @param key The key to check for.
723
- * @returns Is ``key`` present?
724
- */
725
- has(key: any): boolean {
726
- let ptrobj = _getPtr(this);
727
- let idkey = Hiwire.new_value(key);
728
- let result;
729
- try {
730
- result = Module.__pyproxy_contains(ptrobj, idkey);
731
- } catch (e) {
732
- API.fatal_error(e);
733
- } finally {
734
- Hiwire.decref(idkey);
735
- }
736
- if (result === -1) {
737
- Module._pythonexc2js();
738
- }
739
- return result === 1;
740
- }
741
- }
742
- /**
743
- * A helper for [Symbol.iterator].
744
- *
745
- * Because "it is possible for a generator to be garbage collected without
746
- * ever running its finally block", we take extra care to try to ensure that
747
- * we don't leak the iterator. We register it with the finalizationRegistry,
748
- * but if the finally block is executed, we decref the pointer and unregister.
749
- *
750
- * In order to do this, we create the generator with this inner method,
751
- * register the finalizer, and then return it.
752
- *
753
- * Quote from:
754
- * https://hacks.mozilla.org/2015/07/es6-in-depth-generators-continued/
755
- *
756
- * @private
757
- */
758
- function* iter_helper(iterptr: number, token: {}): Generator<any> {
759
- try {
760
- let item;
761
- while ((item = Module.__pyproxy_iter_next(iterptr))) {
762
- yield Hiwire.pop_value(item);
763
- }
764
- } catch (e) {
765
- API.fatal_error(e);
766
- } finally {
767
- Module.finalizationRegistry.unregister(token);
768
- Module._Py_DecRef(iterptr);
769
- }
770
- if (Module._PyErr_Occurred()) {
771
- Module._pythonexc2js();
772
- }
773
- }
774
- export type PyProxyIterable = PyProxy & PyProxyIterableMethods;
775
- // Controlled by IS_ITERABLE, appears for any object with __iter__ or tp_iter,
776
- // unless they are iterators. See: https://docs.python.org/3/c-api/iter.html
777
- // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols
778
- // This avoids allocating a PyProxy wrapper for the temporary iterator.
779
- export class PyProxyIterableMethods {
780
- /**
781
- * This translates to the Python code ``iter(obj)``. Return an iterator
782
- * associated to the proxy. See the documentation for `Symbol.iterator
783
- * <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol/iterator>`_.
784
- *
785
- * Present only if the proxied Python object is iterable (i.e., has an
786
- * ``__iter__`` method).
787
- *
788
- * This will be used implicitly by ``for(let x of proxy){}``.
789
- */
790
- [Symbol.iterator](): Iterator<any, any, any> {
791
- let ptrobj = _getPtr(this);
792
- let token = {};
793
- let iterptr;
794
- try {
795
- iterptr = Module._PyObject_GetIter(ptrobj);
796
- } catch (e) {
797
- API.fatal_error(e);
798
- }
799
- if (iterptr === 0) {
800
- Module._pythonexc2js();
801
- }
802
- let result = iter_helper(iterptr, token);
803
- Module.finalizationRegistry.register(result, [iterptr, undefined], token);
804
- return result;
805
- }
806
- }
807
- export type PyProxyIterator = PyProxy & PyProxyIteratorMethods;
808
- // Controlled by IS_ITERATOR, appears for any object with a __next__ or
809
- // tp_iternext method.
810
- export class PyProxyIteratorMethods {
811
- /** @private */
812
- [Symbol.iterator]() {
813
- return this;
814
- }
815
- /**
816
- * This translates to the Python code ``next(obj)``. Returns the next value of
817
- * the generator. See the documentation for `Generator.prototype.next
818
- * <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Generator/next>`_.
819
- * The argument will be sent to the Python generator.
820
- *
821
- * This will be used implicitly by ``for(let x of proxy){}``.
822
- *
823
- * Present only if the proxied Python object is a generator or iterator (i.e.,
824
- * has a ``send`` or ``__next__`` method).
825
- *
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}``.
832
- */
833
- next(arg: any = undefined): IteratorResult<any, any> {
834
- // Note: arg is optional, if arg is not supplied, it will be undefined
835
- // which gets converted to "Py_None". This is as intended.
836
- let idarg = Hiwire.new_value(arg);
837
- let status;
838
- let done;
839
- let stackTop = Module.stackSave();
840
- let res_ptr = Module.stackAlloc(4);
841
- try {
842
- status = Module.__pyproxyGen_Send(_getPtr(this), idarg, res_ptr);
843
- } catch (e) {
844
- API.fatal_error(e);
845
- } finally {
846
- Hiwire.decref(idarg);
847
- }
848
- let HEAPU32 = Module.HEAPU32;
849
- let idresult = HEAPU32[(res_ptr >> 2) + 0];
850
- Module.stackRestore(stackTop);
851
- if (status === -1) {
852
- Module._pythonexc2js();
853
- }
854
- let value = Hiwire.pop_value(idresult);
855
- done = status === 0;
856
- return { done, value };
857
- }
858
- }
859
- // Another layer of boilerplate. The PyProxyHandlers have some annoying logic
860
- // to deal with straining out the spurious "Function" properties "prototype",
861
- // "arguments", and "length", to deal with correctly satisfying the Proxy
862
- // invariants, and to deal with the mro
863
- function python_hasattr(jsobj: PyProxyClass, jskey: any) {
864
- let ptrobj = _getPtr(jsobj);
865
- let idkey = Hiwire.new_value(jskey);
866
- let result;
867
- try {
868
- result = Module.__pyproxy_hasattr(ptrobj, idkey);
869
- } catch (e) {
870
- API.fatal_error(e);
871
- } finally {
872
- Hiwire.decref(idkey);
873
- }
874
- if (result === -1) {
875
- Module._pythonexc2js();
876
- }
877
- return result !== 0;
878
- }
879
- // Returns a JsRef in order to allow us to differentiate between "not found"
880
- // (in which case we return 0) and "found 'None'" (in which case we return
881
- // Js_undefined).
882
- function python_getattr(jsobj: PyProxyClass, jskey: any) {
883
- let ptrobj = _getPtr(jsobj);
884
- let idkey = Hiwire.new_value(jskey);
885
- let idresult;
886
- let cacheId = jsobj.$$.cache.cacheId;
887
- try {
888
- idresult = Module.__pyproxy_getattr(ptrobj, idkey, cacheId);
889
- } catch (e) {
890
- API.fatal_error(e);
891
- } finally {
892
- Hiwire.decref(idkey);
893
- }
894
- if (idresult === 0) {
895
- if (Module._PyErr_Occurred()) {
896
- Module._pythonexc2js();
897
- }
898
- }
899
- return idresult;
900
- }
901
- function python_setattr(jsobj: PyProxyClass, jskey: any, jsval: any) {
902
- let ptrobj = _getPtr(jsobj);
903
- let idkey = Hiwire.new_value(jskey);
904
- let idval = Hiwire.new_value(jsval);
905
- let errcode;
906
- try {
907
- errcode = Module.__pyproxy_setattr(ptrobj, idkey, idval);
908
- } catch (e) {
909
- API.fatal_error(e);
910
- } finally {
911
- Hiwire.decref(idkey);
912
- Hiwire.decref(idval);
913
- }
914
- if (errcode === -1) {
915
- Module._pythonexc2js();
916
- }
917
- }
918
- function python_delattr(jsobj: PyProxyClass, jskey: any) {
919
- let ptrobj = _getPtr(jsobj);
920
- let idkey = Hiwire.new_value(jskey);
921
- let errcode;
922
- try {
923
- errcode = Module.__pyproxy_delattr(ptrobj, idkey);
924
- } catch (e) {
925
- API.fatal_error(e);
926
- } finally {
927
- Hiwire.decref(idkey);
928
- }
929
- if (errcode === -1) {
930
- Module._pythonexc2js();
931
- }
932
- }
933
- // See explanation of which methods should be defined here and what they do
934
- // here:
935
- // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy
936
- let PyProxyHandlers = {
937
- isExtensible() {
938
- return (!!1);
939
- },
940
- has(jsobj: PyProxyClass, jskey: any) {
941
- // Note: must report "prototype" in proxy when we are callable.
942
- // (We can return the wrong value from "get" handler though.)
943
- let objHasKey = Reflect.has(jsobj, jskey);
944
- if (objHasKey) {
945
- return (!!1);
946
- }
947
- // python_hasattr will crash if given a Symbol.
948
- if (typeof jskey === "symbol") {
949
- return (!!0);
950
- }
951
- if (jskey.startsWith("$")) {
952
- jskey = jskey.slice(1);
953
- }
954
- return python_hasattr(jsobj, jskey);
955
- },
956
- get(jsobj: PyProxyClass, jskey: any) {
957
- // Preference order:
958
- // 1. stuff from JavaScript
959
- // 2. the result of Python getattr
960
- // python_getattr will crash if given a Symbol.
961
- if (jskey in jsobj || typeof jskey === "symbol") {
962
- return Reflect.get(jsobj, jskey);
963
- }
964
- // If keys start with $ remove the $. User can use initial $ to
965
- // unambiguously ask for a key on the Python object.
966
- if (jskey.startsWith("$")) {
967
- jskey = jskey.slice(1);
968
- }
969
- // 2. The result of getattr
970
- let idresult = python_getattr(jsobj, jskey);
971
- if (idresult !== 0) {
972
- return Hiwire.pop_value(idresult);
973
- }
974
- },
975
- set(jsobj: PyProxyClass, jskey: any, jsval: any) {
976
- let descr = Object.getOwnPropertyDescriptor(jsobj, jskey);
977
- if (descr && !descr.writable) {
978
- throw new TypeError(`Cannot set read only field '${jskey}'`);
979
- }
980
- // python_setattr will crash if given a Symbol.
981
- if (typeof jskey === "symbol") {
982
- return Reflect.set(jsobj, jskey, jsval);
983
- }
984
- if (jskey.startsWith("$")) {
985
- jskey = jskey.slice(1);
986
- }
987
- python_setattr(jsobj, jskey, jsval);
988
- return (!!1);
989
- },
990
- deleteProperty(jsobj: PyProxyClass, jskey: any): boolean {
991
- let descr = Object.getOwnPropertyDescriptor(jsobj, jskey);
992
- if (descr && !descr.writable) {
993
- throw new TypeError(`Cannot delete read only field '${jskey}'`);
994
- }
995
- if (typeof jskey === "symbol") {
996
- return Reflect.deleteProperty(jsobj, jskey);
997
- }
998
- if (jskey.startsWith("$")) {
999
- jskey = jskey.slice(1);
1000
- }
1001
- python_delattr(jsobj, jskey);
1002
- // Must return "false" if "jskey" is a nonconfigurable own property.
1003
- // Otherwise JavaScript will throw a TypeError.
1004
- return !descr || !!descr.configurable;
1005
- },
1006
- ownKeys(jsobj: PyProxyClass) {
1007
- let ptrobj = _getPtr(jsobj);
1008
- let idresult;
1009
- try {
1010
- idresult = Module.__pyproxy_ownKeys(ptrobj);
1011
- } catch (e) {
1012
- API.fatal_error(e);
1013
- }
1014
- if (idresult === 0) {
1015
- Module._pythonexc2js();
1016
- }
1017
- let result = Hiwire.pop_value(idresult);
1018
- result.push(...Reflect.ownKeys(jsobj));
1019
- return result;
1020
- },
1021
- apply(jsobj: PyProxyClass & Function, jsthis: any, jsargs: any) {
1022
- return jsobj.apply(jsthis, jsargs);
1023
- },
1024
- };
1025
- export type PyProxyAwaitable = PyProxy & Promise<any>;
1026
- /**
1027
- * The Promise / JavaScript awaitable API.
1028
- * @private
1029
- */
1030
- export class PyProxyAwaitableMethods {
1031
- $$: any;
1032
- /**
1033
- * This wraps __pyproxy_ensure_future and makes a function that converts a
1034
- * Python awaitable to a promise, scheduling the awaitable on the Python
1035
- * event loop if necessary.
1036
- * @private
1037
- */
1038
- _ensure_future(): Promise<any> {
1039
- if (this.$$.promise) {
1040
- return this.$$.promise;
1041
- }
1042
- let ptrobj = _getPtr(this);
1043
- let resolveHandle;
1044
- let rejectHandle;
1045
- let promise = new Promise((resolve, reject) => {
1046
- resolveHandle = resolve;
1047
- rejectHandle = reject;
1048
- });
1049
- let resolve_handle_id = Hiwire.new_value(resolveHandle);
1050
- let reject_handle_id = Hiwire.new_value(rejectHandle);
1051
- let errcode;
1052
- try {
1053
- errcode = Module.__pyproxy_ensure_future(
1054
- ptrobj,
1055
- resolve_handle_id,
1056
- reject_handle_id
1057
- );
1058
- } catch (e) {
1059
- API.fatal_error(e);
1060
- } finally {
1061
- Hiwire.decref(reject_handle_id);
1062
- Hiwire.decref(resolve_handle_id);
1063
- }
1064
- if (errcode === -1) {
1065
- Module._pythonexc2js();
1066
- }
1067
- this.$$.promise = promise;
1068
- // @ts-ignore
1069
- this.destroy();
1070
- return promise;
1071
- }
1072
- /**
1073
- * Runs ``asyncio.ensure_future(awaitable)``, executes
1074
- * ``onFulfilled(result)`` when the ``Future`` resolves successfully,
1075
- * executes ``onRejected(error)`` when the ``Future`` fails. Will be used
1076
- * implicitly by ``await obj``.
1077
- *
1078
- * See the documentation for
1079
- * `Promise.then
1080
- * <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/then>`_
1081
- *
1082
- * Present only if the proxied Python object is `awaitable
1083
- * <https://docs.python.org/3/library/asyncio-task.html?highlight=awaitable#awaitables>`_.
1084
- *
1085
- * @param onFulfilled A handler called with the result as an
1086
- * argument if the awaitable succeeds.
1087
- * @param onRejected A handler called with the error as an
1088
- * argument if the awaitable fails.
1089
- * @returns The resulting Promise.
1090
- */
1091
- then(
1092
- onFulfilled: (value: any) => any,
1093
- onRejected: (reason: any) => any
1094
- ): Promise<any> {
1095
- let promise = this._ensure_future();
1096
- return promise.then(onFulfilled, onRejected);
1097
- }
1098
- /**
1099
- * Runs ``asyncio.ensure_future(awaitable)`` and executes
1100
- * ``onRejected(error)`` if the future fails.
1101
- *
1102
- * See the documentation for
1103
- * `Promise.catch
1104
- * <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/catch>`_.
1105
- *
1106
- * Present only if the proxied Python object is `awaitable
1107
- * <https://docs.python.org/3/library/asyncio-task.html?highlight=awaitable#awaitables>`_.
1108
- *
1109
- * @param onRejected A handler called with the error as an
1110
- * argument if the awaitable fails.
1111
- * @returns The resulting Promise.
1112
- */
1113
- catch(onRejected: (reason: any) => any) {
1114
- let promise = this._ensure_future();
1115
- return promise.catch(onRejected);
1116
- }
1117
- /**
1118
- * Runs ``asyncio.ensure_future(awaitable)`` and executes
1119
- * ``onFinally(error)`` when the future resolves.
1120
- *
1121
- * See the documentation for
1122
- * `Promise.finally
1123
- * <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/finally>`_.
1124
- *
1125
- * Present only if the proxied Python object is `awaitable
1126
- * <https://docs.python.org/3/library/asyncio-task.html?highlight=awaitable#awaitables>`_.
1127
- *
1128
- *
1129
- * @param onFinally A handler that is called with zero arguments
1130
- * when the awaitable resolves.
1131
- * @returns A Promise that resolves or rejects with the same
1132
- * result as the original Promise, but only after executing the
1133
- * ``onFinally`` handler.
1134
- */
1135
- finally(onFinally: () => void) {
1136
- let promise = this._ensure_future();
1137
- return promise.finally(onFinally);
1138
- }
1139
- }
1140
- export type PyProxyCallable = PyProxy &
1141
- PyProxyCallableMethods &
1142
- ((...args: any[]) => any);
1143
- export class PyProxyCallableMethods {
1144
- apply(jsthis: PyProxyClass, jsargs: any) {
1145
- return Module.callPyObject(_getPtr(this), ...jsargs);
1146
- }
1147
- call(jsthis: PyProxyClass, ...jsargs: any) {
1148
- return Module.callPyObject(_getPtr(this), ...jsargs);
1149
- }
1150
- /**
1151
- * Call the function with key word arguments.
1152
- * The last argument must be an object with the keyword arguments.
1153
- */
1154
- callKwargs(...jsargs: any) {
1155
- if (jsargs.length === 0) {
1156
- throw new TypeError(
1157
- "callKwargs requires at least one argument (the key word argument object)"
1158
- );
1159
- }
1160
- let kwargs = jsargs[jsargs.length - 1];
1161
- if (
1162
- kwargs.constructor !== undefined &&
1163
- kwargs.constructor.name !== "Object"
1164
- ) {
1165
- throw new TypeError("kwargs argument is not an object");
1166
- }
1167
- return Module.callPyObjectKwargs(_getPtr(this), ...jsargs);
1168
- }
1169
- }
1170
- // @ts-ignore
1171
- PyProxyCallableMethods.prototype.prototype = Function.prototype;
1172
- // @ts-ignore
1173
- let type_to_array_map: Map<string, any> = new Map([
1174
- ["i8", Int8Array],
1175
- ["u8", Uint8Array],
1176
- ["u8clamped", Uint8ClampedArray],
1177
- ["i16", Int16Array],
1178
- ["u16", Uint16Array],
1179
- ["i32", Int32Array],
1180
- ["u32", Uint32Array],
1181
- ["i32", Int32Array],
1182
- ["u32", Uint32Array],
1183
- // if these aren't available, will be globalThis.BigInt64Array will be
1184
- // undefined rather than raising a ReferenceError.
1185
- ["i64", globalThis.BigInt64Array],
1186
- ["u64", globalThis.BigUint64Array],
1187
- ["f32", Float32Array],
1188
- ["f64", Float64Array],
1189
- ["dataview", DataView],
1190
- ]);
1191
- export type PyProxyBuffer = PyProxy & PyProxyBufferMethods;
1192
- export class PyProxyBufferMethods {
1193
- /**
1194
- * Get a view of the buffer data which is usable from JavaScript. No copy is
1195
- * ever performed.
1196
- *
1197
- * Present only if the proxied Python object supports the `Python Buffer
1198
- * Protocol <https://docs.python.org/3/c-api/buffer.html>`_.
1199
- *
1200
- * We do not support suboffsets, if the buffer requires suboffsets we will
1201
- * throw an error. JavaScript nd array libraries can't handle suboffsets
1202
- * anyways. In this case, you should use the :any:`toJs` api or copy the
1203
- * buffer to one that doesn't use suboffets (using e.g.,
1204
- * `numpy.ascontiguousarray
1205
- * <https://numpy.org/doc/stable/reference/generated/numpy.ascontiguousarray.html>`_).
1206
- *
1207
- * If the buffer stores big endian data or half floats, this function will
1208
- * fail without an explicit type argument. For big endian data you can use
1209
- * ``toJs``. `DataViews
1210
- * <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DataView>`_
1211
- * have support for big endian data, so you might want to pass
1212
- * ``'dataview'`` as the type argument in that case.
1213
- *
1214
- * @param type The type of the :any:`PyBuffer.data <pyodide.PyBuffer.data>` field in the
1215
- * output. Should be one of: ``"i8"``, ``"u8"``, ``"u8clamped"``, ``"i16"``,
1216
- * ``"u16"``, ``"i32"``, ``"u32"``, ``"i32"``, ``"u32"``, ``"i64"``,
1217
- * ``"u64"``, ``"f32"``, ``"f64``, or ``"dataview"``. This argument is
1218
- * optional, if absent ``getBuffer`` will try to determine the appropriate
1219
- * output type based on the buffer `format string
1220
- * <https://docs.python.org/3/library/struct.html#format-strings>`_.
1221
- * @returns :any:`PyBuffer <pyodide.PyBuffer>`
1222
- */
1223
- getBuffer(type?: string): PyBuffer {
1224
- let ArrayType = undefined;
1225
- if (type) {
1226
- ArrayType = type_to_array_map.get(type);
1227
- if (ArrayType === undefined) {
1228
- throw new Error(`Unknown type ${type}`);
1229
- }
1230
- }
1231
- let HEAPU32 = Module.HEAPU32;
1232
- let orig_stack_ptr = Module.stackSave();
1233
- let buffer_struct_ptr = Module.stackAlloc(
1234
- HEAPU32[(Module._buffer_struct_size >> 2) + 0]
1235
- );
1236
- let this_ptr = _getPtr(this);
1237
- let errcode;
1238
- try {
1239
- errcode = Module.__pyproxy_get_buffer(buffer_struct_ptr, this_ptr);
1240
- } catch (e) {
1241
- API.fatal_error(e);
1242
- }
1243
- if (errcode === -1) {
1244
- Module._pythonexc2js();
1245
- }
1246
- // This has to match the fields in buffer_struct
1247
- let startByteOffset = HEAPU32[(buffer_struct_ptr >> 2) + 0];
1248
- let minByteOffset = HEAPU32[(buffer_struct_ptr >> 2) + 1];
1249
- let maxByteOffset = HEAPU32[(buffer_struct_ptr >> 2) + 2];
1250
- let readonly = !!HEAPU32[(buffer_struct_ptr >> 2) + 3];
1251
- let format_ptr = HEAPU32[(buffer_struct_ptr >> 2) + 4];
1252
- let itemsize = HEAPU32[(buffer_struct_ptr >> 2) + 5];
1253
- let shape = Hiwire.pop_value(HEAPU32[(buffer_struct_ptr >> 2) + 6]);
1254
- let strides = Hiwire.pop_value(HEAPU32[(buffer_struct_ptr >> 2) + 7]);
1255
- let view_ptr = HEAPU32[(buffer_struct_ptr >> 2) + 8];
1256
- let c_contiguous = !!HEAPU32[(buffer_struct_ptr >> 2) + 9];
1257
- let f_contiguous = !!HEAPU32[(buffer_struct_ptr >> 2) + 10];
1258
- let format = Module.UTF8ToString(format_ptr);
1259
- Module.stackRestore(orig_stack_ptr);
1260
- let success = (!!0);
1261
- try {
1262
- let bigEndian = (!!0);
1263
- if (ArrayType === undefined) {
1264
- [ArrayType, bigEndian] = Module.processBufferFormatString(
1265
- format,
1266
- " In this case, you can pass an explicit type argument."
1267
- );
1268
- }
1269
- let alignment = parseInt(ArrayType.name.replace(/[^0-9]/g, "")) / 8 || 1;
1270
- if (bigEndian && alignment > 1) {
1271
- throw new Error(
1272
- "Javascript has no native support for big endian buffers. " +
1273
- "In this case, you can pass an explicit type argument. " +
1274
- "For instance, `getBuffer('dataview')` will return a `DataView`" +
1275
- "which has native support for reading big endian data. " +
1276
- "Alternatively, toJs will automatically convert the buffer " +
1277
- "to little endian."
1278
- );
1279
- }
1280
- let numBytes = maxByteOffset - minByteOffset;
1281
- if (
1282
- numBytes !== 0 &&
1283
- (startByteOffset % alignment !== 0 ||
1284
- minByteOffset % alignment !== 0 ||
1285
- maxByteOffset % alignment !== 0)
1286
- ) {
1287
- throw new Error(
1288
- `Buffer does not have valid alignment for a ${ArrayType.name}`
1289
- );
1290
- }
1291
- let numEntries = numBytes / alignment;
1292
- let offset = (startByteOffset - minByteOffset) / alignment;
1293
- let data;
1294
- if (numBytes === 0) {
1295
- data = new ArrayType();
1296
- } else {
1297
- data = new ArrayType(HEAPU32.buffer, minByteOffset, numEntries);
1298
- }
1299
- for (let i of strides.keys()) {
1300
- strides[i] /= alignment;
1301
- }
1302
- success = (!!1);
1303
- let result = Object.create(
1304
- PyBuffer.prototype,
1305
- Object.getOwnPropertyDescriptors({
1306
- offset,
1307
- readonly,
1308
- format,
1309
- itemsize,
1310
- ndim: shape.length,
1311
- nbytes: numBytes,
1312
- shape,
1313
- strides,
1314
- data,
1315
- c_contiguous,
1316
- f_contiguous,
1317
- _view_ptr: view_ptr,
1318
- _released: (!!0),
1319
- })
1320
- );
1321
- // Module.bufferFinalizationRegistry.register(result, view_ptr, result);
1322
- return result;
1323
- } finally {
1324
- if (!success) {
1325
- try {
1326
- Module._PyBuffer_Release(view_ptr);
1327
- Module._PyMem_Free(view_ptr);
1328
- } catch (e) {
1329
- API.fatal_error(e);
1330
- }
1331
- }
1332
- }
1333
- }
1334
- }
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;
1346
- /**
1347
- * A class to allow access to a Python data buffers from JavaScript. These are
1348
- * produced by :any:`PyProxy.getBuffer` and cannot be constructed directly.
1349
- * When you are done, release it with the :any:`release <PyBuffer.release>`
1350
- * method. See
1351
- * `Python buffer protocol documentation
1352
- * <https://docs.python.org/3/c-api/buffer.html>`_ for more information.
1353
- *
1354
- * To find the element ``x[a_1, ..., a_n]``, you could use the following code:
1355
- *
1356
- * .. code-block:: js
1357
- *
1358
- * function multiIndexToIndex(pybuff, multiIndex){
1359
- * if(multindex.length !==pybuff.ndim){
1360
- * throw new Error("Wrong length index");
1361
- * }
1362
- * let idx = pybuff.offset;
1363
- * for(let i = 0; i < pybuff.ndim; i++){
1364
- * if(multiIndex[i] < 0){
1365
- * multiIndex[i] = pybuff.shape[i] - multiIndex[i];
1366
- * }
1367
- * if(multiIndex[i] < 0 || multiIndex[i] >= pybuff.shape[i]){
1368
- * throw new Error("Index out of range");
1369
- * }
1370
- * idx += multiIndex[i] * pybuff.stride[i];
1371
- * }
1372
- * return idx;
1373
- * }
1374
- * console.log("entry is", pybuff.data[multiIndexToIndex(pybuff, [2, 0, -1])]);
1375
- *
1376
- * .. admonition:: Contiguity
1377
- * :class: warning
1378
- *
1379
- * If the buffer is not contiguous, the ``data`` TypedArray will contain
1380
- * data that is not part of the buffer. Modifying this data may lead to
1381
- * undefined behavior.
1382
- *
1383
- * .. admonition:: Readonly buffers
1384
- * :class: warning
1385
- *
1386
- * If ``buffer.readonly`` is ``true``, you should not modify the buffer.
1387
- * Modifying a readonly buffer may lead to undefined behavior.
1388
- *
1389
- * .. admonition:: Converting between TypedArray types
1390
- * :class: warning
1391
- *
1392
- * The following naive code to change the type of a typed array does not
1393
- * work:
1394
- *
1395
- * .. code-block:: js
1396
- *
1397
- * // Incorrectly convert a TypedArray.
1398
- * // Produces a Uint16Array that points to the entire WASM memory!
1399
- * let myarray = new Uint16Array(buffer.data.buffer);
1400
- *
1401
- * Instead, if you want to convert the output TypedArray, you need to say:
1402
- *
1403
- * .. code-block:: js
1404
- *
1405
- * // Correctly convert a TypedArray.
1406
- * let myarray = new Uint16Array(
1407
- * buffer.data.buffer,
1408
- * buffer.data.byteOffset,
1409
- * buffer.data.byteLength
1410
- * );
1411
- */
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
- */
1486
- constructor() {
1487
- throw new TypeError("PyBuffer is not a constructor");
1488
- }
1489
- /**
1490
- * Release the buffer. This allows the memory to be reclaimed.
1491
- */
1492
- release() {
1493
- if (this._released) {
1494
- return;
1495
- }
1496
- // Module.bufferFinalizationRegistry.unregister(this);
1497
- try {
1498
- Module._PyBuffer_Release(this._view_ptr);
1499
- Module._PyMem_Free(this._view_ptr);
1500
- } catch (e) {
1501
- API.fatal_error(e);
1502
- }
1503
- this._released = (!!1);
1504
- // @ts-ignore
1505
- this.data = null;
1506
- }
1507
- }