mirror of
https://github.com/pyscript/pyscript.git
synced 2025-12-19 18:27:29 -05:00
committed by
GitHub
parent
d6b1c393f6
commit
0a7e1ce0d7
@@ -27,6 +27,7 @@ repos:
|
||||
rev: v0.0.257
|
||||
hooks:
|
||||
- id: ruff
|
||||
exclude: pyscript\.core/test
|
||||
args: [--fix]
|
||||
|
||||
- repo: https://github.com/psf/black
|
||||
|
||||
@@ -124,6 +124,8 @@ export const handleCustomType = (node) => {
|
||||
afterRunAsync: codeAfterRunWorkerAsync,
|
||||
});
|
||||
|
||||
module.setGlobal(interpreter, "XWorker", XWorker);
|
||||
|
||||
const resolved = {
|
||||
type,
|
||||
interpreter,
|
||||
|
||||
@@ -7,22 +7,6 @@ export const run = (interpreter, code) => interpreter.runPython(clean(code));
|
||||
export const runAsync = (interpreter, code) =>
|
||||
interpreter.runPythonAsync(clean(code));
|
||||
|
||||
export function runEvent(interpreter, code, key) {
|
||||
code = `import js;event=js.__events.get(${key});${code}`;
|
||||
return this.run(interpreter, code);
|
||||
}
|
||||
|
||||
const worker = (method) =>
|
||||
function (interpreter, code, xworker) {
|
||||
code = `from js import xworker;${code}`;
|
||||
globalThis.xworker = xworker;
|
||||
return this[method](interpreter, code);
|
||||
};
|
||||
|
||||
export const runWorker = worker("run");
|
||||
|
||||
export const runWorkerAsync = worker("runAsync");
|
||||
|
||||
export const writeFile = ({ FS }, path, buffer) =>
|
||||
writeFileUtil(FS, path, buffer);
|
||||
/* c8 ignore stop */
|
||||
|
||||
@@ -1,12 +1,5 @@
|
||||
import { fetchPaths, stdio } from "./_utils.js";
|
||||
import {
|
||||
run,
|
||||
runAsync,
|
||||
runEvent,
|
||||
runWorker,
|
||||
runWorkerAsync,
|
||||
writeFile,
|
||||
} from "./_python.js";
|
||||
import { run, runAsync, writeFile } from "./_python.js";
|
||||
|
||||
const type = "micropython";
|
||||
|
||||
@@ -23,11 +16,18 @@ export default {
|
||||
if (config.fetch) await fetchPaths(this, runtime, config.fetch);
|
||||
return runtime;
|
||||
},
|
||||
setGlobal(interpreter, name, value) {
|
||||
const id = `__pyscript_${this.type}_${name}`;
|
||||
globalThis[id] = value;
|
||||
this.run(interpreter, `from js import ${id};${name}=${id};`);
|
||||
},
|
||||
deleteGlobal(interpreter, name) {
|
||||
const id = `__pyscript_${this.type}_${name}`;
|
||||
this.run(interpreter, `del ${id};del ${name}`);
|
||||
delete globalThis[id];
|
||||
},
|
||||
run,
|
||||
runAsync,
|
||||
runEvent,
|
||||
runWorker,
|
||||
runWorkerAsync,
|
||||
writeFile,
|
||||
};
|
||||
/* c8 ignore stop */
|
||||
|
||||
@@ -1,12 +1,5 @@
|
||||
import { fetchPaths, stdio } from "./_utils.js";
|
||||
import {
|
||||
run,
|
||||
runAsync,
|
||||
runEvent,
|
||||
runWorker,
|
||||
runWorkerAsync,
|
||||
writeFile,
|
||||
} from "./_python.js";
|
||||
import { run, runAsync, writeFile } from "./_python.js";
|
||||
|
||||
const type = "pyodide";
|
||||
|
||||
@@ -31,11 +24,14 @@ export default {
|
||||
}
|
||||
return interpreter;
|
||||
},
|
||||
setGlobal(interpreter, name, value) {
|
||||
interpreter.globals.set(name, value);
|
||||
},
|
||||
deleteGlobal(interpreter, name) {
|
||||
interpreter.globals.delete(name);
|
||||
},
|
||||
run,
|
||||
runAsync,
|
||||
runEvent,
|
||||
runWorker,
|
||||
runWorkerAsync,
|
||||
writeFile,
|
||||
};
|
||||
/* c8 ignore stop */
|
||||
|
||||
@@ -9,15 +9,6 @@ const type = "ruby-wasm-wasi";
|
||||
|
||||
// REQUIRES INTEGRATION TEST
|
||||
/* c8 ignore start */
|
||||
const worker = (method) =>
|
||||
function (interpreter, code, xworker) {
|
||||
globalThis.xworker = xworker;
|
||||
return this[method](
|
||||
interpreter,
|
||||
`require "js";xworker=JS::eval("return xworker");${code}`,
|
||||
);
|
||||
};
|
||||
|
||||
export default {
|
||||
type,
|
||||
experimental: true,
|
||||
@@ -32,16 +23,18 @@ export default {
|
||||
if (config.fetch) await fetchPaths(this, interpreter, config.fetch);
|
||||
return interpreter;
|
||||
},
|
||||
setGlobal(interpreter, name, value) {
|
||||
const id = `__pyscript_ruby_wasm_wasi_${name}`;
|
||||
globalThis[id] = value;
|
||||
this.run(interpreter, `require "js";$${name}=JS::eval("return ${id}")`);
|
||||
},
|
||||
deleteGlobal(interpreter, name) {
|
||||
const id = `__pyscript_ruby_wasm_wasi_${name}`;
|
||||
this.run(interpreter, `$${name}=nil`);
|
||||
delete globalThis[id];
|
||||
},
|
||||
run: (interpreter, code) => interpreter.eval(clean(code)),
|
||||
runAsync: (interpreter, code) => interpreter.evalAsync(clean(code)),
|
||||
runEvent(interpreter, code, key) {
|
||||
return this.run(
|
||||
interpreter,
|
||||
`require "js";event=JS::eval("return __events.get(${key})");${code}`,
|
||||
);
|
||||
},
|
||||
runWorker: worker("run"),
|
||||
runWorkerAsync: worker("runAsync"),
|
||||
writeFile: () => {
|
||||
throw new Error(`writeFile is not supported in ${type}`);
|
||||
},
|
||||
|
||||
@@ -4,12 +4,6 @@ const type = "wasmoon";
|
||||
|
||||
// REQUIRES INTEGRATION TEST
|
||||
/* c8 ignore start */
|
||||
const worker = (method) =>
|
||||
function (interpreter, code, xworker) {
|
||||
interpreter.global.set("xworker", xworker);
|
||||
return this[method](interpreter, code);
|
||||
};
|
||||
|
||||
export default {
|
||||
type,
|
||||
module: (version = "1.15.0") =>
|
||||
@@ -24,14 +18,14 @@ export default {
|
||||
if (config.fetch) await fetchPaths(this, interpreter, config.fetch);
|
||||
return interpreter;
|
||||
},
|
||||
setGlobal(interpreter, name, value) {
|
||||
interpreter.global.set(name, value);
|
||||
},
|
||||
deleteGlobal(interpreter, name) {
|
||||
interpreter.global.set(name, void 0);
|
||||
},
|
||||
run: (interpreter, code) => interpreter.doStringSync(clean(code)),
|
||||
runAsync: (interpreter, code) => interpreter.doString(clean(code)),
|
||||
runEvent(interpreter, code, key) {
|
||||
interpreter.global.set("event", globalThis.__events.get(key));
|
||||
return this.run(interpreter, code);
|
||||
},
|
||||
runWorker: worker("run"),
|
||||
runWorkerAsync: worker("runAsync"),
|
||||
writeFile: (
|
||||
{
|
||||
cmodule: {
|
||||
|
||||
@@ -13,9 +13,6 @@ defineProperty(globalThis, "pyscript", {
|
||||
},
|
||||
});
|
||||
|
||||
let index = 0;
|
||||
globalThis.__events = new Map();
|
||||
|
||||
/* c8 ignore start */ // attributes are tested via integration / e2e
|
||||
// ensure both interpreter and its queue are awaited then returns the interpreter
|
||||
const awaitInterpreter = async (key) => {
|
||||
@@ -43,12 +40,12 @@ export const listener = async (event) => {
|
||||
const interpreter = await awaitInterpreter(
|
||||
el.getAttribute(`${name}-env`) || name,
|
||||
);
|
||||
const i = index++;
|
||||
const handler = registry.get(name);
|
||||
try {
|
||||
globalThis.__events.set(i, event);
|
||||
registry.get(name).runEvent(interpreter, value, i);
|
||||
handler.setGlobal(interpreter, "event", event);
|
||||
handler.run(interpreter, value);
|
||||
} finally {
|
||||
globalThis.__events.delete(i);
|
||||
handler.deleteGlobal(interpreter, "event");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -54,18 +54,15 @@ const execute = async (script, source, XWorker, isAsync) => {
|
||||
try {
|
||||
// temporarily override inherited document.currentScript in a non writable way
|
||||
// but it deletes it right after to preserve native behavior (as it's sync: no trouble)
|
||||
defineProperty(globalThis, "XWorker", {
|
||||
configurable: true,
|
||||
get: () => XWorker,
|
||||
});
|
||||
defineProperty(document, "currentScript", {
|
||||
configurable: true,
|
||||
get: () => script,
|
||||
});
|
||||
module.setGlobal(interpreter, "XWorker", XWorker);
|
||||
return module[isAsync ? "runAsync" : "run"](interpreter, content);
|
||||
} finally {
|
||||
delete globalThis.XWorker;
|
||||
delete document.currentScript;
|
||||
module.deleteGlobal(interpreter, "XWorker");
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -23,15 +23,15 @@ try {
|
||||
);
|
||||
}
|
||||
|
||||
let engine, run, interpreterEvent;
|
||||
let interpreter, run, interpreterEvent;
|
||||
const add = (type, fn) => {
|
||||
addEventListener(
|
||||
type,
|
||||
fn ||
|
||||
(async (event) => {
|
||||
const interpreter = await engine;
|
||||
await interpreter;
|
||||
interpreterEvent = event;
|
||||
run(interpreter, `xworker.on${type}(xworker.event);`, xworker);
|
||||
run(`xworker.on${type}(xworker.event);`, xworker);
|
||||
}),
|
||||
!!fn && { once: true },
|
||||
);
|
||||
@@ -48,6 +48,8 @@ const xworker = {
|
||||
// this getter exists so that arbitrarily access to xworker.event
|
||||
// would always fail once an event has been dispatched, as that's not
|
||||
// meant to be accessed in the wild, respecting the one-off event nature of JS.
|
||||
// because xworker is a unique well defined globally shared reference,
|
||||
// there's also no need to bother setGlobal and deleteGlobal every single time.
|
||||
get event() {
|
||||
const event = interpreterEvent;
|
||||
if (!event) throw new Error("Unauthorized event access");
|
||||
@@ -57,11 +59,14 @@ const xworker = {
|
||||
};
|
||||
|
||||
add("message", ({ data: { options, code, hooks } }) => {
|
||||
engine = (async () => {
|
||||
interpreter = (async () => {
|
||||
const { type, version, config, async: isAsync } = options;
|
||||
const engine = await getRuntime(getRuntimeID(type, version), config);
|
||||
const interpreter = await getRuntime(
|
||||
getRuntimeID(type, version),
|
||||
config,
|
||||
);
|
||||
const details = create(registry.get(type));
|
||||
const name = `runWorker${isAsync ? "Async" : ""}`;
|
||||
const name = `run${isAsync ? "Async" : ""}`;
|
||||
|
||||
if (hooks) {
|
||||
// patch code if needed
|
||||
@@ -73,33 +78,25 @@ add("message", ({ data: { options, code, hooks } }) => {
|
||||
|
||||
// append code that should be executed *after* first
|
||||
if (after) {
|
||||
const method = details[name];
|
||||
details[name] = function (interpreter, code, xworker) {
|
||||
return method.call(
|
||||
this,
|
||||
interpreter,
|
||||
`${code}\n${after}`,
|
||||
xworker,
|
||||
);
|
||||
};
|
||||
const method = details[name].bind(details);
|
||||
details[name] = (interpreter, code) =>
|
||||
method(interpreter, `${code}\n${after}`);
|
||||
}
|
||||
|
||||
// prepend code that should be executed *before* (so that after is post-patched)
|
||||
if (before) {
|
||||
const method = details[name];
|
||||
details[name] = function (interpreter, code, xworker) {
|
||||
return method.call(
|
||||
this,
|
||||
interpreter,
|
||||
`${before}\n${code}`,
|
||||
xworker,
|
||||
);
|
||||
};
|
||||
const method = details[name].bind(details);
|
||||
details[name] = (interpreter, code) =>
|
||||
method(interpreter, `${before}\n${code}`);
|
||||
}
|
||||
}
|
||||
run = details[name].bind(details);
|
||||
run(engine, code, xworker);
|
||||
return engine;
|
||||
// set the `xworker` global reference once
|
||||
details.setGlobal(interpreter, "xworker", xworker);
|
||||
// simplify run calls after possible patches
|
||||
run = details[name].bind(details, interpreter);
|
||||
// execute the content of the worker file
|
||||
run(code);
|
||||
return interpreter;
|
||||
})();
|
||||
add("error");
|
||||
add("message");
|
||||
|
||||
@@ -50,6 +50,6 @@
|
||||
"coincident": "^0.4.1"
|
||||
},
|
||||
"worker": {
|
||||
"blob": "sha256-XQCxBN0Tsy6N0TFG5kG5/CaigwJWLnA63q5ZnUchya4="
|
||||
"blob": "sha256-obDch1OaxOZKhaCpSW9vEAHJk01N+9kYvSiGkNmeJRU="
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ globalThis.XPathEvaluator =
|
||||
}
|
||||
};
|
||||
|
||||
const { registerPlugin } = require("../cjs");
|
||||
require("../cjs");
|
||||
|
||||
(async () => {
|
||||
// shared 3rd party mocks
|
||||
|
||||
@@ -10,8 +10,6 @@
|
||||
</head>
|
||||
<body>
|
||||
<script type="micropython">
|
||||
from js import XWorker
|
||||
|
||||
def show_image(event):
|
||||
from js import document
|
||||
img = document.createElement("img")
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
export const python = { content: "", target: null };
|
||||
export const loadMicroPython = () => ({
|
||||
runPython(content) {
|
||||
python.content = content;
|
||||
python.target = document.currentScript.target;
|
||||
if (document.currentScript?.target) {
|
||||
python.content = content;
|
||||
python.target = document.currentScript.target;
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
@@ -23,6 +23,14 @@ export const loadPyodide = () => ({
|
||||
}
|
||||
python.target = document.currentScript.target;
|
||||
},
|
||||
globals: {
|
||||
set(name, value) {
|
||||
globalThis[name] = value;
|
||||
},
|
||||
delete(name) {
|
||||
delete globalThis[name];
|
||||
},
|
||||
},
|
||||
FS: {
|
||||
mkdirTree() {},
|
||||
writeFile() {},
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
print "ruby #{ RUBY_VERSION }p#{ RUBY_PATCHLEVEL }"
|
||||
end
|
||||
</script>
|
||||
<button ruby-wasm-wasi-click="print_version(event)">
|
||||
<button ruby-wasm-wasi-click="print_version($event)">
|
||||
ruby-wasm-wasi version
|
||||
</button>
|
||||
</body>
|
||||
|
||||
@@ -30,8 +30,6 @@
|
||||
|
||||
<!-- XWorker - MicroPython to MicroPython -->
|
||||
<script type="micropython">
|
||||
from js import XWorker
|
||||
|
||||
def handle_message(event):
|
||||
print(event.data)
|
||||
|
||||
@@ -42,8 +40,6 @@
|
||||
|
||||
<!-- XWorker - MicroPython to Pyodide -->
|
||||
<script type="micropython">
|
||||
from js import XWorker
|
||||
|
||||
def handle_message(event):
|
||||
print(event.data)
|
||||
|
||||
@@ -54,8 +50,6 @@
|
||||
|
||||
<!-- XWorker - MicroPython to Lua -->
|
||||
<script type="micropython">
|
||||
from js import XWorker
|
||||
|
||||
def handle_message(event):
|
||||
print(event.data)
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
</head>
|
||||
<body>
|
||||
<script type="micropython">
|
||||
from js import XWorker, Promise, document
|
||||
from js import Promise, document
|
||||
|
||||
deferred = Promise.withResolvers()
|
||||
|
||||
|
||||
@@ -1,4 +1,2 @@
|
||||
from js import xworker
|
||||
|
||||
print("What is 2 + 3?")
|
||||
print("Answer: " + xworker.sync.input("What is 2 + 3?"))
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
import re
|
||||
|
||||
from js import xworker
|
||||
|
||||
|
||||
def on_message(event):
|
||||
print(event.data)
|
||||
|
||||
Reference in New Issue
Block a user