@pyscript/core 0.7.11 → 0.7.13
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/dist/{codemirror-BYspKCDy.js → codemirror-lkW_eC9r.js} +2 -2
- package/dist/codemirror-lkW_eC9r.js.map +1 -0
- package/dist/{codemirror_commands-BLDaEdQ6.js → codemirror_commands-DL2aL4qa.js} +2 -2
- package/dist/codemirror_commands-DL2aL4qa.js.map +1 -0
- package/dist/codemirror_lang-python-DD5EtV36.js +2 -0
- package/dist/codemirror_lang-python-DD5EtV36.js.map +1 -0
- package/dist/codemirror_language-DRHeqAwG.js +2 -0
- package/dist/codemirror_language-DRHeqAwG.js.map +1 -0
- package/dist/codemirror_state-BNbbkoNK.js +2 -0
- package/dist/codemirror_state-BNbbkoNK.js.map +1 -0
- package/dist/codemirror_view-FN7LalDk.js +2 -0
- package/dist/codemirror_view-FN7LalDk.js.map +1 -0
- package/dist/core-B4BRXuDy.js +4 -0
- package/dist/core-B4BRXuDy.js.map +1 -0
- package/dist/core.js +1 -1
- package/dist/{deprecations-manager-DIDxhyRq.js → deprecations-manager-BRHTwqUZ.js} +2 -2
- package/dist/{deprecations-manager-DIDxhyRq.js.map → deprecations-manager-BRHTwqUZ.js.map} +1 -1
- package/dist/{donkey-CLhmQOjG.js → donkey-CBEqGHeD.js} +2 -2
- package/dist/{donkey-CLhmQOjG.js.map → donkey-CBEqGHeD.js.map} +1 -1
- package/dist/{error-uzvvriog.js → error-DRVc1NKK.js} +2 -2
- package/dist/{error-uzvvriog.js.map → error-DRVc1NKK.js.map} +1 -1
- package/dist/index-C-U2wRvV.js +2 -0
- package/dist/index-C-U2wRvV.js.map +1 -0
- package/dist/{mpy-CnF17tqI.js → mpy-B-jI5Qug.js} +2 -2
- package/dist/{mpy-CnF17tqI.js.map → mpy-B-jI5Qug.js.map} +1 -1
- package/dist/{py-BZSSqcx3.js → py-DNLpCVR2.js} +2 -2
- package/dist/{py-BZSSqcx3.js.map → py-DNLpCVR2.js.map} +1 -1
- package/dist/{py-editor-DZ0Dxzzk.js → py-editor-DCtATRBs.js} +2 -2
- package/dist/{py-editor-DZ0Dxzzk.js.map → py-editor-DCtATRBs.js.map} +1 -1
- package/dist/{py-game-bqieV522.js → py-game-BGWt8dH1.js} +2 -2
- package/dist/{py-game-bqieV522.js.map → py-game-BGWt8dH1.js.map} +1 -1
- package/dist/{py-terminal-DYY4WN57.js → py-terminal-BKvzGq7q.js} +2 -2
- package/dist/{py-terminal-DYY4WN57.js.map → py-terminal-BKvzGq7q.js.map} +1 -1
- package/dist/xterm_addon-fit-DxKdSnof.js +14 -0
- package/dist/xterm_addon-fit-DxKdSnof.js.map +1 -0
- package/dist/xterm_addon-web-links-B6rWzrcs.js +14 -0
- package/dist/xterm_addon-web-links-B6rWzrcs.js.map +1 -0
- package/dist/zip-CgZGjqjF.js +2 -0
- package/dist/zip-CgZGjqjF.js.map +1 -0
- package/package.json +15 -14
- package/src/3rd-party/xterm_addon-fit.js +14 -2
- package/src/3rd-party/xterm_addon-web-links.js +14 -2
- package/src/core.js +13 -2
- package/src/stdlib/pyscript/__init__.py +100 -31
- package/src/stdlib/pyscript/context.py +198 -0
- package/src/stdlib/pyscript/display.py +211 -127
- package/src/stdlib/pyscript/events.py +191 -88
- package/src/stdlib/pyscript/fetch.py +156 -25
- package/src/stdlib/pyscript/ffi.py +132 -16
- package/src/stdlib/pyscript/flatted.py +78 -1
- package/src/stdlib/pyscript/fs.py +205 -49
- package/src/stdlib/pyscript/media.py +210 -50
- package/src/stdlib/pyscript/storage.py +214 -27
- package/src/stdlib/pyscript/util.py +28 -7
- package/src/stdlib/pyscript/web.py +1079 -881
- package/src/stdlib/pyscript/websocket.py +252 -45
- package/src/stdlib/pyscript/workers.py +176 -27
- package/src/stdlib/pyscript.js +13 -13
- package/types/stdlib/pyscript.d.ts +1 -1
- package/dist/codemirror-BYspKCDy.js.map +0 -1
- package/dist/codemirror_commands-BLDaEdQ6.js.map +0 -1
- package/dist/codemirror_lang-python-CkOVBHci.js +0 -2
- package/dist/codemirror_lang-python-CkOVBHci.js.map +0 -1
- package/dist/codemirror_language-DOkvasqm.js +0 -2
- package/dist/codemirror_language-DOkvasqm.js.map +0 -1
- package/dist/codemirror_state-BIAL8JKm.js +0 -2
- package/dist/codemirror_state-BIAL8JKm.js.map +0 -1
- package/dist/codemirror_view-Bt4sLgyA.js +0 -2
- package/dist/codemirror_view-Bt4sLgyA.js.map +0 -1
- package/dist/core-PTfg6inS.js +0 -4
- package/dist/core-PTfg6inS.js.map +0 -1
- package/dist/index-jZ1aOVVJ.js +0 -2
- package/dist/index-jZ1aOVVJ.js.map +0 -1
- package/dist/xterm_addon-fit--gyF3PcZ.js +0 -2
- package/dist/xterm_addon-fit--gyF3PcZ.js.map +0 -1
- package/dist/xterm_addon-web-links-D95xh2la.js +0 -2
- package/dist/xterm_addon-web-links-D95xh2la.js.map +0 -1
- package/dist/zip-pccs084i.js +0 -2
- package/dist/zip-pccs084i.js.map +0 -1
- package/src/stdlib/pyscript/magic_js.py +0 -84
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pyscript/core",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.13",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "PyScript",
|
|
6
6
|
"module": "./index.js",
|
|
@@ -48,6 +48,7 @@
|
|
|
48
48
|
"build:plugins": "node rollup/plugins.cjs",
|
|
49
49
|
"build:stdlib": "node rollup/stdlib.cjs",
|
|
50
50
|
"build:3rd-party": "node rollup/3rd-party.cjs",
|
|
51
|
+
"build:offline": "node rollup/offline.cjs | bash",
|
|
51
52
|
"build:tests-index": "node rollup/build_test_index.cjs",
|
|
52
53
|
"clean:3rd-party": "rm src/3rd-party/*.js && rm src/3rd-party/*.css",
|
|
53
54
|
"test:integration": "npm run test:ws; static-handler --coi . 2>/dev/null & SH_PID=$!; EXIT_CODE=0; (playwright test tests/js_tests.spec.js && playwright test tests/py_tests.main.spec.js && playwright test tests/py_tests.worker.spec.js) || EXIT_CODE=$?; kill $SH_PID 2>/dev/null; exit $EXIT_CODE",
|
|
@@ -70,32 +71,32 @@
|
|
|
70
71
|
"@webreflection/utils": "^0.1.1",
|
|
71
72
|
"add-promise-listener": "^0.1.3",
|
|
72
73
|
"basic-devtools": "^0.1.6",
|
|
73
|
-
"polyscript": "^0.
|
|
74
|
+
"polyscript": "^0.20.4",
|
|
74
75
|
"sticky-module": "^0.1.1",
|
|
75
76
|
"to-json-callback": "^0.1.1",
|
|
76
77
|
"type-checked-collections": "^0.1.7"
|
|
77
78
|
},
|
|
78
79
|
"devDependencies": {
|
|
79
|
-
"@codemirror/commands": "^6.10.
|
|
80
|
+
"@codemirror/commands": "^6.10.1",
|
|
80
81
|
"@codemirror/lang-python": "^6.2.1",
|
|
81
|
-
"@codemirror/language": "^6.
|
|
82
|
-
"@codemirror/state": "^6.5.
|
|
83
|
-
"@codemirror/view": "^6.
|
|
84
|
-
"@playwright/test": "^1.
|
|
82
|
+
"@codemirror/language": "^6.12.1",
|
|
83
|
+
"@codemirror/state": "^6.5.4",
|
|
84
|
+
"@codemirror/view": "^6.39.11",
|
|
85
|
+
"@playwright/test": "^1.57.0",
|
|
85
86
|
"@rollup/plugin-commonjs": "^29.0.0",
|
|
86
87
|
"@rollup/plugin-node-resolve": "^16.0.3",
|
|
87
88
|
"@rollup/plugin-terser": "^0.4.4",
|
|
88
89
|
"@webreflection/toml-j0.4": "^1.1.4",
|
|
89
|
-
"@xterm/addon-fit": "
|
|
90
|
-
"@xterm/addon-web-links": "
|
|
91
|
-
"@xterm/xterm": "
|
|
92
|
-
"bun": "^1.3.
|
|
93
|
-
"chokidar": "^
|
|
90
|
+
"@xterm/addon-fit": "0.11.0",
|
|
91
|
+
"@xterm/addon-web-links": "0.12.0",
|
|
92
|
+
"@xterm/xterm": "5.5.0",
|
|
93
|
+
"bun": "^1.3.6",
|
|
94
|
+
"chokidar": "^5.0.0",
|
|
94
95
|
"codedent": "^0.1.2",
|
|
95
96
|
"codemirror": "^6.0.2",
|
|
96
|
-
"eslint": "^9.39.
|
|
97
|
+
"eslint": "^9.39.2",
|
|
97
98
|
"flatted": "^3.3.3",
|
|
98
|
-
"rollup": "^4.
|
|
99
|
+
"rollup": "^4.55.3",
|
|
99
100
|
"rollup-plugin-postcss": "^4.0.2",
|
|
100
101
|
"rollup-plugin-string": "^3.0.0",
|
|
101
102
|
"static-handler": "^0.5.3",
|
|
@@ -1,7 +1,19 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Bundled by jsDelivr using Rollup v2.79.2 and Terser v5.39.0.
|
|
3
|
-
* Original file: /npm/@xterm/addon-fit@0.
|
|
3
|
+
* Original file: /npm/@xterm/addon-fit@0.11.0/lib/addon-fit.mjs
|
|
4
4
|
*
|
|
5
5
|
* Do NOT use SRI with dynamically generated files! More information: https://www.jsdelivr.com/using-sri-with-dynamic-files
|
|
6
6
|
*/
|
|
7
|
-
|
|
7
|
+
/**
|
|
8
|
+
* Copyright (c) 2014-2024 The xterm.js authors. All rights reserved.
|
|
9
|
+
* @license MIT
|
|
10
|
+
*
|
|
11
|
+
* Copyright (c) 2012-2013, Christopher Jeffrey (MIT License)
|
|
12
|
+
* @license MIT
|
|
13
|
+
*
|
|
14
|
+
* Originally forked from (with the author's permission):
|
|
15
|
+
* Fabrice Bellard's javascript vt100 for jslinux:
|
|
16
|
+
* http://bellard.org/jslinux/
|
|
17
|
+
* Copyright (c) 2011 Fabrice Bellard
|
|
18
|
+
*/
|
|
19
|
+
var e=class{activate(e){this._terminal=e}dispose(){}fit(){let e=this.proposeDimensions();if(!e||!this._terminal||isNaN(e.cols)||isNaN(e.rows))return;let t=this._terminal._core;(this._terminal.rows!==e.rows||this._terminal.cols!==e.cols)&&(t._renderService.clear(),this._terminal.resize(e.cols,e.rows))}proposeDimensions(){if(!this._terminal||!this._terminal.element||!this._terminal.element.parentElement)return;let e=this._terminal._core._renderService.dimensions;if(0===e.css.cell.width||0===e.css.cell.height)return;let t=0===this._terminal.options.scrollback?0:this._terminal.options.overviewRuler?.width||14,r=window.getComputedStyle(this._terminal.element.parentElement),i=parseInt(r.getPropertyValue("height")),s=Math.max(0,parseInt(r.getPropertyValue("width"))),l=window.getComputedStyle(this._terminal.element),a=i-(parseInt(l.getPropertyValue("padding-top"))+parseInt(l.getPropertyValue("padding-bottom"))),n=s-(parseInt(l.getPropertyValue("padding-right"))+parseInt(l.getPropertyValue("padding-left")))-t;return{cols:Math.max(2,Math.floor(n/e.css.cell.width)),rows:Math.max(1,Math.floor(a/e.css.cell.height))}}};export{e as FitAddon};export default null;
|
|
@@ -1,7 +1,19 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Bundled by jsDelivr using Rollup v2.79.2 and Terser v5.39.0.
|
|
3
|
-
* Original file: /npm/@xterm/addon-web-links@0.
|
|
3
|
+
* Original file: /npm/@xterm/addon-web-links@0.12.0/lib/addon-web-links.mjs
|
|
4
4
|
*
|
|
5
5
|
* Do NOT use SRI with dynamically generated files! More information: https://www.jsdelivr.com/using-sri-with-dynamic-files
|
|
6
6
|
*/
|
|
7
|
-
|
|
7
|
+
/**
|
|
8
|
+
* Copyright (c) 2014-2024 The xterm.js authors. All rights reserved.
|
|
9
|
+
* @license MIT
|
|
10
|
+
*
|
|
11
|
+
* Copyright (c) 2012-2013, Christopher Jeffrey (MIT License)
|
|
12
|
+
* @license MIT
|
|
13
|
+
*
|
|
14
|
+
* Originally forked from (with the author's permission):
|
|
15
|
+
* Fabrice Bellard's javascript vt100 for jslinux:
|
|
16
|
+
* http://bellard.org/jslinux/
|
|
17
|
+
* Copyright (c) 2011 Fabrice Bellard
|
|
18
|
+
*/
|
|
19
|
+
var e=class{constructor(e,t,r,i={}){this._terminal=e,this._regex=t,this._handler=r,this._options=i}provideLinks(e,t){let i=r.computeLink(e,this._regex,this._terminal,this._handler);t(this._addCallbacks(i))}_addCallbacks(e){return e.map((e=>(e.leave=this._options.leave,e.hover=(t,r)=>{if(this._options.hover){let{range:i}=e;this._options.hover(t,r,i)}},e)))}};function t(e){try{let t=new URL(e),r=t.password&&t.username?`${t.protocol}//${t.username}:${t.password}@${t.host}`:t.username?`${t.protocol}//${t.username}@${t.host}`:`${t.protocol}//${t.host}`;return e.toLocaleLowerCase().startsWith(r.toLocaleLowerCase())}catch{return!1}}var r=class e{static computeLink(r,i,n,s){let o,a=new RegExp(i.source,(i.flags||"")+"g"),[l,h]=e._getWindowedLineStrings(r-1,n),c=l.join(""),d=[];for(;o=a.exec(c);){let r=o[0];if(!t(r))continue;let[i,a]=e._mapStrIdx(n,h,0,o.index),[l,c]=e._mapStrIdx(n,i,a,r.length);if(-1===i||-1===a||-1===l||-1===c)continue;let p={start:{x:a+1,y:i+1},end:{x:c,y:l+1}};d.push({range:p,text:r,activate:s})}return d}static _getWindowedLineStrings(e,t){let r,i=e,n=e,s=0,o="",a=[];if(r=t.buffer.active.getLine(e)){let e=r.translateToString(!0);if(r.isWrapped&&" "!==e[0]){for(s=0;(r=t.buffer.active.getLine(--i))&&s<2048&&(o=r.translateToString(!0),s+=o.length,a.push(o),r.isWrapped&&-1===o.indexOf(" ")););a.reverse()}for(a.push(e),s=0;(r=t.buffer.active.getLine(++n))&&r.isWrapped&&s<2048&&(o=r.translateToString(!0),s+=o.length,a.push(o),-1===o.indexOf(" ")););}return[a,i]}static _mapStrIdx(e,t,r,i){let n=e.buffer.active,s=n.getNullCell(),o=r;for(;i;){let e=n.getLine(t);if(!e)return[-1,-1];for(let r=o;r<e.length;++r){e.getCell(r,s);let o=s.getChars();if(s.getWidth()&&(i-=o.length||1,r===e.length-1&&""===o)){let e=n.getLine(t+1);e&&e.isWrapped&&(e.getCell(0,s),2===s.getWidth()&&(i+=1))}if(i<0)return[t,r]}t++,o=0}return[t,o]}},i=/(https?|HTTPS?):[/]{2}[^\s"'!*(){}|\\\^<>`]*[^\s"':,.!?{}|\\\^~\[\]`()<>]/;function n(e,t){let r=window.open();if(r){try{r.opener=null}catch{}r.location.href=t}else console.warn("Opening link blocked as opener could not be cleared")}var s=class{constructor(e=n,t={}){this._handler=e,this._options=t}activate(t){this._terminal=t;let r=this._options,n=r.urlRegex||i;this._linkProvider=this._terminal.registerLinkProvider(new e(this._terminal,n,this._handler,r))}dispose(){this._linkProvider?.dispose()}};export{s as WebLinksAddon};export default null;
|
package/src/core.js
CHANGED
|
@@ -117,7 +117,7 @@ for (const [TYPE, interpreter] of TYPES) {
|
|
|
117
117
|
else dispatch(element, TYPE, "done");
|
|
118
118
|
};
|
|
119
119
|
|
|
120
|
-
|
|
120
|
+
let { config, configURL, plugins, error } = configs.get(TYPE);
|
|
121
121
|
|
|
122
122
|
// create a unique identifier when/if needed
|
|
123
123
|
let id = 0;
|
|
@@ -311,13 +311,24 @@ for (const [TYPE, interpreter] of TYPES) {
|
|
|
311
311
|
|
|
312
312
|
hooked.set(TYPE, hooks);
|
|
313
313
|
|
|
314
|
+
// allow offline interpreter detection via [offline] attribute
|
|
315
|
+
let version = offline_interpreter(config);
|
|
316
|
+
if (!version) {
|
|
317
|
+
const css = "script[type='module'][offline]";
|
|
318
|
+
const s = document.querySelector(css)?.src;
|
|
319
|
+
if (s && import.meta.url.startsWith(s.replace(/\.js$/, ""))) {
|
|
320
|
+
version = `./pyscript/${interpreter}/${interpreter}.mjs`;
|
|
321
|
+
version = offline_interpreter({ interpreter: version });
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
|
|
314
325
|
define(TYPE, {
|
|
315
326
|
config,
|
|
316
327
|
configURL,
|
|
317
328
|
interpreter,
|
|
318
329
|
hooks,
|
|
330
|
+
version,
|
|
319
331
|
env: `${TYPE}-script`,
|
|
320
|
-
version: offline_interpreter(config),
|
|
321
332
|
onerror(error, element) {
|
|
322
333
|
errors.set(element, error);
|
|
323
334
|
},
|
|
@@ -1,36 +1,105 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
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
|
-
|
|
1
|
+
"""
|
|
2
|
+
This is the main `pyscript` namespace. It provides the primary Pythonic API
|
|
3
|
+
for users to interact with the
|
|
4
|
+
[browser's own API](https://developer.mozilla.org/en-US/docs/Web/API). It
|
|
5
|
+
includes utilities for common activities such as displaying content, handling
|
|
6
|
+
events, fetching resources, managing local storage, and coordinating with
|
|
7
|
+
web workers.
|
|
8
|
+
|
|
9
|
+
The most important names provided by this namespace can be directly imported
|
|
10
|
+
from `pyscript`, for example:
|
|
11
|
+
|
|
12
|
+
```python
|
|
13
|
+
from pyscript import display, HTML, fetch, when, storage, WebSocket
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
The following names are available in the `pyscript` namespace:
|
|
17
|
+
|
|
18
|
+
- `RUNNING_IN_WORKER`: Boolean indicating if the code is running in a Web
|
|
19
|
+
Worker.
|
|
20
|
+
- `PyWorker`: Class for creating Web Workers running Python code.
|
|
21
|
+
- `config`: Configuration object for pyscript settings.
|
|
22
|
+
- `current_target`: The element in the DOM that is the current target for
|
|
23
|
+
output.
|
|
24
|
+
- `document`: The standard `document` object, proxied in workers.
|
|
25
|
+
- `window`: The standard `window` object, proxied in workers.
|
|
26
|
+
- `js_import`: Function to dynamically import JS modules.
|
|
27
|
+
- `js_modules`: Object containing JS modules available to Python.
|
|
28
|
+
- `sync`: Utility for synchronizing between worker and main thread.
|
|
29
|
+
- `display`: Function to render Python objects in the web page.
|
|
30
|
+
- `HTML`: Helper class to create HTML content for display.
|
|
31
|
+
- `fetch`: Function to perform HTTP requests.
|
|
32
|
+
- `Storage`: Class representing browser storage (local/session).
|
|
33
|
+
- `storage`: Object to interact with browser's local storage.
|
|
34
|
+
- `WebSocket`: Class to create and manage WebSocket connections.
|
|
35
|
+
- `when`: Function to register event handlers on DOM elements.
|
|
36
|
+
- `Event`: Class representing user defined or DOM events.
|
|
37
|
+
- `py_import`: Function to lazily import Pyodide related Python modules.
|
|
38
|
+
|
|
39
|
+
If running in the main thread, the following additional names are available:
|
|
40
|
+
|
|
41
|
+
- `create_named_worker`: Function to create a named Web Worker.
|
|
42
|
+
- `workers`: Object to manage and interact with existing Web Workers.
|
|
43
|
+
|
|
44
|
+
All of these names are defined in the various submodules of `pyscript` and
|
|
45
|
+
are imported and re-exported here for convenience. Please refer to the
|
|
46
|
+
respective submodule documentation for more details on each component.
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
!!! Note
|
|
50
|
+
Some notes about the naming conventions and the relationship between
|
|
51
|
+
various similar-but-different names found within this code base.
|
|
52
|
+
|
|
53
|
+
```python
|
|
54
|
+
import pyscript
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
The `pyscript` package contains the main user-facing API offered by
|
|
58
|
+
PyScript. All the names which are supposed be used by end users should
|
|
59
|
+
be made available in `pyscript/__init__.py` (i.e., this source file).
|
|
60
|
+
|
|
61
|
+
```python
|
|
62
|
+
import _pyscript
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
The `_pyscript` module is an internal API implemented in JS. **End users
|
|
66
|
+
should not use it directly**. For its implementation, grep for
|
|
67
|
+
`interpreter.registerJsModule("_pyscript",...)` in `core.js`.
|
|
68
|
+
|
|
69
|
+
```python
|
|
70
|
+
import js
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
The `js` object is
|
|
74
|
+
[the JS `globalThis`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/globalThis),
|
|
75
|
+
as exported by Pyodide and/or Micropython's foreign function interface
|
|
76
|
+
(FFI). As such, it contains different things in the main thread or in a
|
|
77
|
+
worker, as defined by web standards.
|
|
78
|
+
|
|
79
|
+
```python
|
|
80
|
+
import pyscript.context
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
The `context` submodule abstracts away some of the differences between
|
|
84
|
+
the main thread and a worker. Its most important features are made
|
|
85
|
+
available in the root `pyscript` namespace. All other functionality is
|
|
86
|
+
mostly for internal PyScript use or advanced users. In particular, it
|
|
87
|
+
defines `window` and `document` in such a way that these names work in
|
|
88
|
+
both cases: in the main thread, they are the "real" objects, in a worker
|
|
89
|
+
they are proxies which work thanks to
|
|
90
|
+
[coincident](https://github.com/WebReflection/coincident).
|
|
91
|
+
|
|
92
|
+
```python
|
|
93
|
+
from pyscript import window, document
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
These are just the `window` and `document` objects as defined by
|
|
97
|
+
`pyscript.context`. This is the blessed way to access them from `pyscript`,
|
|
98
|
+
as it works transparently in both the main thread and worker cases.
|
|
99
|
+
"""
|
|
31
100
|
|
|
32
101
|
from polyscript import lazy_py_modules as py_import
|
|
33
|
-
from pyscript.
|
|
102
|
+
from pyscript.context import (
|
|
34
103
|
RUNNING_IN_WORKER,
|
|
35
104
|
PyWorker,
|
|
36
105
|
config,
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Execution context management for PyScript.
|
|
3
|
+
|
|
4
|
+
This module handles the differences between running in the
|
|
5
|
+
[main browser thread](https://developer.mozilla.org/en-US/docs/Glossary/Main_thread)
|
|
6
|
+
versus running in a
|
|
7
|
+
[Web Worker](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers),
|
|
8
|
+
providing a consistent API regardless of the execution context.
|
|
9
|
+
|
|
10
|
+
Key features:
|
|
11
|
+
|
|
12
|
+
- Detects whether code is running in a worker or main thread. Read this via
|
|
13
|
+
the boolean `pyscript.context.RUNNING_IN_WORKER`.
|
|
14
|
+
- Parses and normalizes configuration from `polyscript.config` and adds the
|
|
15
|
+
Python interpreter type via the `type` key in `pyscript.context.config`.
|
|
16
|
+
- Provides appropriate implementations of `window`, `document`, and `sync`.
|
|
17
|
+
- Sets up JavaScript module import system, including a lazy `js_import`
|
|
18
|
+
function.
|
|
19
|
+
- Manages `PyWorker` creation.
|
|
20
|
+
- Provides access to the current display target via
|
|
21
|
+
`pyscript.context.display_target`.
|
|
22
|
+
|
|
23
|
+
!!! warning
|
|
24
|
+
|
|
25
|
+
These are key differences between the main thread and worker contexts:
|
|
26
|
+
|
|
27
|
+
Main thread context:
|
|
28
|
+
|
|
29
|
+
- `window` and `document` are available directly.
|
|
30
|
+
- `PyWorker` can be created to spawn worker threads.
|
|
31
|
+
- `sync` is not available (raises `NotSupported`).
|
|
32
|
+
|
|
33
|
+
Worker context:
|
|
34
|
+
|
|
35
|
+
- `window` and `document` are proxied from main thread (if SharedArrayBuffer
|
|
36
|
+
available).
|
|
37
|
+
- `PyWorker` is not available (raises `NotSupported`).
|
|
38
|
+
- `sync` utilities are available for main thread communication.
|
|
39
|
+
"""
|
|
40
|
+
|
|
41
|
+
import json
|
|
42
|
+
import sys
|
|
43
|
+
|
|
44
|
+
import js
|
|
45
|
+
from polyscript import config as _polyscript_config
|
|
46
|
+
from polyscript import js_modules
|
|
47
|
+
from pyscript.util import NotSupported
|
|
48
|
+
|
|
49
|
+
RUNNING_IN_WORKER = not hasattr(js, "document")
|
|
50
|
+
"""Detect execution context: True if running in a worker, False if main thread."""
|
|
51
|
+
|
|
52
|
+
config = json.loads(js.JSON.stringify(_polyscript_config))
|
|
53
|
+
"""Parsed and normalized configuration."""
|
|
54
|
+
if isinstance(config, str):
|
|
55
|
+
config = {}
|
|
56
|
+
|
|
57
|
+
js_import = None
|
|
58
|
+
"""Function to import JavaScript modules dynamically."""
|
|
59
|
+
|
|
60
|
+
window = None
|
|
61
|
+
"""The `window` object (proxied if in a worker)."""
|
|
62
|
+
|
|
63
|
+
document = None
|
|
64
|
+
"""The `document` object (proxied if in a worker)."""
|
|
65
|
+
|
|
66
|
+
sync = None
|
|
67
|
+
"""Sync utilities for worker-main thread communication (only in workers)."""
|
|
68
|
+
|
|
69
|
+
# Detect and add Python interpreter type to config.
|
|
70
|
+
if "MicroPython" in sys.version:
|
|
71
|
+
config["type"] = "mpy"
|
|
72
|
+
else:
|
|
73
|
+
config["type"] = "py"
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
class _JSModuleProxy:
|
|
77
|
+
"""
|
|
78
|
+
Proxy for JavaScript modules imported via js_modules.
|
|
79
|
+
|
|
80
|
+
This allows Python code to import JavaScript modules using Python's
|
|
81
|
+
import syntax:
|
|
82
|
+
|
|
83
|
+
```python
|
|
84
|
+
from pyscript.js_modules lodash import debounce
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
The proxy lazily retrieves the actual JavaScript module when accessed.
|
|
88
|
+
"""
|
|
89
|
+
|
|
90
|
+
def __init__(self, name):
|
|
91
|
+
"""
|
|
92
|
+
Create a proxy for the named JavaScript module.
|
|
93
|
+
"""
|
|
94
|
+
self.name = name
|
|
95
|
+
|
|
96
|
+
def __getattr__(self, field):
|
|
97
|
+
"""
|
|
98
|
+
Retrieve a JavaScript object/function from the proxied JavaScript
|
|
99
|
+
module via the given `field` name.
|
|
100
|
+
"""
|
|
101
|
+
# Avoid Pyodide looking for non-existent special methods.
|
|
102
|
+
if not field.startswith("_"):
|
|
103
|
+
return getattr(getattr(js_modules, self.name), field)
|
|
104
|
+
return None
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
# Register all available JavaScript modules in Python's module system.
|
|
108
|
+
# This enables: from pyscript.js_modules.xxx import yyy
|
|
109
|
+
for module_name in js.Reflect.ownKeys(js_modules):
|
|
110
|
+
sys.modules[f"pyscript.js_modules.{module_name}"] = _JSModuleProxy(module_name)
|
|
111
|
+
sys.modules["pyscript.js_modules"] = js_modules
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
# Context-specific setup: Worker vs Main Thread.
|
|
115
|
+
if RUNNING_IN_WORKER:
|
|
116
|
+
import polyscript
|
|
117
|
+
|
|
118
|
+
# PyWorker cannot be created from within a worker.
|
|
119
|
+
PyWorker = NotSupported(
|
|
120
|
+
"pyscript.PyWorker",
|
|
121
|
+
"pyscript.PyWorker works only when running in the main thread",
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
# Attempt to access main thread's window and document via SharedArrayBuffer.
|
|
125
|
+
try:
|
|
126
|
+
window = polyscript.xworker.window
|
|
127
|
+
document = window.document
|
|
128
|
+
js.document = document
|
|
129
|
+
|
|
130
|
+
# Create js_import function that runs imports on the main thread.
|
|
131
|
+
js_import = window.Function(
|
|
132
|
+
"return (...urls) => Promise.all(urls.map((url) => import(url)))"
|
|
133
|
+
)()
|
|
134
|
+
|
|
135
|
+
except:
|
|
136
|
+
# SharedArrayBuffer not available - window/document cannot be proxied.
|
|
137
|
+
sab_error_message = (
|
|
138
|
+
"Unable to use `window` or `document` in worker. "
|
|
139
|
+
"This requires SharedArrayBuffer support. "
|
|
140
|
+
"See: https://docs.pyscript.net/latest/faq/#sharedarraybuffer"
|
|
141
|
+
)
|
|
142
|
+
js.console.warn(sab_error_message)
|
|
143
|
+
window = NotSupported("pyscript.window", sab_error_message)
|
|
144
|
+
document = NotSupported("pyscript.document", sab_error_message)
|
|
145
|
+
|
|
146
|
+
# Worker-specific utilities for main thread communication.
|
|
147
|
+
sync = polyscript.xworker.sync
|
|
148
|
+
|
|
149
|
+
def current_target():
|
|
150
|
+
"""
|
|
151
|
+
Get the current output target in worker context.
|
|
152
|
+
"""
|
|
153
|
+
return polyscript.target
|
|
154
|
+
|
|
155
|
+
else:
|
|
156
|
+
# Main thread context setup.
|
|
157
|
+
import _pyscript
|
|
158
|
+
from _pyscript import PyWorker as _PyWorker
|
|
159
|
+
from pyscript.ffi import to_js
|
|
160
|
+
|
|
161
|
+
js_import = _pyscript.js_import
|
|
162
|
+
|
|
163
|
+
def PyWorker(url, **options):
|
|
164
|
+
"""
|
|
165
|
+
Create a Web Worker running Python code.
|
|
166
|
+
|
|
167
|
+
This spawns a new worker thread that can execute Python code
|
|
168
|
+
found at the `url`, independently of the main thread. The
|
|
169
|
+
`**options` can be used to configure the worker.
|
|
170
|
+
|
|
171
|
+
```python
|
|
172
|
+
from pyscript import PyWorker
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
# Create a worker to run background tasks.
|
|
176
|
+
# (`type` MUST be either `micropython` or `pyodide`)
|
|
177
|
+
worker = PyWorker("./worker.py", type="micropython")
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
PyWorker **can only be created from the main thread**, not from
|
|
181
|
+
within another worker.
|
|
182
|
+
"""
|
|
183
|
+
return _PyWorker(url, to_js(options))
|
|
184
|
+
|
|
185
|
+
# Main thread has direct access to window and document.
|
|
186
|
+
window = js
|
|
187
|
+
document = js.document
|
|
188
|
+
|
|
189
|
+
# sync is not available in main thread (only in workers).
|
|
190
|
+
sync = NotSupported(
|
|
191
|
+
"pyscript.sync", "pyscript.sync works only when running in a worker"
|
|
192
|
+
)
|
|
193
|
+
|
|
194
|
+
def current_target():
|
|
195
|
+
"""
|
|
196
|
+
Get the current output target in main thread context.
|
|
197
|
+
"""
|
|
198
|
+
return _pyscript.target
|