mirror of
https://github.com/pyscript/pyscript.git
synced 2025-12-23 22:00:25 -05:00
Add pyscript module in both Main and Workers (#1619)
This commit is contained in:
committed by
GitHub
parent
2774e49ab9
commit
8a01a56e51
@@ -20,7 +20,7 @@ repos:
|
|||||||
- id: check-yaml
|
- id: check-yaml
|
||||||
- id: detect-private-key
|
- id: detect-private-key
|
||||||
- id: end-of-file-fixer
|
- id: end-of-file-fixer
|
||||||
exclude: \.min\.js$
|
exclude: pyscript\.next/core.*|\.min\.js$
|
||||||
- id: trailing-whitespace
|
- id: trailing-whitespace
|
||||||
|
|
||||||
- repo: https://github.com/charliermarsh/ruff-pre-commit
|
- repo: https://github.com/charliermarsh/ruff-pre-commit
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -1,10 +1,11 @@
|
|||||||
import "@ungap/with-resolvers";
|
import "@ungap/with-resolvers";
|
||||||
import { $ } from "basic-devtools";
|
import { $ } from "basic-devtools";
|
||||||
import { define } from "polyscript";
|
import { define, XWorker } from "polyscript";
|
||||||
|
|
||||||
// TODO: this is not strictly polyscript related but handy ... not sure
|
// TODO: this is not strictly polyscript related but handy ... not sure
|
||||||
// we should factor this utility out a part but this works anyway.
|
// we should factor this utility out a part but this works anyway.
|
||||||
import { queryTarget } from "../node_modules/polyscript/esm/script-handler.js";
|
import { queryTarget } from "../node_modules/polyscript/esm/script-handler.js";
|
||||||
|
import { Hook } from "../node_modules/polyscript/esm/worker/hooks.js";
|
||||||
|
|
||||||
import { robustFetch as fetch } from "./fetch.js";
|
import { robustFetch as fetch } from "./fetch.js";
|
||||||
|
|
||||||
@@ -12,7 +13,9 @@ const { defineProperty } = Object;
|
|||||||
|
|
||||||
const getText = (body) => body.text();
|
const getText = (body) => body.text();
|
||||||
|
|
||||||
(async () => {
|
// allows lazy element features on code evaluation
|
||||||
|
let currentElement;
|
||||||
|
|
||||||
// create a unique identifier when/if needed
|
// create a unique identifier when/if needed
|
||||||
let id = 0;
|
let id = 0;
|
||||||
const getID = (prefix = "py") => `${prefix}-${id++}`;
|
const getID = (prefix = "py") => `${prefix}-${id++}`;
|
||||||
@@ -68,19 +71,54 @@ const getText = (body) => body.text();
|
|||||||
for (const fn of hooks[hook]) fn(pyodide, element);
|
for (const fn of hooks[hook]) fn(pyodide, element);
|
||||||
};
|
};
|
||||||
|
|
||||||
const addDisplay = (element) => {
|
const registerModule = ({ XWorker: $XWorker, interpreter, io }) => {
|
||||||
const id = isScript(element) ? element.target.id : element.id;
|
// automatically use the pyscript stderr (when/if defined)
|
||||||
return `
|
// this defaults to console.error
|
||||||
# this code is just for demo purpose but the basics work
|
function PyWorker(...args) {
|
||||||
def _display(what, target="${id}", append=True):
|
const worker = $XWorker(...args);
|
||||||
from js import document
|
worker.onerror = ({ error }) => io.stderr(error);
|
||||||
element = document.getElementById(target)
|
return worker;
|
||||||
if append:
|
}
|
||||||
element.append(what)
|
interpreter.registerJsModule("pyscript", {
|
||||||
else:
|
PyWorker,
|
||||||
element.textContent = what
|
document,
|
||||||
display = _display
|
window,
|
||||||
`;
|
// a getter to ensure if multiple scripts with same
|
||||||
|
// env (py) runs, their execution code will have the correct
|
||||||
|
// display reference with automatic target
|
||||||
|
get display() {
|
||||||
|
const id = isScript(currentElement)
|
||||||
|
? currentElement.target.id
|
||||||
|
: currentElement.id;
|
||||||
|
|
||||||
|
// TODO: decide which feature of display we want to keep
|
||||||
|
return (what, target = id, append = true) => {
|
||||||
|
const element = document.getElementById(target);
|
||||||
|
if (append) element.append(what);
|
||||||
|
else element.textContent = what;
|
||||||
|
};
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const workerPyScriptModule = [
|
||||||
|
"from pyodide_js import FS",
|
||||||
|
`FS.writeFile('./pyscript.py', '${[
|
||||||
|
"import polyscript",
|
||||||
|
"document=polyscript.xworker.window.document",
|
||||||
|
"window=polyscript.xworker.window",
|
||||||
|
"sync=polyscript.xworker.sync",
|
||||||
|
].join(";")}')`,
|
||||||
|
].join(";");
|
||||||
|
|
||||||
|
const workerHooks = {
|
||||||
|
codeBeforeRunWorker: () =>
|
||||||
|
[workerPyScriptModule, ...hooks.codeBeforeRunWorker].join("\n"),
|
||||||
|
codeBeforeRunWorkerAsync: () =>
|
||||||
|
[workerPyScriptModule, ...hooks.codeBeforeRunWorkerAsync].join("\n"),
|
||||||
|
codeAfterRunWorker: () => [...hooks.codeAfterRunWorker].join("\n"),
|
||||||
|
codeAfterRunWorkerAsync: () =>
|
||||||
|
[...hooks.codeAfterRunWorkerAsync].join("\n"),
|
||||||
};
|
};
|
||||||
|
|
||||||
// define the module as both `<script type="py">` and `<py-script>`
|
// define the module as both `<script type="py">` and `<py-script>`
|
||||||
@@ -88,24 +126,14 @@ const getText = (body) => body.text();
|
|||||||
config,
|
config,
|
||||||
env: "py-script",
|
env: "py-script",
|
||||||
interpreter: "pyodide",
|
interpreter: "pyodide",
|
||||||
codeBeforeRunWorker() {
|
...workerHooks,
|
||||||
return [...hooks.codeBeforeRunWorker].join("\n");
|
|
||||||
},
|
|
||||||
codeAfterRunWorker() {
|
|
||||||
return [...hooks.codeAfterRunWorker].join("\n");
|
|
||||||
},
|
|
||||||
onBeforeRun(pyodide, element) {
|
onBeforeRun(pyodide, element) {
|
||||||
|
currentElement = element;
|
||||||
bootstrapNodeAndPlugins(pyodide, element, before, "onBeforeRun");
|
bootstrapNodeAndPlugins(pyodide, element, before, "onBeforeRun");
|
||||||
pyodide.interpreter.runPython(addDisplay(element));
|
|
||||||
},
|
},
|
||||||
onBeforeRunAync(pyodide, element) {
|
onBeforeRunAync(pyodide, element) {
|
||||||
pyodide.interpreter.runPython(addDisplay(element));
|
currentElement = element;
|
||||||
bootstrapNodeAndPlugins(
|
bootstrapNodeAndPlugins(pyodide, element, before, "onBeforeRunAync");
|
||||||
pyodide,
|
|
||||||
element,
|
|
||||||
before,
|
|
||||||
"onBeforeRunAync",
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
onAfterRun(pyodide, element) {
|
onAfterRun(pyodide, element) {
|
||||||
bootstrapNodeAndPlugins(pyodide, element, after, "onAfterRun");
|
bootstrapNodeAndPlugins(pyodide, element, after, "onAfterRun");
|
||||||
@@ -114,6 +142,7 @@ const getText = (body) => body.text();
|
|||||||
bootstrapNodeAndPlugins(pyodide, element, after, "onAfterRunAsync");
|
bootstrapNodeAndPlugins(pyodide, element, after, "onAfterRunAsync");
|
||||||
},
|
},
|
||||||
async onInterpreterReady(pyodide, element) {
|
async onInterpreterReady(pyodide, element) {
|
||||||
|
registerModule(pyodide, element);
|
||||||
// allows plugins to do whatever they want with the element
|
// allows plugins to do whatever they want with the element
|
||||||
// before regular stuff happens in here
|
// before regular stuff happens in here
|
||||||
for (const callback of hooks.onInterpreterReady)
|
for (const callback of hooks.onInterpreterReady)
|
||||||
@@ -134,9 +163,7 @@ const getText = (body) => body.text();
|
|||||||
// document.currentScript.target if needed
|
// document.currentScript.target if needed
|
||||||
defineProperty(element, "target", { value: show });
|
defineProperty(element, "target", { value: show });
|
||||||
|
|
||||||
pyodide[`run${isAsync ? "Async" : ""}`](
|
pyodide[`run${isAsync ? "Async" : ""}`](await fetchSource(element));
|
||||||
await fetchSource(element),
|
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
// resolve PyScriptElement to allow connectedCallback
|
// resolve PyScriptElement to allow connectedCallback
|
||||||
element._pyodide.resolve(pyodide);
|
element._pyodide.resolve(pyodide);
|
||||||
@@ -165,7 +192,18 @@ const getText = (body) => body.text();
|
|||||||
}
|
}
|
||||||
|
|
||||||
customElements.define("py-script", PyScriptElement);
|
customElements.define("py-script", PyScriptElement);
|
||||||
})();
|
|
||||||
|
export function PyWorker(file, options) {
|
||||||
|
// this propagates pyscript worker hooks without needing a pyscript
|
||||||
|
// bootstrap + it passes arguments and enforces `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.
|
||||||
|
return XWorker.call(new Hook(null, workerHooks), file, {
|
||||||
|
...options,
|
||||||
|
type: "pyodide",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
export const hooks = {
|
export const hooks = {
|
||||||
/** @type {Set<function>} */
|
/** @type {Set<function>} */
|
||||||
|
|||||||
28
pyscript.next/test/worker.html
Normal file
28
pyscript.next/test/worker.html
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<title>PyScript Next</title>
|
||||||
|
<link rel="stylesheet" href="../core.css" />
|
||||||
|
<script type="module">
|
||||||
|
import { PyWorker } from '../core.js';
|
||||||
|
PyWorker('./worker.py'/*, options allowed except `type` */);
|
||||||
|
// the type is overwritten as "pyodide" in PyScript as the module
|
||||||
|
// lives in that env too
|
||||||
|
</script>
|
||||||
|
<script>
|
||||||
|
// this is only to test non-blocking nature/bootstrap
|
||||||
|
addEventListener('DOMContentLoaded', () => {
|
||||||
|
const div = document.body.appendChild(
|
||||||
|
document.createElement('div')
|
||||||
|
);
|
||||||
|
(function monitor() {
|
||||||
|
const date = new Date;
|
||||||
|
div.textContent = `${date.getSeconds()}.${date.getMilliseconds()}`;
|
||||||
|
requestAnimationFrame(monitor);
|
||||||
|
}());
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
</html>
|
||||||
3
pyscript.next/test/worker.py
Normal file
3
pyscript.next/test/worker.py
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
from pyscript import document
|
||||||
|
|
||||||
|
document.body.append("Hello World")
|
||||||
Reference in New Issue
Block a user