pyodide 0.29.4 → 314.0.0-alpha.2
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/console-v2.html +133 -16
- package/ffi.d.ts +33 -18
- package/package.json +5 -6
- package/pyodide-lock.json +1 -1
- package/pyodide.asm.mjs +2 -0
- package/pyodide.asm.wasm +0 -0
- package/pyodide.d.ts +488 -32
- package/pyodide.js +3 -3
- package/pyodide.js.map +4 -4
- package/pyodide.mjs +3 -3
- package/pyodide.mjs.map +4 -4
- package/python_stdlib.zip +0 -0
- package/pyodide.asm.js +0 -15
package/console-v2.html
CHANGED
|
@@ -188,13 +188,29 @@ of the stable console.
|
|
|
188
188
|
const history = [];
|
|
189
189
|
let historyIndex = null; // null means not navigating history
|
|
190
190
|
|
|
191
|
+
// Load history from localStorage
|
|
192
|
+
try {
|
|
193
|
+
const savedHistory = localStorage.getItem("0_commands");
|
|
194
|
+
if (savedHistory) {
|
|
195
|
+
const parsed = JSON.parse(savedHistory);
|
|
196
|
+
if (Array.isArray(parsed)) {
|
|
197
|
+
history.push(...parsed);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
} catch (e) {
|
|
201
|
+
console.error("Failed to load history from localStorage:", e);
|
|
202
|
+
}
|
|
203
|
+
|
|
191
204
|
term.write(prompt);
|
|
192
205
|
|
|
193
206
|
function addToHistory(command) {
|
|
194
207
|
const trimmed = command.trimEnd();
|
|
195
208
|
if (!trimmed) return;
|
|
196
209
|
const last = history[history.length - 1];
|
|
197
|
-
if (last !== trimmed)
|
|
210
|
+
if (last !== trimmed) {
|
|
211
|
+
history.push(trimmed);
|
|
212
|
+
localStorage.setItem("0_commands", JSON.stringify(history));
|
|
213
|
+
}
|
|
198
214
|
}
|
|
199
215
|
|
|
200
216
|
function refreshLine() {
|
|
@@ -217,6 +233,112 @@ of the stable console.
|
|
|
217
233
|
refreshLine();
|
|
218
234
|
}
|
|
219
235
|
|
|
236
|
+
function insertAtCursor(text) {
|
|
237
|
+
const before = buffer.slice(0, cursorIndex);
|
|
238
|
+
const after = buffer.slice(cursorIndex);
|
|
239
|
+
setBuffer(before + text + after, cursorIndex + text.length);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
function clearBuffer() {
|
|
243
|
+
buffer = "";
|
|
244
|
+
cursorIndex = 0;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
function longestCommonPrefix(strings) {
|
|
248
|
+
if (strings.length === 0) return "";
|
|
249
|
+
return strings.reduce((a, b) => {
|
|
250
|
+
let i = 0;
|
|
251
|
+
while (i < a.length && i < b.length && a[i] === b[i]) i++;
|
|
252
|
+
return a.slice(0, i);
|
|
253
|
+
});
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
async function handleTabCompletion() {
|
|
257
|
+
const sourceToComplete = buffer.slice(0, cursorIndex);
|
|
258
|
+
if (!sourceToComplete.trim()) {
|
|
259
|
+
return;
|
|
260
|
+
}
|
|
261
|
+
if (/[([{]\s*$/.test(sourceToComplete)) {
|
|
262
|
+
return;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
const completionResult = pyconsole.complete(sourceToComplete);
|
|
266
|
+
const completions = completionResult[0].toJs();
|
|
267
|
+
const start = completionResult[1];
|
|
268
|
+
completionResult.destroy();
|
|
269
|
+
|
|
270
|
+
const currentWord = sourceToComplete.slice(start);
|
|
271
|
+
if (!currentWord.trim() || /^\d+$/.test(currentWord.trim())) {
|
|
272
|
+
return;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
if (completions.length === 1) {
|
|
276
|
+
const newBuf =
|
|
277
|
+
buffer.slice(0, start) +
|
|
278
|
+
completions[0] +
|
|
279
|
+
buffer.slice(cursorIndex);
|
|
280
|
+
setBuffer(newBuf, start + completions[0].length);
|
|
281
|
+
} else if (completions.length > 1) {
|
|
282
|
+
const prefix = longestCommonPrefix(completions);
|
|
283
|
+
if (prefix.length > currentWord.length) {
|
|
284
|
+
const newBuf =
|
|
285
|
+
buffer.slice(0, start) +
|
|
286
|
+
prefix +
|
|
287
|
+
buffer.slice(cursorIndex);
|
|
288
|
+
setBuffer(newBuf, start + prefix.length);
|
|
289
|
+
} else {
|
|
290
|
+
term.write("\r\n");
|
|
291
|
+
const displayCompletions = completions.slice(0, 200);
|
|
292
|
+
term.writeln(displayCompletions.join(" "));
|
|
293
|
+
if (completions.length > 200) {
|
|
294
|
+
term.writeln(`... and ${completions.length - 200} more`);
|
|
295
|
+
}
|
|
296
|
+
refreshLine();
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
async function handlePaste(data) {
|
|
302
|
+
const normalized = data.replace(/\r\n?/g, "\n");
|
|
303
|
+
if (normalized.includes("\n")) {
|
|
304
|
+
const hasTrailingNewline = normalized.endsWith("\n");
|
|
305
|
+
const lines = normalized.split("\n");
|
|
306
|
+
if (hasTrailingNewline) {
|
|
307
|
+
lines.pop();
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
const cleanedLines = lines.map((line) =>
|
|
311
|
+
line.replace(/^\s*(>>>|\.\.\.)\s?/, "")
|
|
312
|
+
);
|
|
313
|
+
|
|
314
|
+
const executableLines = hasTrailingNewline
|
|
315
|
+
? cleanedLines
|
|
316
|
+
: cleanedLines.slice(0, -1);
|
|
317
|
+
|
|
318
|
+
for (const line of executableLines) {
|
|
319
|
+
insertAtCursor(line);
|
|
320
|
+
term.write("\r\n");
|
|
321
|
+
await execLine(buffer);
|
|
322
|
+
clearBuffer();
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
if (!hasTrailingNewline) {
|
|
326
|
+
const trailingFragment =
|
|
327
|
+
cleanedLines.length > 0
|
|
328
|
+
? cleanedLines[cleanedLines.length - 1]
|
|
329
|
+
: "";
|
|
330
|
+
if (trailingFragment) {
|
|
331
|
+
insertAtCursor(trailingFragment);
|
|
332
|
+
}
|
|
333
|
+
} else {
|
|
334
|
+
term.write(prompt);
|
|
335
|
+
}
|
|
336
|
+
} else {
|
|
337
|
+
// Single line paste
|
|
338
|
+
insertAtCursor(data);
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
|
|
220
342
|
async function execLine(line) {
|
|
221
343
|
// Normalize non-breaking spaces to regular spaces
|
|
222
344
|
line = line.replace(/\u00a0/g, " ");
|
|
@@ -278,14 +400,12 @@ of the stable console.
|
|
|
278
400
|
case "\r": // Enter
|
|
279
401
|
term.write("\r\n");
|
|
280
402
|
await execLine(buffer);
|
|
281
|
-
|
|
282
|
-
cursorIndex = 0;
|
|
403
|
+
clearBuffer();
|
|
283
404
|
term.write(prompt);
|
|
284
405
|
break;
|
|
285
406
|
case "\u0003": // Ctrl-C
|
|
286
407
|
pyconsole.buffer.clear();
|
|
287
|
-
|
|
288
|
-
cursorIndex = 0;
|
|
408
|
+
clearBuffer();
|
|
289
409
|
term.write("^C\r\nKeyboardInterrupt\r\n" + ps1);
|
|
290
410
|
prompt = ps1;
|
|
291
411
|
historyIndex = null;
|
|
@@ -293,11 +413,7 @@ of the stable console.
|
|
|
293
413
|
case "\u0016": // Ctrl-V
|
|
294
414
|
// paste from clipboard
|
|
295
415
|
const clipboard = await navigator.clipboard.readText();
|
|
296
|
-
|
|
297
|
-
buffer.slice(0, cursorIndex) +
|
|
298
|
-
clipboard +
|
|
299
|
-
buffer.slice(cursorIndex);
|
|
300
|
-
setBuffer(newBuf, newBuf.length);
|
|
416
|
+
await handlePaste(clipboard);
|
|
301
417
|
break;
|
|
302
418
|
case "\u007F": // Backspace
|
|
303
419
|
if (cursorIndex > 0) {
|
|
@@ -341,16 +457,17 @@ of the stable console.
|
|
|
341
457
|
refreshLine();
|
|
342
458
|
}
|
|
343
459
|
break;
|
|
460
|
+
case "\x1B[Z": // Shift+Tab - ignore to prevent clearing input
|
|
461
|
+
break;
|
|
462
|
+
case "\t":
|
|
463
|
+
await handleTabCompletion();
|
|
464
|
+
break;
|
|
344
465
|
default:
|
|
345
466
|
if (data) {
|
|
346
467
|
// Normalize non-breaking spaces to regular spaces
|
|
347
468
|
data = data.replace(/\u00a0/g, " ");
|
|
348
|
-
//
|
|
349
|
-
|
|
350
|
-
const after = buffer.slice(cursorIndex);
|
|
351
|
-
const newBuf = before + data + after;
|
|
352
|
-
const newCursor = cursorIndex + data.length;
|
|
353
|
-
setBuffer(newBuf, newCursor);
|
|
469
|
+
// Handle multiline paste
|
|
470
|
+
await handlePaste(data);
|
|
354
471
|
}
|
|
355
472
|
}
|
|
356
473
|
});
|
package/ffi.d.ts
CHANGED
|
@@ -7,11 +7,17 @@ export type TypedArray = Int8Array | Uint8Array | Int16Array | Uint16Array | Int
|
|
|
7
7
|
interface PyProxy {
|
|
8
8
|
[x: string]: any;
|
|
9
9
|
}
|
|
10
|
+
declare const dispose: symbol;
|
|
10
11
|
/**
|
|
11
12
|
* A :js:class:`~pyodide.ffi.PyProxy` is an object that allows idiomatic use of a Python object from
|
|
12
13
|
* JavaScript. See :ref:`type-translations-pyproxy`.
|
|
13
14
|
*/
|
|
14
15
|
declare class PyProxy {
|
|
16
|
+
/**
|
|
17
|
+
* JavaScript resource management
|
|
18
|
+
* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Resource_management#the_using_and_await_using_declarations
|
|
19
|
+
*/
|
|
20
|
+
[Symbol.dispose]: () => void;
|
|
15
21
|
/** @private */
|
|
16
22
|
$$flags: number;
|
|
17
23
|
/** @private */
|
|
@@ -126,7 +132,7 @@ declare class PyProxy {
|
|
|
126
132
|
*/
|
|
127
133
|
declare class PyProxyWithLength extends PyProxy {
|
|
128
134
|
/** @private */
|
|
129
|
-
static [Symbol.hasInstance](obj: any): obj is
|
|
135
|
+
static [Symbol.hasInstance](obj: any): obj is PyProxyWithLength;
|
|
130
136
|
}
|
|
131
137
|
interface PyProxyWithLength extends PyLengthMethods {
|
|
132
138
|
}
|
|
@@ -142,7 +148,7 @@ declare class PyLengthMethods {
|
|
|
142
148
|
*/
|
|
143
149
|
declare class PyProxyWithGet extends PyProxy {
|
|
144
150
|
/** @private */
|
|
145
|
-
static [Symbol.hasInstance](obj: any): obj is
|
|
151
|
+
static [Symbol.hasInstance](obj: any): obj is PyProxyWithGet;
|
|
146
152
|
}
|
|
147
153
|
interface PyProxyWithGet extends PyGetItemMethods {
|
|
148
154
|
}
|
|
@@ -176,7 +182,7 @@ declare class PyGetItemMethods {
|
|
|
176
182
|
*/
|
|
177
183
|
declare class PyProxyWithSet extends PyProxy {
|
|
178
184
|
/** @private */
|
|
179
|
-
static [Symbol.hasInstance](obj: any): obj is
|
|
185
|
+
static [Symbol.hasInstance](obj: any): obj is PyProxyWithSet;
|
|
180
186
|
}
|
|
181
187
|
interface PyProxyWithSet extends PySetItemMethods {
|
|
182
188
|
}
|
|
@@ -201,7 +207,7 @@ declare class PySetItemMethods {
|
|
|
201
207
|
*/
|
|
202
208
|
declare class PyProxyWithHas extends PyProxy {
|
|
203
209
|
/** @private */
|
|
204
|
-
static [Symbol.hasInstance](obj: any): obj is
|
|
210
|
+
static [Symbol.hasInstance](obj: any): obj is PyProxyWithHas;
|
|
205
211
|
}
|
|
206
212
|
interface PyProxyWithHas extends PyContainsMethods {
|
|
207
213
|
}
|
|
@@ -220,7 +226,7 @@ declare class PyContainsMethods {
|
|
|
220
226
|
*/
|
|
221
227
|
declare class PyIterable extends PyProxy {
|
|
222
228
|
/** @private */
|
|
223
|
-
static [Symbol.hasInstance](obj: any): obj is
|
|
229
|
+
static [Symbol.hasInstance](obj: any): obj is PyIterable;
|
|
224
230
|
}
|
|
225
231
|
interface PyIterable extends PyIterableMethods {
|
|
226
232
|
}
|
|
@@ -240,7 +246,7 @@ declare class PyIterableMethods {
|
|
|
240
246
|
*/
|
|
241
247
|
declare class PyAsyncIterable extends PyProxy {
|
|
242
248
|
/** @private */
|
|
243
|
-
static [Symbol.hasInstance](obj: any): obj is
|
|
249
|
+
static [Symbol.hasInstance](obj: any): obj is PyAsyncIterable;
|
|
244
250
|
}
|
|
245
251
|
interface PyAsyncIterable extends PyAsyncIterableMethods {
|
|
246
252
|
}
|
|
@@ -259,7 +265,7 @@ declare class PyAsyncIterableMethods {
|
|
|
259
265
|
*/
|
|
260
266
|
declare class PyIterator extends PyProxy {
|
|
261
267
|
/** @private */
|
|
262
|
-
static [Symbol.hasInstance](obj: any): obj is
|
|
268
|
+
static [Symbol.hasInstance](obj: any): obj is PyIterator;
|
|
263
269
|
}
|
|
264
270
|
interface PyIterator extends PyIteratorMethods {
|
|
265
271
|
}
|
|
@@ -288,7 +294,7 @@ declare class PyIteratorMethods {
|
|
|
288
294
|
*/
|
|
289
295
|
declare class PyGenerator extends PyProxy {
|
|
290
296
|
/** @private */
|
|
291
|
-
static [Symbol.hasInstance](obj: any): obj is
|
|
297
|
+
static [Symbol.hasInstance](obj: any): obj is PyGenerator;
|
|
292
298
|
}
|
|
293
299
|
interface PyGenerator extends PyGeneratorMethods {
|
|
294
300
|
}
|
|
@@ -331,7 +337,7 @@ declare class PyGeneratorMethods {
|
|
|
331
337
|
*/
|
|
332
338
|
declare class PyAsyncIterator extends PyProxy {
|
|
333
339
|
/** @private */
|
|
334
|
-
static [Symbol.hasInstance](obj: any): obj is
|
|
340
|
+
static [Symbol.hasInstance](obj: any): obj is PyAsyncIterator;
|
|
335
341
|
}
|
|
336
342
|
interface PyAsyncIterator extends PyAsyncIteratorMethods {
|
|
337
343
|
}
|
|
@@ -361,7 +367,7 @@ declare class PyAsyncIteratorMethods {
|
|
|
361
367
|
*/
|
|
362
368
|
declare class PyAsyncGenerator extends PyProxy {
|
|
363
369
|
/** @private */
|
|
364
|
-
static [Symbol.hasInstance](obj: any): obj is
|
|
370
|
+
static [Symbol.hasInstance](obj: any): obj is PyAsyncGenerator;
|
|
365
371
|
}
|
|
366
372
|
interface PyAsyncGenerator extends PyAsyncGeneratorMethods {
|
|
367
373
|
}
|
|
@@ -403,7 +409,7 @@ declare class PyAsyncGeneratorMethods {
|
|
|
403
409
|
*/
|
|
404
410
|
declare class PySequence extends PyProxy {
|
|
405
411
|
/** @private */
|
|
406
|
-
static [Symbol.hasInstance](obj: any): obj is
|
|
412
|
+
static [Symbol.hasInstance](obj: any): obj is PySequence;
|
|
407
413
|
}
|
|
408
414
|
interface PySequence extends PySequenceMethods {
|
|
409
415
|
}
|
|
@@ -603,7 +609,7 @@ declare class PySequenceMethods {
|
|
|
603
609
|
*/
|
|
604
610
|
declare class PyMutableSequence extends PyProxy {
|
|
605
611
|
/** @private */
|
|
606
|
-
static [Symbol.hasInstance](obj: any): obj is
|
|
612
|
+
static [Symbol.hasInstance](obj: any): obj is PyMutableSequence;
|
|
607
613
|
}
|
|
608
614
|
interface PyMutableSequence extends PyMutableSequenceMethods {
|
|
609
615
|
}
|
|
@@ -690,7 +696,7 @@ declare class PyMutableSequenceMethods {
|
|
|
690
696
|
*/
|
|
691
697
|
declare class PyAwaitable extends PyProxy {
|
|
692
698
|
/** @private */
|
|
693
|
-
static [Symbol.hasInstance](obj: any): obj is
|
|
699
|
+
static [Symbol.hasInstance](obj: any): obj is PyAwaitable;
|
|
694
700
|
}
|
|
695
701
|
interface PyAwaitable extends Promise<any> {
|
|
696
702
|
}
|
|
@@ -892,6 +898,11 @@ declare class PyBufferMethods {
|
|
|
892
898
|
* data, so you might want to pass ``'dataview'`` as the type argument in that
|
|
893
899
|
* case.
|
|
894
900
|
*
|
|
901
|
+
* When you are done with the buffer view, you have to call
|
|
902
|
+
* :js:func:`~PyBufferView.release`. Alternatively, if you declare the buffer
|
|
903
|
+
* with `using pybuf = proxy.getBuffer()`, JavaScript will automatically
|
|
904
|
+
* release the buffer at the end of the current scope.
|
|
905
|
+
*
|
|
895
906
|
* @param type The type of the :js:attr:`~pyodide.ffi.PyBufferView.data` field
|
|
896
907
|
* in the output. Should be one of: ``"i8"``, ``"u8"``, ``"u8clamped"``,
|
|
897
908
|
* ``"i16"``, ``"u16"``, ``"i32"``, ``"u32"``, ``"i32"``, ``"u32"``,
|
|
@@ -907,16 +918,19 @@ declare class PyBufferMethods {
|
|
|
907
918
|
*/
|
|
908
919
|
declare class PyDict extends PyProxy {
|
|
909
920
|
/** @private */
|
|
910
|
-
static [Symbol.hasInstance](obj: any): obj is
|
|
921
|
+
static [Symbol.hasInstance](obj: any): obj is PyDict;
|
|
911
922
|
}
|
|
912
923
|
interface PyDict extends PyProxyWithGet, PyProxyWithSet, PyProxyWithHas, PyProxyWithLength, PyIterable {
|
|
913
924
|
}
|
|
914
925
|
/**
|
|
915
926
|
* A class to allow access to Python data buffers from JavaScript. These are
|
|
916
|
-
* produced by :js:meth:`~pyodide.ffi.PyBuffer.getBuffer` and cannot be
|
|
917
|
-
* When you are done, release it with the
|
|
918
|
-
*
|
|
919
|
-
*
|
|
927
|
+
* produced by :js:meth:`~pyodide.ffi.PyBuffer.getBuffer` and cannot be
|
|
928
|
+
* constructed directly. When you are done, release it with the
|
|
929
|
+
* :js:func:`~PyBufferView.release` method. It has a `[Symbol.dispose]()` method
|
|
930
|
+
* which is identical to the `release` method, so if you create the buffer with
|
|
931
|
+
* `using pybuf = proxy.getBuffer();` and JavaScript will automatically release
|
|
932
|
+
* it at the end of the scope. See the Python :external:doc:`c-api/buffer`
|
|
933
|
+
* documentation for more information.
|
|
920
934
|
*
|
|
921
935
|
* To find the element ``x[a_1, ..., a_n]``, you could use the following code:
|
|
922
936
|
*
|
|
@@ -964,6 +978,7 @@ interface PyDict extends PyProxyWithGet, PyProxyWithSet, PyProxyWithHas, PyProxy
|
|
|
964
978
|
* );
|
|
965
979
|
*/
|
|
966
980
|
declare class PyBufferView {
|
|
981
|
+
[Symbol.dispose]: () => void;
|
|
967
982
|
/**
|
|
968
983
|
* The offset of the first entry of the array. For instance if our array
|
|
969
984
|
* is 3d, then you will find ``array[0,0,0]`` at
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pyodide",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "314.0.0-alpha.2",
|
|
4
4
|
"description": "The Pyodide JavaScript package",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"python",
|
|
@@ -30,15 +30,14 @@
|
|
|
30
30
|
"dts-bundle-generator": "^8.1.1",
|
|
31
31
|
"esbuild": "^0.25.0",
|
|
32
32
|
"express": "^4.17.3",
|
|
33
|
-
"mocha": "^9.0.2",
|
|
34
33
|
"npm-run-all": "^4.1.5",
|
|
35
34
|
"nyc": "^15.1.0",
|
|
36
35
|
"playwright": "^1.55.1",
|
|
37
36
|
"prettier": "^2.2.1",
|
|
38
37
|
"tsd": "^0.24.1",
|
|
39
38
|
"tsx": "^4.20.5",
|
|
40
|
-
"typedoc": "^0.27.
|
|
41
|
-
"typescript": "5.
|
|
39
|
+
"typedoc": "^0.27.9",
|
|
40
|
+
"typescript": "5.8",
|
|
42
41
|
"wabt": "^1.0.32"
|
|
43
42
|
},
|
|
44
43
|
"main": "pyodide.js",
|
|
@@ -52,7 +51,7 @@
|
|
|
52
51
|
"types": "./ffi.d.ts"
|
|
53
52
|
},
|
|
54
53
|
"./pyodide.asm.wasm": "./pyodide.asm.wasm",
|
|
55
|
-
"./pyodide.asm.
|
|
54
|
+
"./pyodide.asm.mjs": "./pyodide.asm.mjs",
|
|
56
55
|
"./python_stdlib.zip": "./python_stdlib.zip",
|
|
57
56
|
"./pyodide.mjs": "./pyodide.mjs",
|
|
58
57
|
"./pyodide.js": "./pyodide.js",
|
|
@@ -60,7 +59,7 @@
|
|
|
60
59
|
"./pyodide-lock.json": "./pyodide-lock.json"
|
|
61
60
|
},
|
|
62
61
|
"files": [
|
|
63
|
-
"pyodide.asm.
|
|
62
|
+
"pyodide.asm.mjs",
|
|
64
63
|
"pyodide.asm.wasm",
|
|
65
64
|
"python_stdlib.zip",
|
|
66
65
|
"pyodide.mjs",
|