mirror of
https://github.com/pyscript/pyscript.git
synced 2025-12-19 18:27:29 -05:00
Added py:all-done event (#1756)
This commit is contained in:
committed by
GitHub
parent
b9a1227e47
commit
3ac2ac0982
50
pyscript.core/package-lock.json
generated
50
pyscript.core/package-lock.json
generated
@@ -1,17 +1,17 @@
|
||||
{
|
||||
"name": "@pyscript/core",
|
||||
"version": "0.2.3",
|
||||
"version": "0.2.4",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@pyscript/core",
|
||||
"version": "0.2.3",
|
||||
"version": "0.2.4",
|
||||
"license": "APACHE-2.0",
|
||||
"dependencies": {
|
||||
"@ungap/with-resolvers": "^0.1.0",
|
||||
"basic-devtools": "^0.1.6",
|
||||
"polyscript": "^0.4.2"
|
||||
"polyscript": "^0.4.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@rollup/plugin-node-resolve": "^15.2.1",
|
||||
@@ -49,9 +49,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@eslint-community/regexpp": {
|
||||
"version": "4.8.1",
|
||||
"resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.8.1.tgz",
|
||||
"integrity": "sha512-PWiOzLIUAjN/w5K17PoF4n6sKBw0gqLHPhywmYHP4t1VFQQVYeb1yWsJwnMVEMl3tUHME7X/SJPZLmtG7XBDxQ==",
|
||||
"version": "4.8.2",
|
||||
"resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.8.2.tgz",
|
||||
"integrity": "sha512-0MGxAVt1m/ZK+LTJp/j0qF7Hz97D9O/FH9Ms3ltnyIdDD57cbb1ACIQTkbHvNXtWDv5TPq7w5Kq56+cNukbo7g==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": "^12.0.0 || ^14.0.0 || >=16.0.0"
|
||||
@@ -851,9 +851,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/electron-to-chromium": {
|
||||
"version": "1.4.528",
|
||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.528.tgz",
|
||||
"integrity": "sha512-UdREXMXzLkREF4jA8t89FQjA8WHI6ssP38PMY4/4KhXFQbtImnghh4GkCgrtiZwLKUKVD2iTVXvDVQjfomEQuA==",
|
||||
"version": "1.4.529",
|
||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.529.tgz",
|
||||
"integrity": "sha512-6uyPyXTo8lkv8SWAmjKFbG42U073TXlzD4R8rW3EzuznhFS2olCIAfjjQtV2dV2ar/vRF55KUd3zQYnCB0dd3A==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/entities": {
|
||||
@@ -1278,15 +1278,6 @@
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/import-fresh/node_modules/resolve-from": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
|
||||
"integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/import-from": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/import-from/-/import-from-3.0.0.tgz",
|
||||
@@ -1299,6 +1290,15 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/import-from/node_modules/resolve-from": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz",
|
||||
"integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/imurmurhash": {
|
||||
"version": "0.1.4",
|
||||
"resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
|
||||
@@ -1776,9 +1776,9 @@
|
||||
"integrity": "sha512-yyVAOFKTAElc7KdLt2+UKGExNYwYb/Y/WE9i+1ezCQsJE8gbKSjewfpRqK2nQgZ4d4hhAAGgDCOcIZVilqE5UA=="
|
||||
},
|
||||
"node_modules/polyscript": {
|
||||
"version": "0.4.2",
|
||||
"resolved": "https://registry.npmjs.org/polyscript/-/polyscript-0.4.2.tgz",
|
||||
"integrity": "sha512-3mM5Y/DdpYND8/INAUmgF5VL4InVc04xADB+of129t8RjXi3eZK4xoGRPZdTYzW+wM56WNptnC8fC9Zt7jKLoA==",
|
||||
"version": "0.4.6",
|
||||
"resolved": "https://registry.npmjs.org/polyscript/-/polyscript-0.4.6.tgz",
|
||||
"integrity": "sha512-yRL8iwa8NHCWYIkYIRZ7Ujwd69WaDKAoeFxhQRLkTmcdlKKFxoFJStwyb5PONWZUl+mb+oXGkrPPsRaAJHHipQ==",
|
||||
"dependencies": {
|
||||
"@ungap/structured-clone": "^1.2.0",
|
||||
"@ungap/with-resolvers": "^0.1.0",
|
||||
@@ -2421,12 +2421,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/resolve-from": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz",
|
||||
"integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==",
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
|
||||
"integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/reusify": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@pyscript/core",
|
||||
"version": "0.2.3",
|
||||
"version": "0.2.4",
|
||||
"type": "module",
|
||||
"description": "PyScript",
|
||||
"module": "./index.js",
|
||||
@@ -33,7 +33,7 @@
|
||||
"dependencies": {
|
||||
"@ungap/with-resolvers": "^0.1.0",
|
||||
"basic-devtools": "^0.1.6",
|
||||
"polyscript": "^0.4.2"
|
||||
"polyscript": "^0.4.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@rollup/plugin-node-resolve": "^15.2.1",
|
||||
|
||||
62
pyscript.core/src/all-done.js
Normal file
62
pyscript.core/src/all-done.js
Normal file
@@ -0,0 +1,62 @@
|
||||
import TYPES from "./types.js";
|
||||
import hooks from "./hooks.js";
|
||||
|
||||
const DONE = "py:all-done";
|
||||
|
||||
const {
|
||||
onAfterRun,
|
||||
onAfterRunAsync,
|
||||
codeAfterRunWorker,
|
||||
codeAfterRunWorkerAsync,
|
||||
} = hooks;
|
||||
|
||||
const waitForIt = [];
|
||||
const codes = [];
|
||||
|
||||
const codeFor = (element) => {
|
||||
const isAsync = element.hasAttribute("async");
|
||||
const { promise, resolve } = Promise.withResolvers();
|
||||
const type = `${DONE}:${waitForIt.push(promise)}`;
|
||||
|
||||
// resolve each promise once notified
|
||||
addEventListener(type, resolve, { once: true });
|
||||
|
||||
if (element.hasAttribute("worker")) {
|
||||
const code = `
|
||||
from pyscript import window as _w
|
||||
_w.dispatchEvent(_w.Event.new("${type}"))
|
||||
`;
|
||||
if (isAsync) codeAfterRunWorkerAsync.add(code);
|
||||
else codeAfterRunWorker.add(code);
|
||||
return code;
|
||||
}
|
||||
|
||||
// dispatch only once the ready element is the same
|
||||
const code = (_, el) => {
|
||||
if (el === element) dispatchEvent(new Event(type));
|
||||
};
|
||||
|
||||
if (isAsync) onAfterRunAsync.add(code);
|
||||
else onAfterRun.add(code);
|
||||
return code;
|
||||
};
|
||||
|
||||
const selector = [];
|
||||
for (const [TYPE] of TYPES)
|
||||
selector.push(`script[type="${TYPE}"]`, `${TYPE}-script`);
|
||||
|
||||
// loop over all known scripts and elements
|
||||
for (const element of document.querySelectorAll(selector.join(",")))
|
||||
codes.push(codeFor(element));
|
||||
|
||||
// wait for all the things then cleanup
|
||||
Promise.all(waitForIt).then(() => {
|
||||
// cleanup unnecessary hooks
|
||||
for (const code of codes) {
|
||||
onAfterRun.delete(code);
|
||||
onAfterRunAsync.delete(code);
|
||||
codeAfterRunWorker.delete(code);
|
||||
codeAfterRunWorkerAsync.delete(code);
|
||||
}
|
||||
dispatchEvent(new Event(DONE));
|
||||
});
|
||||
@@ -1,16 +1,21 @@
|
||||
/*! (c) PyScript Development Team */
|
||||
|
||||
import "@ungap/with-resolvers";
|
||||
import { INVALID_CONTENT, define, XWorker } from "polyscript";
|
||||
|
||||
// TODO: this is not strictly polyscript related but handy ... not sure
|
||||
// we should factor this utility out a part but this works anyway.
|
||||
// These imports can hook more than usual and help debugging possible polyscript issues
|
||||
import {
|
||||
INVALID_CONTENT,
|
||||
define,
|
||||
XWorker,
|
||||
} from "../node_modules/polyscript/esm/index.js";
|
||||
import { queryTarget } from "../node_modules/polyscript/esm/script-handler.js";
|
||||
import { dedent, dispatch } from "../node_modules/polyscript/esm/utils.js";
|
||||
import { Hook } from "../node_modules/polyscript/esm/worker/hooks.js";
|
||||
|
||||
import "./all-done.js";
|
||||
import TYPES from "./types.js";
|
||||
import configs from "./config.js";
|
||||
import hooks from "./hooks.js";
|
||||
import sync from "./sync.js";
|
||||
import stdlib from "./stdlib.js";
|
||||
import { ErrorCode } from "./exceptions.js";
|
||||
@@ -66,28 +71,6 @@ const registerModule = ({ XWorker: $XWorker, interpreter, io }) => {
|
||||
interpreter.runPython(stdlib, { globals: interpreter.runPython("{}") });
|
||||
};
|
||||
|
||||
export const hooks = {
|
||||
/** @type {Set<function>} */
|
||||
onBeforeRun: new Set(),
|
||||
/** @type {Set<function>} */
|
||||
onBeforeRunAsync: new Set(),
|
||||
/** @type {Set<function>} */
|
||||
onAfterRun: new Set(),
|
||||
/** @type {Set<function>} */
|
||||
onAfterRunAsync: new Set(),
|
||||
/** @type {Set<function>} */
|
||||
onInterpreterReady: new Set(),
|
||||
|
||||
/** @type {Set<string>} */
|
||||
codeBeforeRunWorker: new Set(),
|
||||
/** @type {Set<string>} */
|
||||
codeBeforeRunWorkerAsync: new Set(),
|
||||
/** @type {Set<string>} */
|
||||
codeAfterRunWorker: new Set(),
|
||||
/** @type {Set<string>} */
|
||||
codeAfterRunWorkerAsync: new Set(),
|
||||
};
|
||||
|
||||
const workerHooks = {
|
||||
codeBeforeRunWorker: () =>
|
||||
[stdlib, ...hooks.codeBeforeRunWorker].map(dedent).join("\n"),
|
||||
@@ -100,7 +83,7 @@ const workerHooks = {
|
||||
};
|
||||
|
||||
const exportedConfig = {};
|
||||
export { exportedConfig as config };
|
||||
export { exportedConfig as config, hooks };
|
||||
|
||||
for (const [TYPE, interpreter] of TYPES) {
|
||||
const { config, plugins, error } = configs.get(TYPE);
|
||||
|
||||
21
pyscript.core/src/hooks.js
Normal file
21
pyscript.core/src/hooks.js
Normal file
@@ -0,0 +1,21 @@
|
||||
export default {
|
||||
/** @type {Set<function>} */
|
||||
onBeforeRun: new Set(),
|
||||
/** @type {Set<function>} */
|
||||
onBeforeRunAsync: new Set(),
|
||||
/** @type {Set<function>} */
|
||||
onAfterRun: new Set(),
|
||||
/** @type {Set<function>} */
|
||||
onAfterRunAsync: new Set(),
|
||||
/** @type {Set<function>} */
|
||||
onInterpreterReady: new Set(),
|
||||
|
||||
/** @type {Set<string>} */
|
||||
codeBeforeRunWorker: new Set(),
|
||||
/** @type {Set<string>} */
|
||||
codeBeforeRunWorkerAsync: new Set(),
|
||||
/** @type {Set<string>} */
|
||||
codeAfterRunWorker: new Set(),
|
||||
/** @type {Set<string>} */
|
||||
codeAfterRunWorkerAsync: new Set(),
|
||||
};
|
||||
39
pyscript.core/test/all-done.html
Normal file
39
pyscript.core/test/all-done.html
Normal file
@@ -0,0 +1,39 @@
|
||||
<!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 '../dist/core.js';
|
||||
|
||||
document.body.append('loading ...', document.createElement('br'));
|
||||
|
||||
addEventListener(
|
||||
'py:all-done',
|
||||
() => {
|
||||
document.body.append('all executed');
|
||||
},
|
||||
{ once: true }
|
||||
);
|
||||
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<script type="py">
|
||||
print(1)
|
||||
</script>
|
||||
<py-script>
|
||||
print(2)
|
||||
</py-script>
|
||||
<py-script async>
|
||||
print(3)
|
||||
</py-script>
|
||||
<script type="py" worker>
|
||||
print(4)
|
||||
</script>
|
||||
<py-script async worker>
|
||||
print(5)
|
||||
</py-script>
|
||||
</body>
|
||||
</html>
|
||||
31
pyscript.core/test/dialog.html
Normal file
31
pyscript.core/test/dialog.html
Normal file
@@ -0,0 +1,31 @@
|
||||
<!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="../dist/core.css">
|
||||
<script type="module" src="../dist/core.js"></script>
|
||||
<script type="module">
|
||||
const loader = document.querySelector('#loader');
|
||||
loader.showModal();
|
||||
addEventListener(
|
||||
'py:all-done',
|
||||
() => {
|
||||
loader.close();
|
||||
},
|
||||
{ once: true }
|
||||
);
|
||||
</script>
|
||||
<script type="py">
|
||||
from pyscript import document
|
||||
|
||||
document.body.textContent = "PyScript Ready";
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<dialog id="loader">
|
||||
Loading PyScript ...
|
||||
</dialog>
|
||||
</body>
|
||||
</html>
|
||||
@@ -20,8 +20,10 @@ class TestBasic(PyScriptTest):
|
||||
</py-script>
|
||||
"""
|
||||
)
|
||||
assert self.console.log.lines == ["hello from script py",
|
||||
"hello from py-script"]
|
||||
assert self.console.log.lines == [
|
||||
"hello from script py",
|
||||
"hello from py-script",
|
||||
]
|
||||
|
||||
def test_execution_thread(self):
|
||||
self.pyscript_run(
|
||||
@@ -162,10 +164,12 @@ class TestBasic(PyScriptTest):
|
||||
|
||||
"""
|
||||
)
|
||||
assert self.console.log.lines[-4:] == ["A true false",
|
||||
assert self.console.log.lines[-4:] == [
|
||||
"A true false",
|
||||
"B <div></div>",
|
||||
"C true false",
|
||||
"D <div></div>"]
|
||||
"D <div></div>",
|
||||
]
|
||||
|
||||
def test_packages(self):
|
||||
self.pyscript_run(
|
||||
@@ -346,10 +350,15 @@ class TestBasic(PyScriptTest):
|
||||
)
|
||||
pyscript_tag = self.page.locator("py-script")
|
||||
assert pyscript_tag.inner_html() == ""
|
||||
assert pyscript_tag.evaluate("node => node.srcCode") == 'print("hello from py-script")'
|
||||
assert (
|
||||
pyscript_tag.evaluate("node => node.srcCode")
|
||||
== 'print("hello from py-script")'
|
||||
)
|
||||
script_py_tag = self.page.locator('script[type="py"]')
|
||||
assert script_py_tag.evaluate("node => node.srcCode") == 'print("hello from script py")'
|
||||
|
||||
assert (
|
||||
script_py_tag.evaluate("node => node.srcCode")
|
||||
== 'print("hello from script py")'
|
||||
)
|
||||
|
||||
def test_py_attribute_without_id(self):
|
||||
self.pyscript_run(
|
||||
@@ -366,3 +375,20 @@ class TestBasic(PyScriptTest):
|
||||
self.wait_for_console("hello world!")
|
||||
assert self.console.log.lines[-1] == "hello world!"
|
||||
assert self.console.error.lines == []
|
||||
|
||||
def test_py_all_done_event(self):
|
||||
self.pyscript_run(
|
||||
"""
|
||||
<script>
|
||||
addEventListener("py:all-done", () => console.log("2"))
|
||||
</script>
|
||||
<script type="py">
|
||||
print("1")
|
||||
</script>
|
||||
"""
|
||||
)
|
||||
btn = self.page.wait_for_selector("button")
|
||||
btn.click()
|
||||
self.wait_for_console("1")
|
||||
assert self.console.log.lines[-1] == "2"
|
||||
assert self.console.error.lines == []
|
||||
|
||||
1
pyscript.core/types/all-done.d.ts
vendored
Normal file
1
pyscript.core/types/all-done.d.ts
vendored
Normal file
@@ -0,0 +1 @@
|
||||
export {};
|
||||
14
pyscript.core/types/core.d.ts
vendored
14
pyscript.core/types/core.d.ts
vendored
@@ -10,17 +10,7 @@ export function PyWorker(file: string, options?: {
|
||||
}): Worker & {
|
||||
sync: ProxyHandler<object>;
|
||||
};
|
||||
export namespace hooks {
|
||||
let onBeforeRun: Set<Function>;
|
||||
let onBeforeRunAsync: Set<Function>;
|
||||
let onAfterRun: Set<Function>;
|
||||
let onAfterRunAsync: Set<Function>;
|
||||
let onInterpreterReady: Set<Function>;
|
||||
let codeBeforeRunWorker: Set<string>;
|
||||
let codeBeforeRunWorkerAsync: Set<string>;
|
||||
let codeAfterRunWorker: Set<string>;
|
||||
let codeAfterRunWorkerAsync: Set<string>;
|
||||
}
|
||||
export { exportedConfig as config };
|
||||
import sync from "./sync.js";
|
||||
declare const exportedConfig: {};
|
||||
import hooks from "./hooks.js";
|
||||
export { exportedConfig as config, hooks };
|
||||
|
||||
12
pyscript.core/types/hooks.d.ts
vendored
Normal file
12
pyscript.core/types/hooks.d.ts
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
declare namespace _default {
|
||||
let onBeforeRun: Set<Function>;
|
||||
let onBeforeRunAsync: Set<Function>;
|
||||
let onAfterRun: Set<Function>;
|
||||
let onAfterRunAsync: Set<Function>;
|
||||
let onInterpreterReady: Set<Function>;
|
||||
let codeBeforeRunWorker: Set<string>;
|
||||
let codeBeforeRunWorkerAsync: Set<string>;
|
||||
let codeAfterRunWorker: Set<string>;
|
||||
let codeAfterRunWorkerAsync: Set<string>;
|
||||
}
|
||||
export default _default;
|
||||
Reference in New Issue
Block a user