@pyscript/core 0.1.21 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/core.js +3 -3
- package/dist/core.js.map +1 -1
- package/dist/error-e4fe78fd.js +2 -0
- package/dist/error-e4fe78fd.js.map +1 -0
- package/package.json +2 -2
- package/src/config.js +1 -1
- package/src/core.js +20 -1
- package/src/exceptions.js +7 -6
- package/src/plugins/error.js +2 -2
- package/src/stdlib/pyscript/display.py +7 -0
- package/src/stdlib/pyscript.js +1 -1
- package/types/config.d.ts +2 -1
- package/types/exceptions.d.ts +6 -5
- package/dist/error-87e0706c.js +0 -2
- package/dist/error-87e0706c.js.map +0 -1
- package/tests/integration/__init__.py +0 -0
- package/tests/integration/conftest.py +0 -184
- package/tests/integration/support.py +0 -1038
- package/tests/integration/test_00_support.py +0 -495
- package/tests/integration/test_01_basic.py +0 -353
- package/tests/integration/test_02_display.py +0 -452
- package/tests/integration/test_03_element.py +0 -303
- package/tests/integration/test_assets/line_plot.png +0 -0
- package/tests/integration/test_assets/tripcolor.png +0 -0
- package/tests/integration/test_async.py +0 -197
- package/tests/integration/test_event_handling.py +0 -193
- package/tests/integration/test_importmap.py +0 -66
- package/tests/integration/test_interpreter.py +0 -98
- package/tests/integration/test_plugins.py +0 -419
- package/tests/integration/test_py_config.py +0 -294
- package/tests/integration/test_py_repl.py +0 -663
- package/tests/integration/test_py_terminal.py +0 -270
- package/tests/integration/test_runtime_attributes.py +0 -64
- package/tests/integration/test_script_type.py +0 -121
- package/tests/integration/test_shadow_root.py +0 -33
- package/tests/integration/test_splashscreen.py +0 -124
- package/tests/integration/test_stdio_handling.py +0 -370
- package/tests/integration/test_style.py +0 -47
- package/tests/integration/test_warnings_and_banners.py +0 -32
- package/tests/integration/test_zz_examples.py +0 -419
- package/tests/integration/test_zzz_docs_snippets.py +0 -305
@@ -1,452 +0,0 @@
|
|
1
|
-
import base64
|
2
|
-
import io
|
3
|
-
import os
|
4
|
-
import re
|
5
|
-
|
6
|
-
import numpy as np
|
7
|
-
import pytest
|
8
|
-
from PIL import Image
|
9
|
-
|
10
|
-
from .support import (
|
11
|
-
PyScriptTest,
|
12
|
-
filter_inner_text,
|
13
|
-
filter_page_content,
|
14
|
-
wait_for_render,
|
15
|
-
)
|
16
|
-
|
17
|
-
DISPLAY_OUTPUT_ID_PATTERN = r'[id^="py-"]'
|
18
|
-
|
19
|
-
|
20
|
-
class TestDisplay(PyScriptTest):
|
21
|
-
def test_simple_display(self):
|
22
|
-
self.pyscript_run(
|
23
|
-
"""
|
24
|
-
<py-script>
|
25
|
-
print('ciao')
|
26
|
-
from pyscript import display
|
27
|
-
display("hello world")
|
28
|
-
</py-script>
|
29
|
-
""",
|
30
|
-
timeout=20000,
|
31
|
-
)
|
32
|
-
node_list = self.page.query_selector_all(DISPLAY_OUTPUT_ID_PATTERN)
|
33
|
-
pattern = r"<div>hello world</div>"
|
34
|
-
assert node_list[0].inner_html() == pattern
|
35
|
-
assert len(node_list) == 1
|
36
|
-
|
37
|
-
def test_consecutive_display(self):
|
38
|
-
self.pyscript_run(
|
39
|
-
"""
|
40
|
-
<py-script>
|
41
|
-
from pyscript import display
|
42
|
-
display('hello 1')
|
43
|
-
</py-script>
|
44
|
-
<p>hello 2</p>
|
45
|
-
<py-script>
|
46
|
-
from pyscript import display
|
47
|
-
display('hello 3')
|
48
|
-
</py-script>
|
49
|
-
"""
|
50
|
-
)
|
51
|
-
inner_text = self.page.inner_text("body")
|
52
|
-
lines = inner_text.splitlines()
|
53
|
-
|
54
|
-
lines = [line for line in filter_page_content(lines)] # remove empty lines
|
55
|
-
assert lines == ["hello 1", "hello 2", "hello 3"]
|
56
|
-
|
57
|
-
def test_target_attribute(self):
|
58
|
-
self.pyscript_run(
|
59
|
-
"""
|
60
|
-
<py-script>
|
61
|
-
from pyscript import display
|
62
|
-
display('hello world', target="mydiv")
|
63
|
-
</py-script>
|
64
|
-
<div id="mydiv"></div>
|
65
|
-
"""
|
66
|
-
)
|
67
|
-
mydiv = self.page.locator("#mydiv")
|
68
|
-
assert mydiv.inner_text() == "hello world"
|
69
|
-
|
70
|
-
def test_consecutive_display_target(self):
|
71
|
-
self.pyscript_run(
|
72
|
-
"""
|
73
|
-
<py-script id="first">
|
74
|
-
from pyscript import display
|
75
|
-
display('hello 1')
|
76
|
-
</py-script>
|
77
|
-
<p>hello in between 1 and 2</p>
|
78
|
-
<py-script id="second">
|
79
|
-
from pyscript import display
|
80
|
-
display('hello 2', target="second")
|
81
|
-
</py-script>
|
82
|
-
<py-script id="third">
|
83
|
-
from pyscript import display
|
84
|
-
display('hello 3')
|
85
|
-
</py-script>
|
86
|
-
"""
|
87
|
-
)
|
88
|
-
inner_text = self.page.inner_text("body")
|
89
|
-
lines = inner_text.splitlines()
|
90
|
-
lines = [line for line in filter_page_content(lines)] # remove empty lines
|
91
|
-
assert lines == ["hello 1", "hello in between 1 and 2", "hello 2", "hello 3"]
|
92
|
-
|
93
|
-
def test_multiple_display_calls_same_tag(self):
|
94
|
-
self.pyscript_run(
|
95
|
-
"""
|
96
|
-
<py-script>
|
97
|
-
from pyscript import display
|
98
|
-
display('hello')
|
99
|
-
display('world')
|
100
|
-
</py-script>
|
101
|
-
"""
|
102
|
-
)
|
103
|
-
tag = self.page.locator("py-script")
|
104
|
-
lines = tag.inner_text().splitlines()
|
105
|
-
assert lines == ["hello", "world"]
|
106
|
-
|
107
|
-
def test_implicit_target_from_a_different_tag(self):
|
108
|
-
self.pyscript_run(
|
109
|
-
"""
|
110
|
-
<py-script id="py1">
|
111
|
-
from pyscript import display
|
112
|
-
def say_hello():
|
113
|
-
display('hello')
|
114
|
-
</py-script>
|
115
|
-
|
116
|
-
<py-script id="py2">
|
117
|
-
from pyscript import display
|
118
|
-
say_hello()
|
119
|
-
</py-script>
|
120
|
-
"""
|
121
|
-
)
|
122
|
-
py1 = self.page.locator("#py1")
|
123
|
-
py2 = self.page.locator("#py2")
|
124
|
-
assert py1.inner_text() == ""
|
125
|
-
assert py2.inner_text() == "hello"
|
126
|
-
|
127
|
-
def test_no_explicit_target(self):
|
128
|
-
self.pyscript_run(
|
129
|
-
"""
|
130
|
-
<py-script>
|
131
|
-
from pyscript import display
|
132
|
-
def display_hello(error):
|
133
|
-
display('hello world')
|
134
|
-
</py-script>
|
135
|
-
<button id="my-button" py-click="display_hello">Click me</button>
|
136
|
-
"""
|
137
|
-
)
|
138
|
-
self.page.locator("button").click()
|
139
|
-
|
140
|
-
text = self.page.locator("py-script").text_content()
|
141
|
-
assert "hello world" in text
|
142
|
-
|
143
|
-
def test_explicit_target_pyscript_tag(self):
|
144
|
-
self.pyscript_run(
|
145
|
-
"""
|
146
|
-
<py-script>
|
147
|
-
from pyscript import display
|
148
|
-
def display_hello():
|
149
|
-
display('hello', target='second-pyscript-tag')
|
150
|
-
</py-script>
|
151
|
-
<py-script id="second-pyscript-tag">
|
152
|
-
display_hello()
|
153
|
-
</py-script>
|
154
|
-
"""
|
155
|
-
)
|
156
|
-
text = self.page.locator("id=second-pyscript-tag").inner_text()
|
157
|
-
assert text == "hello"
|
158
|
-
|
159
|
-
def test_explicit_target_on_button_tag(self):
|
160
|
-
self.pyscript_run(
|
161
|
-
"""
|
162
|
-
<py-script>
|
163
|
-
from pyscript import display
|
164
|
-
def display_hello(error):
|
165
|
-
display('hello', target='my-button')
|
166
|
-
</py-script>
|
167
|
-
<button id="my-button" py-click="display_hello">Click me</button>
|
168
|
-
"""
|
169
|
-
)
|
170
|
-
self.page.locator("text=Click me").click()
|
171
|
-
text = self.page.locator("id=my-button").inner_text()
|
172
|
-
assert "hello" in text
|
173
|
-
|
174
|
-
def test_explicit_different_target_from_call(self):
|
175
|
-
self.pyscript_run(
|
176
|
-
"""
|
177
|
-
<py-script id="first-pyscript-tag">
|
178
|
-
from pyscript import display
|
179
|
-
def display_hello():
|
180
|
-
display('hello', target='second-pyscript-tag')
|
181
|
-
</py-script>
|
182
|
-
<py-script id="second-pyscript-tag">
|
183
|
-
print('nothing to see here')
|
184
|
-
</py-script>
|
185
|
-
<py-script>
|
186
|
-
display_hello()
|
187
|
-
</py-script>
|
188
|
-
"""
|
189
|
-
)
|
190
|
-
text = self.page.locator("id=second-pyscript-tag").all_inner_texts()
|
191
|
-
assert "hello" in text
|
192
|
-
|
193
|
-
def test_append_true(self):
|
194
|
-
self.pyscript_run(
|
195
|
-
"""
|
196
|
-
<py-script>
|
197
|
-
from pyscript import display
|
198
|
-
display('hello world', append=True)
|
199
|
-
</py-script>
|
200
|
-
"""
|
201
|
-
)
|
202
|
-
node_list = self.page.query_selector_all(DISPLAY_OUTPUT_ID_PATTERN)
|
203
|
-
pattern = r"<div>hello world</div>"
|
204
|
-
|
205
|
-
assert node_list[0].inner_html() == pattern
|
206
|
-
assert len(node_list) == 1
|
207
|
-
|
208
|
-
def test_append_false(self):
|
209
|
-
self.pyscript_run(
|
210
|
-
"""
|
211
|
-
<py-script>
|
212
|
-
from pyscript import display
|
213
|
-
display('hello world', append=False)
|
214
|
-
</py-script>
|
215
|
-
"""
|
216
|
-
)
|
217
|
-
inner_html = self.page.content()
|
218
|
-
pattern = r'<py-script id="py-.*">hello world</py-script>'
|
219
|
-
assert re.search(pattern, inner_html)
|
220
|
-
|
221
|
-
def test_display_multiple_values(self):
|
222
|
-
self.pyscript_run(
|
223
|
-
"""
|
224
|
-
<py-script>
|
225
|
-
from pyscript import display
|
226
|
-
hello = 'hello'
|
227
|
-
world = 'world'
|
228
|
-
display(hello, world)
|
229
|
-
</py-script>
|
230
|
-
"""
|
231
|
-
)
|
232
|
-
inner_text = self.page.inner_text("html")
|
233
|
-
assert inner_text == "hello\nworld"
|
234
|
-
|
235
|
-
def test_display_multiple_append_false(self):
|
236
|
-
self.pyscript_run(
|
237
|
-
"""
|
238
|
-
<py-script>
|
239
|
-
from pyscript import display
|
240
|
-
display('hello', append=False)
|
241
|
-
display('world', append=False)
|
242
|
-
</py-script>
|
243
|
-
"""
|
244
|
-
)
|
245
|
-
inner_html = self.page.content()
|
246
|
-
pattern = r'<py-script id="py-.*">world</py-script>'
|
247
|
-
assert re.search(pattern, inner_html)
|
248
|
-
|
249
|
-
# TODO: this is a display.py issue to fix when append=False is used
|
250
|
-
# do not use the first element, just clean up and then append
|
251
|
-
# remove the # display comment once that's done
|
252
|
-
def test_display_multiple_append_false_with_target(self):
|
253
|
-
self.pyscript_run(
|
254
|
-
"""
|
255
|
-
<div id="circle-div"></div>
|
256
|
-
<script type="py">
|
257
|
-
from pyscript import display
|
258
|
-
class Circle:
|
259
|
-
r = 0
|
260
|
-
def _repr_svg_(self):
|
261
|
-
return (
|
262
|
-
f'<svg height="{self.r*2}" width="{self.r*2}">'
|
263
|
-
f'<circle cx="{self.r}" cy="{self.r}" r="{self.r}" fill="red" /></svg>'
|
264
|
-
)
|
265
|
-
|
266
|
-
circle = Circle()
|
267
|
-
|
268
|
-
circle.r += 5
|
269
|
-
# display(circle, target="circle-div", append=False)
|
270
|
-
circle.r += 5
|
271
|
-
display(circle, target="circle-div", append=False)
|
272
|
-
</script>
|
273
|
-
"""
|
274
|
-
)
|
275
|
-
innerhtml = self.page.locator("id=circle-div").inner_html()
|
276
|
-
assert (
|
277
|
-
innerhtml
|
278
|
-
== '<svg height="20" width="20"><circle cx="10" cy="10" r="10" fill="red"></circle></svg>' # noqa: E501
|
279
|
-
)
|
280
|
-
assert self.console.error.lines == []
|
281
|
-
|
282
|
-
def test_display_list_dict_tuple(self):
|
283
|
-
self.pyscript_run(
|
284
|
-
"""
|
285
|
-
<py-script>
|
286
|
-
from pyscript import display
|
287
|
-
l = ['A', 1, '!']
|
288
|
-
d = {'B': 2, 'List': l}
|
289
|
-
t = ('C', 3, '!')
|
290
|
-
display(l, d, t)
|
291
|
-
</py-script>
|
292
|
-
"""
|
293
|
-
)
|
294
|
-
inner_text = self.page.inner_text("html")
|
295
|
-
filtered_inner_text = filter_inner_text(inner_text)
|
296
|
-
print(filtered_inner_text)
|
297
|
-
assert (
|
298
|
-
filtered_inner_text
|
299
|
-
== "['A', 1, '!']\n{'B': 2, 'List': ['A', 1, '!']}\n('C', 3, '!')"
|
300
|
-
)
|
301
|
-
|
302
|
-
def test_display_should_escape(self):
|
303
|
-
self.pyscript_run(
|
304
|
-
"""
|
305
|
-
<py-script>
|
306
|
-
from pyscript import display
|
307
|
-
display("<p>hello world</p>")
|
308
|
-
</py-script>
|
309
|
-
"""
|
310
|
-
)
|
311
|
-
# out = self.page.locator("py-script > div")
|
312
|
-
node_list = self.page.query_selector_all(DISPLAY_OUTPUT_ID_PATTERN)
|
313
|
-
node_list[0]
|
314
|
-
# assert out.inner_html() == html.escape("<p>hello world</p>")
|
315
|
-
# assert out.inner_text() == "<p>hello world</p>"
|
316
|
-
|
317
|
-
@pytest.mark.skip("FIXME: HTML has been removed from pyscript")
|
318
|
-
def test_display_HTML(self):
|
319
|
-
self.pyscript_run(
|
320
|
-
"""
|
321
|
-
<py-script>
|
322
|
-
from pyscript import display, HTML
|
323
|
-
display(HTML("<p>hello world</p>"))
|
324
|
-
</py-script>
|
325
|
-
"""
|
326
|
-
)
|
327
|
-
# out = self.page.locator("py-script > div")
|
328
|
-
node_list = self.page.query_selector_all(DISPLAY_OUTPUT_ID_PATTERN)
|
329
|
-
node_list[0]
|
330
|
-
# assert out.inner_html() == "<p>hello world</p>"
|
331
|
-
# assert out.inner_text() == "hello world"
|
332
|
-
|
333
|
-
@pytest.mark.skip(
|
334
|
-
"FIX TEST: Works correctly in Chrome, but fails in TEST with the error:\n\n"
|
335
|
-
"It's likely that the Test framework injections in config are causing"
|
336
|
-
"this error."
|
337
|
-
)
|
338
|
-
def test_image_display(self):
|
339
|
-
self.pyscript_run(
|
340
|
-
"""
|
341
|
-
<py-config> packages = ["matplotlib"] </py-config>
|
342
|
-
<py-script>
|
343
|
-
from pyscript import display
|
344
|
-
import matplotlib.pyplot as plt
|
345
|
-
xpoints = [3, 6, 9]
|
346
|
-
ypoints = [1, 2, 3]
|
347
|
-
plt.plot(xpoints, ypoints)
|
348
|
-
display(plt)
|
349
|
-
</py-script>
|
350
|
-
"""
|
351
|
-
)
|
352
|
-
wait_for_render(self.page, "*", "<img src=['\"]data:image")
|
353
|
-
test = self.page.wait_for_selector("img")
|
354
|
-
img_src = test.get_attribute("src").replace(
|
355
|
-
"data:image/png;charset=utf-8;base64,", ""
|
356
|
-
)
|
357
|
-
img_data = np.asarray(Image.open(io.BytesIO(base64.b64decode(img_src))))
|
358
|
-
with Image.open(
|
359
|
-
os.path.join(os.path.dirname(__file__), "test_assets", "line_plot.png"),
|
360
|
-
) as image:
|
361
|
-
ref_data = np.asarray(image)
|
362
|
-
|
363
|
-
deviation = np.mean(np.abs(img_data - ref_data))
|
364
|
-
assert deviation == 0.0
|
365
|
-
self.assert_no_banners()
|
366
|
-
|
367
|
-
def test_empty_HTML_and_console_output(self):
|
368
|
-
self.pyscript_run(
|
369
|
-
"""
|
370
|
-
<py-script>
|
371
|
-
from pyscript import display
|
372
|
-
import js
|
373
|
-
print('print from python')
|
374
|
-
js.console.log('print from js')
|
375
|
-
js.console.error('error from js');
|
376
|
-
</py-script>
|
377
|
-
"""
|
378
|
-
)
|
379
|
-
inner_html = self.page.content()
|
380
|
-
assert re.search("", inner_html)
|
381
|
-
console_text = self.console.all.lines
|
382
|
-
assert "print from python" in console_text
|
383
|
-
assert "print from js" in console_text
|
384
|
-
assert "error from js" in console_text
|
385
|
-
|
386
|
-
def test_text_HTML_and_console_output(self):
|
387
|
-
self.pyscript_run(
|
388
|
-
"""
|
389
|
-
<py-script>
|
390
|
-
from pyscript import display
|
391
|
-
import js
|
392
|
-
display('this goes to the DOM')
|
393
|
-
print('print from python')
|
394
|
-
js.console.log('print from js')
|
395
|
-
js.console.error('error from js');
|
396
|
-
</py-script>
|
397
|
-
"""
|
398
|
-
)
|
399
|
-
inner_text = self.page.inner_text("py-script")
|
400
|
-
assert inner_text == "this goes to the DOM"
|
401
|
-
assert self.console.log.lines[-2:] == [
|
402
|
-
"print from python",
|
403
|
-
"print from js",
|
404
|
-
]
|
405
|
-
print(self.console.error.lines)
|
406
|
-
assert self.console.error.lines[-1] == "error from js"
|
407
|
-
|
408
|
-
def test_console_line_break(self):
|
409
|
-
self.pyscript_run(
|
410
|
-
"""
|
411
|
-
<py-script>
|
412
|
-
print('1print\\n2print')
|
413
|
-
print('1console\\n2console')
|
414
|
-
</py-script>
|
415
|
-
"""
|
416
|
-
)
|
417
|
-
console_text = self.console.all.lines
|
418
|
-
assert console_text.index("1print") == (console_text.index("2print") - 1)
|
419
|
-
assert console_text.index("1console") == (console_text.index("2console") - 1)
|
420
|
-
|
421
|
-
@pytest.mark.skip(
|
422
|
-
"FIX TEST: Works correctly in Chrome, but fails in TEST with the error:\n\n"
|
423
|
-
"It's likely that the Test framework injections in config are causing"
|
424
|
-
"this error."
|
425
|
-
)
|
426
|
-
def test_image_renders_correctly(self):
|
427
|
-
"""This is just a sanity check to make sure that images are rendered correctly."""
|
428
|
-
buffer = io.BytesIO()
|
429
|
-
img = Image.new("RGB", (4, 4), color=(0, 0, 0))
|
430
|
-
img.save(buffer, format="PNG")
|
431
|
-
|
432
|
-
b64_img = base64.b64encode(buffer.getvalue()).decode("utf-8")
|
433
|
-
expected_img_src = f"data:image/png;charset=utf-8;base64,{b64_img}"
|
434
|
-
|
435
|
-
self.pyscript_run(
|
436
|
-
"""
|
437
|
-
<py-config>
|
438
|
-
packages = ["pillow"]
|
439
|
-
</py-config>
|
440
|
-
|
441
|
-
<div id="img-target" />
|
442
|
-
<py-script>
|
443
|
-
from pyscript import display
|
444
|
-
from PIL import Image
|
445
|
-
img = Image.new("RGB", (4, 4), color=(0, 0, 0))
|
446
|
-
display(img, target='img-target', append=False)
|
447
|
-
</py-script>
|
448
|
-
"""
|
449
|
-
)
|
450
|
-
|
451
|
-
rendered_img_src = self.page.locator("img").get_attribute("src")
|
452
|
-
assert rendered_img_src == expected_img_src
|