Skip to content

Commit a61d4b2

Browse files
committed
Improve the py<->js notebook example
1 parent 34237ec commit a61d4b2

File tree

5 files changed

+100
-48
lines changed

5 files changed

+100
-48
lines changed

wasm/notebook/snippets/python-js-css/javascript.txt

Lines changed: 30 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,23 +3,41 @@
33
injectPython({
44
// injectPython functions take the positional arguments as
55
// normal function args, and kwargs as the `this` variable
6-
add_text_input(buttonText, callback) {
6+
add_text_input() {
77
const input = document.createElement('input');
88
pushNotebook(input);
9+
return () => input.value;
10+
},
11+
add_button(buttonText, cb) {
12+
const do_button = (callback) => {
13+
const btn = document.createElement('button');
14+
btn.innerHTML = buttonText;
15+
btn.addEventListener('click', () => {
16+
try {
17+
// python functions passed to js have a signature
18+
// of ([args...], {kwargs...}) => any
19+
callback([], {});
20+
} catch (err) {
21+
// puts the traceback in the error box
22+
handlePyError(err);
23+
}
24+
});
25+
pushNotebook(btn);
26+
};
927

10-
const btn = document.createElement('button');
11-
btn.innerHTML = buttonText;
12-
btn.addEventListener('click', () => {
13-
resultDiv.innerHTML = '';
14-
// python functions passed to js have a signature
15-
// of ([args...], {kwargs...}) => any
16-
const output = callback([input.value], {});
17-
resultDiv.innerHTML += output;
18-
});
19-
pushNotebook(btn);
20-
28+
if (cb == null) {
29+
// to allow using as a decorator
30+
return do_button;
31+
} else {
32+
do_button(cb);
33+
}
34+
},
35+
add_output() {
2136
const resultDiv = document.createElement('div');
2237
resultDiv.classList.add('result');
2338
pushNotebook(resultDiv);
39+
return (value) => {
40+
resultDiv.innerHTML = value;
41+
};
2442
},
2543
});

wasm/notebook/snippets/python-js-css/main.txt

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,12 @@ In this demo example, the RustPython Notebook:
3232
h2("Calculator")
3333
h3("Enter your lucky number")
3434

35-
def runModel(input):
36-
output = f"""\
37-
<br>
38-
A little javascript birdie told the python snake your lucky number 🙊
39-
Now everyone knows that it is: {input}
40-
"""
41-
return output
42-
43-
add_text_input("click me", runModel)
35+
inp1 = add_text_input()
36+
inp2 = add_text_input()
37+
38+
@add_button("click me to add")
39+
def run_model():
40+
a, b = int(inp1()), int(inp2())
41+
set_output(f"<pre>{a} + {b} = <b>{a + b}</b></pre>")
42+
43+
set_output = add_output()

wasm/notebook/snippets/python-js.txt

Lines changed: 40 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -45,41 +45,59 @@ Here is a run down of what is happening with this demo. The notebook:
4545
injectPython({
4646
// injectPython functions take the positional arguments as
4747
// normal function args, and kwargs as the `this` variable
48-
add_text_input(buttonText, callback) {
48+
add_text_input() {
4949
const input = document.createElement('input');
5050
pushNotebook(input);
51-
52-
const btn = document.createElement('button');
53-
btn.innerHTML = buttonText;
54-
btn.addEventListener('click', () => {
55-
resultDiv.innerHTML = '';
56-
// python functions passed to js have a signature
57-
// of ([args...], {kwargs...}) => any
58-
const output = callback([input.value], {});
59-
resultDiv.innerHTML += output;
60-
});
61-
pushNotebook(btn);
62-
51+
return () => input.value;
52+
},
53+
add_button(buttonText, cb) {
54+
const do_button = (callback) => {
55+
const btn = document.createElement('button');
56+
btn.innerHTML = buttonText;
57+
btn.addEventListener('click', () => {
58+
try {
59+
// python functions passed to js have a signature
60+
// of ([args...], {kwargs...}) => any
61+
callback([], {});
62+
} catch (err) {
63+
// puts the traceback in the error box
64+
handlePyError(err);
65+
}
66+
});
67+
pushNotebook(btn);
68+
};
69+
70+
if (cb == null) {
71+
// to allow using as a decorator
72+
return do_button;
73+
} else {
74+
do_button(cb);
75+
}
76+
},
77+
add_output() {
6378
const resultDiv = document.createElement('div');
6479
resultDiv.classList.add('result');
6580
pushNotebook(resultDiv);
81+
return (value) => {
82+
resultDiv.innerHTML = value;
83+
};
6684
},
6785
});
6886

6987
%%py
7088

71-
# Python code goes here
89+
# Python code
7290

7391
# you have access to helpers for emitting p & h1-h6
7492
h2("Calculator")
7593
h3("Enter your lucky number")
7694

77-
def runModel(input):
78-
output = f"""\
79-
<br>
80-
A little javascript birdie told the python snake your lucky number 🙊
81-
Now everyone knows that it is: {input}
82-
"""
83-
return output
95+
inp1 = add_text_input()
96+
inp2 = add_text_input()
97+
98+
@add_button("click me to add")
99+
def run_model():
100+
a, b = int(inp1()), int(inp2())
101+
set_output(f"<pre>{a} + {b} = <b>{a + b}</b></pre>")
84102

85-
add_text_input("click me", runModel)
103+
set_output = add_output()

wasm/notebook/src/index.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import {
2727
checkCssStatus,
2828
renderMarkdown,
2929
renderMath,
30+
handlePythonError,
3031
} from './process';
3132

3233
let rp;
@@ -182,6 +183,9 @@ async function executeNotebook() {
182183
window.pushNotebook = (elem) => {
183184
notebook.appendChild(elem);
184185
};
186+
window.handlePyError = (err) => {
187+
handlePythonError(error, err);
188+
};
185189
pyvm.setStdout((text) => {
186190
const para = document.createElement('p');
187191
para.appendChild(document.createTextNode(text));

wasm/notebook/src/process.js

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,17 @@ function runPython(pyvm, code, error) {
2929
try {
3030
pyvm.exec(code);
3131
} catch (err) {
32-
if (err instanceof WebAssembly.RuntimeError) {
33-
err = window.__RUSTPYTHON_ERROR || err;
34-
}
35-
error.textContent = err;
32+
handlePythonError(error, err);
3633
}
3734
}
3835

36+
function handlePythonError(errorElem, err) {
37+
if (err instanceof WebAssembly.RuntimeError) {
38+
err = window.__RUSTPYTHON_ERROR || err;
39+
}
40+
errorElem.textContent = err;
41+
}
42+
3943
function addCSS(code) {
4044
let style = document.createElement('style');
4145
style.type = 'text/css';
@@ -74,4 +78,12 @@ async function runJS(code) {
7478
}
7579
}
7680

77-
export { runPython, runJS, renderMarkdown, renderMath, addCSS, checkCssStatus };
81+
export {
82+
runPython,
83+
handlePythonError,
84+
runJS,
85+
renderMarkdown,
86+
renderMath,
87+
addCSS,
88+
checkCssStatus,
89+
};

0 commit comments

Comments
 (0)