Allow Workers w/out SharedArrayBuffer (#1967)

Allow Workers w/out SharedArrayBuffer
This commit is contained in:
Andrea Giammarchi
2024-02-02 15:03:30 +01:00
committed by GitHub
parent bcaab0eb93
commit 181d276c8b
8 changed files with 122 additions and 60 deletions

View File

@@ -1,17 +1,17 @@
{
"name": "@pyscript/core",
"version": "0.3.23",
"version": "0.4.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@pyscript/core",
"version": "0.3.23",
"version": "0.4.0",
"license": "APACHE-2.0",
"dependencies": {
"@ungap/with-resolvers": "^0.1.0",
"basic-devtools": "^0.1.6",
"polyscript": "^0.6.18",
"polyscript": "^0.7.0",
"sticky-module": "^0.1.1",
"to-json-callback": "^0.1.1",
"type-checked-collections": "^0.1.7"
@@ -22,7 +22,7 @@
"@codemirror/language": "^6.10.0",
"@codemirror/state": "^6.4.0",
"@codemirror/view": "^6.23.1",
"@playwright/test": "^1.41.1",
"@playwright/test": "^1.41.2",
"@rollup/plugin-commonjs": "^25.0.7",
"@rollup/plugin-node-resolve": "^15.2.3",
"@rollup/plugin-terser": "^0.4.4",
@@ -361,12 +361,12 @@
}
},
"node_modules/@playwright/test": {
"version": "1.41.1",
"resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.41.1.tgz",
"integrity": "sha512-9g8EWTjiQ9yFBXc6HjCWe41msLpxEX0KhmfmPl9RPLJdfzL4F0lg2BdJ91O9azFdl11y1pmpwdjBiSxvqc+btw==",
"version": "1.41.2",
"resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.41.2.tgz",
"integrity": "sha512-qQB9h7KbibJzrDpkXkYvsmiDJK14FULCCZgEcoe2AvFAS64oCirWTwzTlAYEbKaRxWs5TFesE1Na6izMv3HfGg==",
"dev": true,
"dependencies": {
"playwright": "1.41.1"
"playwright": "1.41.2"
},
"bin": {
"playwright": "cli.js"
@@ -970,13 +970,13 @@
}
},
"node_modules/coincident": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/coincident/-/coincident-1.1.1.tgz",
"integrity": "sha512-4i6bejrHuY6aOY8uhq56g/psUK2k99y5hImpavQz7yfPNCXuJkmtRYpvBOguC0mdYXPgQjvoz+Odw/WO6q4okg==",
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/coincident/-/coincident-1.2.1.tgz",
"integrity": "sha512-OXlCJBtBC278tNueIEyc5I9dvh9qOOZh1YPUbSRFI+i0AK4ELT/Io67qUv3uPmemW6dPHNmTdr/WKmkmnuBU5g==",
"dependencies": {
"@ungap/structured-clone": "^1.2.0",
"@ungap/with-resolvers": "^0.1.0",
"gc-hook": "^0.3.0",
"gc-hook": "^0.3.1",
"proxy-target": "^3.0.1"
},
"optionalDependencies": {
@@ -1634,9 +1634,9 @@
}
},
"node_modules/gc-hook": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/gc-hook/-/gc-hook-0.3.0.tgz",
"integrity": "sha512-Qkp0HM3z839Ns0LpXFJBXqClNW23wQo6JpUdJAjuf1/2jB+oUWSOMzeMv2yFq8Ur45z8IWw9hpRhkSjxSt5RWg=="
"version": "0.3.1",
"resolved": "https://registry.npmjs.org/gc-hook/-/gc-hook-0.3.1.tgz",
"integrity": "sha512-E5M+O/h2o7eZzGhzRZGex6hbB3k4NWqO0eA+OzLRLXxhdbYPajZnynPwAtphnh+cRHPwsj5Z80dqZlfI4eK55A=="
},
"node_modules/generic-names": {
"version": "4.0.0",
@@ -2359,12 +2359,12 @@
"integrity": "sha512-yyVAOFKTAElc7KdLt2+UKGExNYwYb/Y/WE9i+1ezCQsJE8gbKSjewfpRqK2nQgZ4d4hhAAGgDCOcIZVilqE5UA=="
},
"node_modules/playwright": {
"version": "1.41.1",
"resolved": "https://registry.npmjs.org/playwright/-/playwright-1.41.1.tgz",
"integrity": "sha512-gdZAWG97oUnbBdRL3GuBvX3nDDmUOuqzV/D24dytqlKt+eI5KbwusluZRGljx1YoJKZ2NRPaeWiFTeGZO7SosQ==",
"version": "1.41.2",
"resolved": "https://registry.npmjs.org/playwright/-/playwright-1.41.2.tgz",
"integrity": "sha512-v0bOa6H2GJChDL8pAeLa/LZC4feoAMbSQm1/jF/ySsWWoaNItvrMP7GEkvEEFyCTUYKMxjQKaTSg5up7nR6/8A==",
"dev": true,
"dependencies": {
"playwright-core": "1.41.1"
"playwright-core": "1.41.2"
},
"bin": {
"playwright": "cli.js"
@@ -2377,9 +2377,9 @@
}
},
"node_modules/playwright-core": {
"version": "1.41.1",
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.41.1.tgz",
"integrity": "sha512-/KPO5DzXSMlxSX77wy+HihKGOunh3hqndhqeo/nMxfigiKzogn8kfL0ZBDu0L1RKgan5XHCPmn6zXd2NUJgjhg==",
"version": "1.41.2",
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.41.2.tgz",
"integrity": "sha512-VaTvwCA4Y8kxEe+kfm2+uUUw5Lubf38RxF7FpBxLPmGe5sdNkSg5e3ChEigaGrX7qdqT3pt2m/98LiyvU2x6CA==",
"dev": true,
"bin": {
"playwright-core": "cli.js"
@@ -2403,16 +2403,16 @@
}
},
"node_modules/polyscript": {
"version": "0.6.18",
"resolved": "https://registry.npmjs.org/polyscript/-/polyscript-0.6.18.tgz",
"integrity": "sha512-naU5tisWCt/a12kl1lIdtphaGUCEDf4mmlzuOcvjayqkmfXUlxLdc9A5VEEZLcleWr5Wtx34aU9IBBG8hfSI6Q==",
"version": "0.7.0",
"resolved": "https://registry.npmjs.org/polyscript/-/polyscript-0.7.0.tgz",
"integrity": "sha512-cvxpvYY5JnHL59tE3Njje1sdDPcqHP7GITJnC8AsAOFAwZb+ucqyyS8gacyNEoyRArK0P3g50pZ4rcl/ojafow==",
"dependencies": {
"@ungap/structured-clone": "^1.2.0",
"@ungap/with-resolvers": "^0.1.0",
"basic-devtools": "^0.1.6",
"codedent": "^0.1.2",
"coincident": "^1.1.1",
"gc-hook": "^0.3.0",
"coincident": "^1.2.1",
"gc-hook": "^0.3.1",
"html-escaper": "^3.0.3",
"proxy-target": "^3.0.1",
"sticky-module": "^0.1.1",

View File

@@ -1,6 +1,6 @@
{
"name": "@pyscript/core",
"version": "0.3.23",
"version": "0.4.0",
"type": "module",
"description": "PyScript",
"module": "./index.js",
@@ -42,7 +42,7 @@
"dependencies": {
"@ungap/with-resolvers": "^0.1.0",
"basic-devtools": "^0.1.6",
"polyscript": "^0.6.18",
"polyscript": "^0.7.0",
"sticky-module": "^0.1.1",
"to-json-callback": "^0.1.1",
"type-checked-collections": "^0.1.7"
@@ -53,7 +53,7 @@
"@codemirror/language": "^6.10.0",
"@codemirror/state": "^6.4.0",
"@codemirror/view": "^6.23.1",
"@playwright/test": "^1.41.1",
"@playwright/test": "^1.41.2",
"@rollup/plugin-commonjs": "^25.0.7",
"@rollup/plugin-node-resolve": "^15.2.3",
"@rollup/plugin-terser": "^0.4.4",

View File

@@ -29,10 +29,36 @@ import { hooks, main, worker, codeFor, createFunction } from "./hooks.js";
// generic helper to disambiguate between custom element and script
const isScript = ({ tagName }) => tagName === "SCRIPT";
// Used to create either Pyodide or MicroPython workers
// with the PyScript module available within the code
const [PyWorker, MPWorker] = [...TYPES.entries()].map(
([TYPE, interpreter]) =>
/**
* A `Worker` facade able to bootstrap on the worker thread only a PyScript module.
* @param {string} file the python file to run ina worker.
* @param {{config?: string | object, async?: boolean}} [options] optional configuration for the worker.
* @returns {Promise<Worker & {sync: object}>}
*/
async function PyScriptWorker(file, options) {
await configs.get(TYPE).plugins;
const xworker = XWorker.call(
new Hook(null, hooked.get(TYPE)),
file,
{
...options,
type: interpreter,
},
);
assign(xworker.sync, sync);
return xworker.ready;
},
);
// avoid multiple initialization of the same library
const [
{
PyWorker: exportedPyWorker,
MPWorker: exportedMPWorker,
hooks: exportedHooks,
config: exportedConfig,
whenDefined: exportedWhenDefined,
@@ -40,6 +66,7 @@ const [
alreadyLive,
] = stickyModule("@pyscript/core", {
PyWorker,
MPWorker,
hooks,
config: {},
whenDefined,
@@ -48,6 +75,7 @@ const [
export {
TYPES,
exportedPyWorker as PyWorker,
exportedMPWorker as MPWorker,
exportedHooks as hooks,
exportedConfig as config,
exportedWhenDefined as whenDefined,
@@ -314,24 +342,3 @@ for (const [TYPE, interpreter] of TYPES) {
// export the used config without allowing leaks through it
exportedConfig[TYPE] = structuredClone(config);
}
/**
* A `Worker` facade able to bootstrap on the worker thread only a PyScript module.
* @param {string} file the python file to run ina worker.
* @param {{config?: string | object, async?: boolean}} [options] optional configuration for the worker.
* @returns {Worker & {sync: ProxyHandler<object>}}
*/
function PyWorker(file, options) {
const hooks = hooked.get("py");
// this propagates pyscript worker hooks without needing a pyscript
// bootstrap + it passes arguments and it defaults to `pyodide`
// as the interpreter to use in the worker, as all hooks assume that
// and as `pyodide` is the only default interpreter that can deal with
// all the features we need to deliver pyscript out there.
const xworker = XWorker.call(new Hook(null, hooks), file, {
type: "pyodide",
...options,
});
assign(xworker.sync, sync);
return xworker;
}

View File

@@ -24,16 +24,33 @@ for name in globalThis.Reflect.ownKeys(js_modules):
sys.modules["pyscript.js_modules"] = js_modules
if RUNNING_IN_WORKER:
import js
import polyscript
PyWorker = NotSupported(
"pyscript.PyWorker",
"pyscript.PyWorker works only when running in the main thread",
)
window = polyscript.xworker.window
document = window.document
js.document = document
try:
globalThis.SharedArrayBuffer.new(4)
import js
window = polyscript.xworker.window
document = window.document
js.document = document
except:
globalThis.console.debug("SharedArrayBuffer is not available")
# in this scenario none of the utilities would work
# as expected so we better export these as NotSupported
window = NotSupported(
"pyscript.window",
"pyscript.window in workers works only via SharedArrayBuffer",
)
document = NotSupported(
"pyscript.document",
"pyscript.document in workers works only via SharedArrayBuffer",
)
sync = polyscript.xworker.sync
# in workers the display does not have a default ID

View File

@@ -0,0 +1,23 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="../../dist/core.css">
<script type="module">
import { PyWorker } from '../../dist/core.js';
const { sync } = await PyWorker(
'./worker.py',
{
config: {
sync_main_only: true
}
}
);
document.documentElement.classList.add(
await sync.get_class()
);
</script>
</head>
</html>

View File

@@ -0,0 +1,3 @@
from pyscript import sync
sync.get_class = lambda: "ok"

View File

View File

@@ -3,14 +3,26 @@ import TYPES from "./types.js";
* A `Worker` facade able to bootstrap on the worker thread only a PyScript module.
* @param {string} file the python file to run ina worker.
* @param {{config?: string | object, async?: boolean}} [options] optional configuration for the worker.
* @returns {Worker & {sync: ProxyHandler<object>}}
* @returns {Promise<Worker & {sync: object}>}
*/
declare function exportedPyWorker(file: string, options?: {
config?: string | object;
async?: boolean;
}): Worker & {
sync: ProxyHandler<object>;
};
}): Promise<Worker & {
sync: object;
}>;
/**
* A `Worker` facade able to bootstrap on the worker thread only a PyScript module.
* @param {string} file the python file to run ina worker.
* @param {{config?: string | object, async?: boolean}} [options] optional configuration for the worker.
* @returns {Promise<Worker & {sync: object}>}
*/
declare function exportedMPWorker(file: string, options?: {
config?: string | object;
async?: boolean;
}): Promise<Worker & {
sync: object;
}>;
declare const exportedHooks: {
main: {
onWorker: Set<Function>;
@@ -39,4 +51,4 @@ declare const exportedHooks: {
declare const exportedConfig: {};
declare const exportedWhenDefined: (type: string) => Promise<any>;
import sync from "./sync.js";
export { TYPES, exportedPyWorker as PyWorker, exportedHooks as hooks, exportedConfig as config, exportedWhenDefined as whenDefined };
export { TYPES, exportedPyWorker as PyWorker, exportedMPWorker as MPWorker, exportedHooks as hooks, exportedConfig as config, exportedWhenDefined as whenDefined };