10000 Add a "donkey" worker that execs or evaluates all the things (#2210) · pyscript/pyscript@f827efe · GitHub
[go: up one dir, main page]

Skip to content

Commit f827efe

Browse files
Add a "donkey" worker that execs or evaluates all the things (#2210)
* WIP * Add a "donkey" worker that execs or evaluates all the things --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
1 parent 8c6bfec commit f827efe

File tree

10 files changed

+137
-10
lines changed

10 files changed

+137
-10
lines changed

core/package-lock.json

Lines changed: 9 additions & 9 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

core/src/core.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,11 @@ import {
3737
import { stdlib, optional } from "./stdlib.js";
3838
export { stdlib, optional, inputFailure };
3939

40+
export const donkey = (options) =>
41+
import(/* webpackIgnore: true */ "./plugins/donkey.js").then((module) =>
42+
module.default(options),
43+
);
44+
4045
// generic helper to disambiguate between custom element and script
4146
const isScript = ({ tagName }) => tagName === "SCRIPT";
4247

core/src/plugins.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,11 @@ export default {
55
/* webpackIgnore: true */
66
"./plugins/deprecations-manager.js"
77
),
8+
donkey: () =>
9+
import(
10+
/* webpackIgnore: true */
11+
"./plugins/donkey.js"
12+
),
813
error: () =>
914
import(
1015
/* webpackIgnore: true */

core/src/plugins/donkey.js

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
import { assign, dedent } from "polyscript/exports";
2+
3+
const invoke = (name, args) => `${name}(code, ${args.join(", ")})`;
4+
5+
export default (options = {}) => {
6+
const type = options.type || "py";
7+
const args = options.persistent
8+
? ["globals()", "__locals__"]
9+
: ["{}", "{}"];
10+
const src = URL.createObjectURL(
11+
new Blob([
12+
dedent(`
13+
from pyscript import sync, config
14+
__message__ = lambda e,v: f"\x1b[31m\x1b[1m{e.__name__}\x1b[0m: {v}"
15+
__locals__ = {}
16+
if config["type"] == "py":
17+
import sys
18+
def __error__(_):
19+
info = sys.exc_info()
20+
return __message__(info[0], info[1])
21+
else:
22+
__error__ = lambda e: __message__(e.__class__, e.value)
23+
def execute(code):
24+
try: return ${invoke("exec", args)};
25+
except Exception as e: print(__error__(e));
26+
def evaluate(code):
27+
try: return ${invoke("eval", args)};
28+
except Exception as e: print(__error__(e));
29+
sync.execute = execute
30+
sync.evaluate = evaluate
31+
`),
32+
]),
33+
);
34+
35+
const script = assign(document.createElement("script"), { type, src });
36+
37+
script.toggleAttribute("worker", true);
38+
script.toggleAttribute("terminal", true);
39+
if (options.terminal) script.setAttribute("target", options.terminal);
40+
if (options.config)
41+
script.setAttribute("config", JSON.stringify(options.config));
42+
43+
return new Promise((resolve) => {
44+
script.addEventListener(`${type}:done`, (event) => {
45+
event.stopPropagation();
46+
URL.revokeObjectURL(src);
47+
const { xworker, process, terminal } = script;
48+
const { execute, evaluate } = xworker.sync;
49+
script.remove();
50+
resolve({
51+
process,
52+
execute: (code) => execute(dedent(code)),
53+
evaluate: (code) => evaluate(dedent(code)),
54+
clear: () => terminal.clear(),
55+
reset: () => terminal.reset(),
56+
kill: () => {
57+
xworker.terminate();
58+
terminal.dispose();
59+
},
60+
});
61+
});
62+
document.body.append(script);
63+
});
64+
};

core/tests/index.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,5 +14,5 @@
1414
a:hover { opacity: 1; }
1515
</style>
1616
</head>
17-
<body><ul><li><strong><span>javascript</span></strong><ul><li><a href="./javascript/async-listener.html">async-listener<small>.html</small></a></li><li><a href="./javascript/config-url.html">config-url<small>.html</small></a></li><li><a href="./javascript/config_type.html">config_type<small>.html</small></a></li><li><strong><a href="./javascript/fetch/index.html">fetch</a></strong></li><li><a href="./javascript/ffi.html">ffi<small>.html</small></a></li><li><a href="./javascript/hooks.html">hooks<small>.html</small></a></li><li><strong><a href="./javascript/issue-2093/index.html">issue-2093</a></strong></li><li><a href="./javascript/js-storage.html">js-storage<small>.html</small></a></li><li><a href="./javascript/js_modules.html">js_modules<small>.html</small></a></li><li><strong><a href="./javascript/loader/index.html">loader</a></strong></li><li><a href="./javascript/mpy.html">mpy<small>.html</small></a></li><li><a href="./javascript/py-terminal-main.html">py-terminal-main<small>.html</small></a></li><li><a href="./javascript/py-terminal-worker.html">py-terminal-worker<small>.html</small></a></li><li><a href="./javascript/py-terminal.html">py-terminal<small>.html</small></a></li><li><a href="./javascript/py-terminals.html">py-terminals<small>.html</small></a></li><li><a href="./javascript/storage.html">storage<small>.html</small></a></li><li><strong><a href="./javascript/workers/index.html">workers</a></strong><ul><li><a href="./javascript/workers/named.html">named<small>.html</small></a></li></ul></li></ul></li><li><strong><a href="./manual/index.html">manual</a></strong><ul><li><a href="./manual/all-done.html">all-done<small>.html</small></a></li><li><a href="./manual/async.html">async<small>.html</small></a></li><li><a href="./manual/camera.html">camera<small>.html</small></a></li><li><a href="./manual/click.html">click<small>.html</small></a></li><li><a href="./manual/code-a-part.html">code-a-part<small>.html</small></a></li><li><a href="./manual/combo.html">combo<small>.html</small></a></li><li><a href="./manual/config.html">config<small>.html</small></a></li><li><a href="./manual/create-element.html">create-element<small>.html</small></a></li><li><a href="./manual/dialog.html">dialog<small>.html</small></a></li><li><a href="./manual/display.html">display<small F438 >.html</small></a></li><li><a href="./manual/error.html">error<small>.html</small></a></li><li><a href="./manual/html-decode.html">html-decode<small>.html</small></a></li><li><a href="./manual/input.html">input<small>.html</small></a></li><li><a href="./manual/interpreter.html">interpreter<small>.html</small></a></li><li><strong><a href="./manual/issue-7015/index.html">issue-7015</a></strong></li><li><a href="./manual/multi.html">multi<small>.html</small></a></li><li><a href="./manual/multiple-editors.html">multiple-editors<small>.html</small></a></li><li><a href="./manual/no-error.html">no-error<small>.html</small></a></li><li><strong><a href="./manual/no_sab/index.html">no_sab</a></strong></li><li><strong><a href="./manual/piratical/index.html">piratical</a></strong></li><li><a href="./manual/py-editor.html">py-editor<small>.html</small></a></li><li><a href="./manual/py-editor-failure.html">py-editor-failure<small>.html</small></a></li><li><strong><a href="./manual/py-terminals/index.html">py-terminals</a></strong><ul><li><a href="./manual/py-terminals/no-repl.html">no-repl<small>.html</small></a></li><li><a href="./manual/py-terminals/repl.html">repl<small>.html</small></a></li></ul></li><li><a href="./manual/py_modules.html">py_modules<small>.html</small></a></li><li><strong><a href="./manual/service-worker/index.html">service-worker</a></strong></li><li><a href="./manual/split-config.html">split-config<small>.html</small></a></li><li><a href="./manual/submit.html">submit<small>.html</small></a></li><li><a href="./manual/target.html">target<small>.html</small></a></li><li><a href="./manual/test_display_HTML.html">test_display_HTML<small>.html</small></a></li><li><a href="./manual/test_when.html">test_when<small>.html</small></a></li><li><a href="./manual/worker.html">worker<small>.html</small></a></li></ul></li><li><strong><a href="./python/index.html">python</a></strong></li></ul></body>
17+
<body><ul><li><strong><span>javascript</span></strong><ul><li><a href="./javascript/async-listener.html">async-listener<small>.html</small></a></li><li><a href="./javascript/config-url.html">config-url<small>.html</small></a></li><li><a href="./javascript/config_type.html">config_type<small>.html</small></a></li><li><strong><a href="./javascript/fetch/index.html">fetch</a></strong></li><li><a href="./javascript/ffi.html">ffi<small>.html</small></a></li><li><a href="./javascript/hooks.html">hooks<small>.html</small></a></li><li><strong><a href="./javascript/issue-2093/index.html">issue-2093</a></strong></li><li><a href="./javascript/js-storage.html">js-storage<small>.html</small></a></li><li><a href="./javascript/js_modules.html">js_modules<small>.html</small></a></li><li><strong><a href="./javascript/loader/index.html">loader</a></strong></li><li><a href="./javascript/mpy.html">mpy<small>.html</small></a></li><li><a href="./javascript/py-terminal-main.html">py-terminal-main<small>.html</small></a></li><li><a href="./javascript/py-terminal-worker.html">py-terminal-worker<small>.html</small></a></li><li><a href="./javascript/py-terminal.html">py-terminal<small>.html</small></a></li><li><a href="./javascript/py-terminals.html">py-terminals<small>.html</small></a></li><li><a href="./javascript/storage.html">storage<small>.html</small></a></li><li><strong><a href="./javascript/workers/index.html">workers</a></strong><ul><li><a href="./javascript/workers/named.html">named<small>.html</small></a></li></ul></li></ul></li><li><strong><a href="./manual/index.html">manual</a></strong><ul><li><a href="./manual/all-done.html">all-done<small>.html</small></a></li><li><a href="./manual/async.html">async<small>.html</small></a></li><li><a href="./manual/camera.html">camera<small>.html</small></a></li><li><a href="./manual/click.html">click<small>.html</small></a></li><li><a href="./manual/code-a-part.html">code-a-part<small>.html</small></a></li><li><a href="./manual/combo.html">combo<small>.html</small></a></li><li><a href="./manual/config.html">config<small>.html</small></a></li><li><a href="./manual/create-element.html">create-element<small>.html</small></a></li><li><a href="./manual/dialog.html">dialog<small>.html</small></a></li><li><a href="./manual/display.html">display<small>.html</small></a></li><li><strong><a href="./manual/donkey/index.html">donkey</a></strong></li><li><a href="./manual/error.html">error<small>.html</small></a></li><li><a href="./manual/html-decode.html">html-decode<small>.html</small></a></li><li><a href="./manual/input.html">input<small>.html</small></a></li><li><a href="./manual/interpreter.html">interpreter<small>.html</small></a></li><li><strong><a href="./manual/issue-7015/index.html">issue-7015</a></strong></li><li><a href="./manual/multi.html">multi<small>.html</small></a></li><li><a href="./manual/multiple-editors.html">multiple-editors<small>.html</small></a></li><li><a href="./manual/no-error.html">no-error<small>.html</small></a></li><li><strong><a href="./manual/no_sab/index.html">no_sab</a></strong></li><li><strong><a href="./manual/piratical/index.html">piratical</a></strong></li><li><a href="./manual/py-editor.html">py-editor<small>.html</small></a></li><li><a href="./manual/py-editor-failure.html">py-editor-failure<small>.html</small></a></li><li><strong><a href="./manual/py-terminals/index.html">py-terminals</a></strong><ul><li><a href="./manual/py-terminals/no-repl.html">no-repl<small>.html</small></a></li><li><a href="./manual/py-terminals/repl.html">repl<small>.html</small></a></li></ul></li><li><a href="./manual/py_modules.html">py_modules<small>.html</small></a></li><li><strong><a href="./manual/service-worker/index.html">service-worker</a></strong></li><li><a href="./manual/split-config.html">split-config<small>.html</small></a></li><li><a href="./manual/submit.html">submit<small>.html</small></a></li><li><a href="./manual/target.html">target<small>.html</small></a></li><li><a href="./manual/test_display_HTML.html">test_display_HTML<small>.html</small></a></li><li><a href="./manual/test_when.html">test_when<small>.html</small></a></li><li><a href="./manual/worker.html">worker<small>.html</small></a></li></ul></li><li><strong><a href="./python/index.html">python</a></strong></li></ul></body>
1818
</html>

core/tests/manual/donkey/index.html

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<meta charset="utf-8">
5+
<meta name="viewport" content="width=device-width,initial-scale=1">
6+
<link rel="stylesheet" href="../../../dist/core.css" />
7+
<script type="module" src="./index.js"></script>
8+
</head>
9+
<body>
10+
<div id="container"></div>
11+
<button id="run" disabled>Run</button>
12+
<button id="clear" disabled>Clear</button>
13+
<button id="kill" disabled>Kill</button>
14+
</body>
15+
</html>

core/tests/manual/donkey/index.js

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import { donkey } from '../../../dist/core.js';
2+
3+
const runButton = document.querySelector('#run');
4+
const clearButton = document.querySelector('#clear');
5+
const killButton = document.querySelector('#kill');
6+
7+
const {
8+
execute, // exec(expression)
9+
evaluate, // eval(expression)
10+
process, // process(code)
11+
clear,
12+
kill,
13+
} = await donkey({ terminal: '#container' });
14+
15+
clearButton.onclick = clear;
16+
killButton.onclick = kill;
17+
18+
runButton.disabled = false;
19+
runButton.onclick = async () => {
20+
killButton.disabled = false;
21+
clearButton.disabled = true;
22+
runButton.disabled = true;
23+
// multiline code
24+
await execute(`
25+
a = 1 + 2
26+
print(f'1 + 2 = {a}')
27+
`);
28+
// single expression evaluation
29+
const name = await evaluate('input("what is your name? ")');
30+
alert(`Hello ${name}`);
31+
killButton.disabled = true;
32+
clearButton.disabled = false;
33+
runButton.disabled = false;
34+
};

core/types/core.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
export function donkey(options: any): Promise<any>;
12
export function offline_interpreter(config: any): string;
23
import { stdlib } from "./stdlib.js";
34
import { optional } from "./stdlib.js";

core/types/plugins.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
declare const _default: {
22
"deprecations-manager": () => Promise<typeof import("./plugins/deprecations-manager.js")>;
3+
donkey: () => Promise<typeof import("./plugins/donkey.js")>;
34
error: () => Promise<typeof import("./plugins/error.js")>;
45
"py-editor": () => Promise<typeof import("./plugins/py-editor.js")>;
56
"py-terminal": () => Promise<typeof import("./plugins/py-terminal.js")>;

core/types/plugins/donkey.d.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
declare function _default(options?: {}): Promise<any>;
2+
export default _default;

0 commit comments

Comments
 (0)
0