10000 Merge pull request #28 from anaconda/pys-19/allow_out_err_redirect · Positive-Conative/pyscript@a612b64 · GitHub
[go: up one dir, main page]

Skip to content

Commit a612b64

Browse files
authored
Merge pull request pyscript#28 from anaconda/pys-19/allow_out_err_redirect
[PYS-19] allow out err redirect
2 parents 6525faf + 9e47644 commit a612b64

11 files changed

+330
-209
lines changed

pyscriptjs/examples/bokeh.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
<h1>Bokeh Example</h1>
2424
<div id="myplot"></div>
2525

26-
<py-script>
26+
<py-script id="main">
2727
import json
2828
import pyodide
2929

pyscriptjs/examples/bokeh_interactive.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
<h1>Bokeh Example</h1>
2424
<div id="myplot"></div>
2525

26-
<py-script>
26+
<py-script id="main">
2727
import asyncio
2828
import json
2929
import pyodide

pyscriptjs/examples/repl2.html

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,12 @@
2020
</py-env>
2121

2222
<body>
23+
<h1 class="font-semibold text-2xl ml-5">Custom REPL</h1>
2324
<py-box widths="2/3;1/3">
24-
<py-repl id="my-repl" auto-generate="true" target="output"> </py-repl>
25+
<py-repl id="my-repl" auto-generate="true" std-out="output" std-err="err-div"> </py-repl>
2526
<div id="output"></div>
2627
</py-box>
28+
<footer id="err-div" class="bg-red-700 text-white text-center border-t-4 border-gree-500 fixed inset-x-0 bottom-0 p-4 hidden">
29+
</footer>
2730
</body>
2831
</html>

pyscriptjs/examples/simple_script.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414

1515
<body>
1616
<div id="outputDiv" class="font-mono" style="background-color:yellow"></div>
17-
<py-script target="outputDiv">
17+
<py-script output="outputDiv">
1818
from datetime import datetime
1919
now = datetime.now()
2020
now.strftime("%m/%d/%Y, %H:%M:%S")

pyscriptjs/examples/simple_script2.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
<div class="font-mono">start time: <label id="outputDiv"></label></div>
2121
<div id="outputDiv2" class="font-mono"></div>
2222
<div id="outputDiv3" class="font-mono"></div>
23-
<py-script target="outputDiv">
23+
<py-script output="outputDiv">
2424
import utils
2525
utils.now()
2626
</py-script>

pyscriptjs/src/components/base.ts

Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
import { pyodideLoaded, loadedEnvironments, componentDetailsNavOpen, mode } from '../stores';
2+
3+
// Premise used to connect to the first available pyodide interpreter
4+
let pyodideReadyPromise;
5+
let environments;
6+
let currentMode;
7+
let Element;
8+
9+
pyodideLoaded.subscribe(value => {
10+
pyodideReadyPromise = value;
11+
});
12+
loadedEnvironments.subscribe(value => {
13+
environments = value;
14+
});
15+
16+
let propertiesNavOpen;
17+
componentDetailsNavOpen.subscribe(value => {
18+
propertiesNavOpen = value;
19+
});
20+
21+
mode.subscribe(value => {
22+
currentMode = value;
23+
});
24+
25+
// TODO: use type declaractions
26+
type PyodideInterface = {
27+
registerJsModule(name: string, module: object): void
28+
}
29+
30+
31+
export class BaseEvalElement extends HTMLElement {
32+
shadow: ShadowRoot;
33+
wrapper: HTMLElement;
34+
code: string;
35+
source: string;
36+
btnConfig: HTMLElement;
37+
btnRun: HTMLElement;
38+
outputElement: HTMLElement;
39+
errorElement: HTMLElement;
40+
theme: string;
41+
42+
constructor() {
43+
super();
44+
45+
// attach shadow so we can preserve the element original innerHtml content
46+
this.shadow = this.attachShadow({ mode: 'open'});
47+
this.wrapper = document.createElement('slot');
48+
this.shadow.appendChild(this.wrapper);
49+
}
50+
51+
addToOutput(s: string) {
52+
this.outputElement.innerHTML += "<div>"+s+"</div>";
53+
this.outputElement.hidden = false;
54+
}
55+
56+
postEvaluate(){
57+
58+
}
59+
60+
getSourceFromElement(): string{
61+
return "";
62+
}
63+
64+
async getSourceFromFile(s: string): Promise<string>{
65+
let pyodide = await pyodideReadyPromise;
66+
let response = await fetch(s);
67+
this.code = await response.text();
68+
return this.code;
69+
}
70+
71+
protected async _register_esm(pyodide: PyodideInterface): Promise<void> {
72+
const imports: {[key: string]: unknown} = {}
73+
74+
for (const node of document.querySelectorAll("script[type='importmap']")) {
75+
const importmap = (() => {
76+
try {
77+
return JSON.parse(node.textContent)
78+
} catch {
79+
return null
80+
}
81+
})()
82+
83+
if (importmap?.imports == null)
84+
continue
85+
86+
for (const [name, url] of Object.entries(importmap.imports)) {
87+
if (typeof name != "string" || typeof url != "string")
88+
continue
89+
90+
try {
91+
// XXX: pyodide doesn't like Module(), failing with
92+
// "can't read 'name' of undefined" at import time
93+
imports[name] = {...await import(url)}
94+
} catch {
95+
console.error(`failed to fetch '${url}' for '${name}'`)
96+
}
97+
}
98+
}
99+
100+
pyodide.registerJsModule("esm", imports)
101+
}
102+
103+
async evaluate(): Promise<void> {
104+
console.log('evaluate');
105+
let pyodide = await pyodideReadyPromise;
106+
let source: string;
107+
let output;
108+
try {
109+
// @ts-ignore
110+
if (this.source){
111+
source = await this.getSourceFromFile(this.source);
112+
}else{
113+
source = this.getSourceFromElement();
114+
}
115+
116+
await this._register_esm(pyodide);
117+
118+
if (source.includes("asyncio")){
119+
await pyodide.runPythonAsync(`output_manager.change("`+this.outputElement.id+`", "`+this.errorElement.id+`")`);
120+
output = await pyodide.runPythonAsync(source);
121+
await pyodide.runPythonAsync(`output_manager.revert()`)
122+
}else{
123+
output = pyodide.runPython(`output_manager.change("`+this.outputElement.id+`", "`+this.errorElement.id+`")`);
124+
output = pyodide.runPython(source);
125+
pyodide.runPython(`output_manager.revert()`)
126+
}
127+
128+
if (output !== undefined){
129+
if (Element === undefined){
130+
Element = pyodide.globals.get('Element');
131+
}
132+
const out = Element(this.outputElement.id);
133+
// @ts-ignore
134+
out.write.callKwargs(output, { append : true});
135+
136+
this.outputElement.hidden = false;
137+
this.outputElement.style.display = 'block';
138+
}
139+
140+
this.postEvaluate()
141+
142+
} catch (err) {
143+
if (Element === undefined){
144+
Element = pyodide.globals.get('Element');
145+
}
146+
const out = Element(this.errorElement.id);
147+
// @ts-ignore
148+
out.write.callKwargs(err, { append : true});
149+
this.errorElement.hidden = false;
150+
this.errorElement.style.display = 'block';
151+
}
152+
}
153+
}

pyscriptjs/src/components/pybox.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ export class PyBox extends HTMLElement {
5858

5959
for (let i in this.widths) {
6060
// @ts-ignore
61-
addClasses(mainDiv.childNodes[parseInt(i)], [this.widths[i]]);
61+
addClasses(mainDiv.childNodes[parseInt(i)], [this.widths[i], 'mx-4']);
6262
}
6363

6464
this.appendChild(mainDiv);

0 commit comments

Comments
 (0)
0