@pyscript/core 0.1.22 → 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 +2 -2
- 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/core.js +19 -33
- package/src/plugins/error.js +2 -2
- package/src/stdlib/pyscript/display.py +7 -0
- package/src/stdlib/pyscript.js +1 -1
- 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,353 +0,0 @@
|
|
1
|
-
import re
|
2
|
-
|
3
|
-
import pytest
|
4
|
-
|
5
|
-
from .support import PyScriptTest
|
6
|
-
|
7
|
-
|
8
|
-
class TestBasic(PyScriptTest):
|
9
|
-
def test_pyscript_hello(self):
|
10
|
-
self.pyscript_run(
|
11
|
-
"""
|
12
|
-
<script type="py">
|
13
|
-
import js
|
14
|
-
js.console.log('hello pyscript')
|
15
|
-
</script>
|
16
|
-
"""
|
17
|
-
)
|
18
|
-
assert self.console.log.lines == ["hello pyscript"]
|
19
|
-
|
20
|
-
def test_execution_thread(self):
|
21
|
-
self.pyscript_run(
|
22
|
-
"""
|
23
|
-
<!-- we don't really need anything here, we just want to check that
|
24
|
-
pyscript does not bootstrap -->
|
25
|
-
""",
|
26
|
-
wait_for_pyscript=False,
|
27
|
-
)
|
28
|
-
assert self.execution_thread in ("main", "worker")
|
29
|
-
if self.execution_thread == "main":
|
30
|
-
pass
|
31
|
-
elif self.execution_thread == "worker":
|
32
|
-
pass
|
33
|
-
assert self.console.log.lines == []
|
34
|
-
|
35
|
-
# TODO: if there's no py-script there are surely no plugins neither
|
36
|
-
# this test must be discussed or rewritten to make sense now
|
37
|
-
@pytest.mark.skip(
|
38
|
-
reason="FIXME: No banner and should also add a WARNING about CORS"
|
39
|
-
)
|
40
|
-
def test_no_cors_headers(self):
|
41
|
-
self.disable_cors_headers()
|
42
|
-
self.pyscript_run(
|
43
|
-
"""
|
44
|
-
<!-- we don't really need anything here, we just want to check that
|
45
|
-
pyscript starts -->
|
46
|
-
""",
|
47
|
-
wait_for_pyscript=False,
|
48
|
-
)
|
49
|
-
assert self.headers == {}
|
50
|
-
if self.execution_thread == "worker":
|
51
|
-
expected_alert_banner_msg = (
|
52
|
-
'(PY1000): When execution_thread is "worker", the site must be cross origin '
|
53
|
-
"isolated, but crossOriginIsolated is false. To be cross origin isolated, "
|
54
|
-
"the server must use https and also serve with the following headers: "
|
55
|
-
'{"Cross-Origin-Embedder-Policy":"require-corp",'
|
56
|
-
'"Cross-Origin-Opener-Policy":"same-origin"}. '
|
57
|
-
"The problem may be that one or both of these are missing."
|
58
|
-
)
|
59
|
-
alert_banner = self.page.wait_for_selector(".alert-banner")
|
60
|
-
assert expected_alert_banner_msg in alert_banner.inner_text()
|
61
|
-
else:
|
62
|
-
self.assert_no_banners()
|
63
|
-
|
64
|
-
def test_print(self):
|
65
|
-
self.pyscript_run(
|
66
|
-
"""
|
67
|
-
<py-script>
|
68
|
-
print('hello pyscript')
|
69
|
-
</py-script>
|
70
|
-
"""
|
71
|
-
)
|
72
|
-
assert self.console.log.lines[-1] == "hello pyscript"
|
73
|
-
|
74
|
-
def test_python_exception(self):
|
75
|
-
self.pyscript_run(
|
76
|
-
"""
|
77
|
-
<py-script>
|
78
|
-
print('hello pyscript')
|
79
|
-
raise Exception('this is an error')
|
80
|
-
</py-script>
|
81
|
-
"""
|
82
|
-
)
|
83
|
-
assert "hello pyscript" in self.console.log.lines
|
84
|
-
self.check_py_errors("Exception: this is an error")
|
85
|
-
#
|
86
|
-
# check that we sent the traceback to the console
|
87
|
-
tb_lines = self.console.error.lines[-1].splitlines()
|
88
|
-
assert tb_lines[0] == "PythonError: Traceback (most recent call last):"
|
89
|
-
#
|
90
|
-
# check that we show the traceback in the page. Note that here we
|
91
|
-
# display the "raw" python traceback, without the "[pyexec] Python
|
92
|
-
# exception:" line (which is useful in the console, but not for the
|
93
|
-
# user)
|
94
|
-
banner = self.page.locator(".py-error")
|
95
|
-
tb_lines = banner.inner_text().splitlines()
|
96
|
-
assert tb_lines[0] == "Traceback (most recent call last):"
|
97
|
-
assert tb_lines[-1] == "Exception: this is an error"
|
98
|
-
|
99
|
-
def test_python_exception_in_event_handler(self):
|
100
|
-
self.pyscript_run(
|
101
|
-
"""
|
102
|
-
<button py-click="onclick">Click me</button>
|
103
|
-
<py-script>
|
104
|
-
def onclick(event):
|
105
|
-
raise Exception("this is an error inside handler")
|
106
|
-
</py-script>
|
107
|
-
"""
|
108
|
-
)
|
109
|
-
|
110
|
-
self.page.locator("button").click()
|
111
|
-
self.wait_for_console(
|
112
|
-
"Exception: this is an error inside handler", match_substring=True
|
113
|
-
)
|
114
|
-
|
115
|
-
self.check_py_errors("Exception: this is an error inside handler")
|
116
|
-
|
117
|
-
## error in console
|
118
|
-
tb_lines = self.console.error.lines[-1].splitlines()
|
119
|
-
assert tb_lines[0] == "PythonError: Traceback (most recent call last):"
|
120
|
-
|
121
|
-
## error in DOM
|
122
|
-
tb_lines = self.page.locator(".py-error").inner_text().splitlines()
|
123
|
-
assert tb_lines[0] == "Traceback (most recent call last):"
|
124
|
-
assert tb_lines[-1] == "Exception: this is an error inside handler"
|
125
|
-
|
126
|
-
def test_execution_in_order(self):
|
127
|
-
"""
|
128
|
-
Check that they py-script tags are executed in the same order they are
|
129
|
-
defined
|
130
|
-
"""
|
131
|
-
self.pyscript_run(
|
132
|
-
"""
|
133
|
-
<py-script>import js; js.console.log('one')</py-script>
|
134
|
-
<py-script>js.console.log('two')</py-script>
|
135
|
-
<py-script>js.console.log('three')</py-script>
|
136
|
-
<py-script>js.console.log('four')</py-script>
|
137
|
-
"""
|
138
|
-
)
|
139
|
-
assert self.console.log.lines[-4:] == [
|
140
|
-
"one",
|
141
|
-
"two",
|
142
|
-
"three",
|
143
|
-
"four",
|
144
|
-
]
|
145
|
-
|
146
|
-
def test_escaping_of_angle_brackets(self):
|
147
|
-
"""
|
148
|
-
Check that py-script tags escape angle brackets
|
149
|
-
"""
|
150
|
-
self.pyscript_run(
|
151
|
-
"""
|
152
|
-
<py-script>import js; js.console.log(1<2, 1>2)</py-script>
|
153
|
-
<py-script>js.console.log("<div></div>")</py-script>
|
154
|
-
"""
|
155
|
-
)
|
156
|
-
|
157
|
-
assert self.console.log.lines[-2:] == ["true false", "<div></div>"]
|
158
|
-
|
159
|
-
@pytest.mark.skip(reason="FIX TEST: Works on CHROME")
|
160
|
-
def test_packages(self):
|
161
|
-
self.pyscript_run(
|
162
|
-
"""
|
163
|
-
<py-config>
|
164
|
-
packages = ["asciitree"]
|
165
|
-
</py-config>
|
166
|
-
<py-script>
|
167
|
-
import js
|
168
|
-
import asciitree
|
169
|
-
js.console.log('hello', asciitree.__name__)
|
170
|
-
</py-script>
|
171
|
-
"""
|
172
|
-
)
|
173
|
-
|
174
|
-
assert self.console.log.lines[-3:] == [
|
175
|
-
"Loading asciitree", # printed by pyodide
|
176
|
-
"Loaded asciitree", # printed by pyodide
|
177
|
-
"hello asciitree", # printed by us
|
178
|
-
]
|
179
|
-
|
180
|
-
# TODO: if there's no py-script there are surely no plugins neither
|
181
|
-
# this test must be discussed or rewritten to make sense now
|
182
|
-
@pytest.mark.skip("FIXME: No banner")
|
183
|
-
def test_non_existent_package(self):
|
184
|
-
self.pyscript_run(
|
185
|
-
"""
|
186
|
-
<py-config>
|
187
|
-
packages = ["i-dont-exist"]
|
188
|
-
</py-config>
|
189
|
-
""",
|
190
|
-
wait_for_pyscript=False,
|
191
|
-
)
|
192
|
-
|
193
|
-
expected_alert_banner_msg = (
|
194
|
-
"(PY1001): Unable to install package(s) 'i-dont-exist'. "
|
195
|
-
"Unable to find package in PyPI. Please make sure you have "
|
196
|
-
"entered a correct package name."
|
197
|
-
)
|
198
|
-
|
199
|
-
alert_banner = self.page.wait_for_selector(".alert-banner")
|
200
|
-
assert expected_alert_banner_msg in alert_banner.inner_text()
|
201
|
-
self.check_py_errors("Can't fetch metadata for 'i-dont-exist'")
|
202
|
-
|
203
|
-
# TODO: if there's no py-script there are surely no plugins neither
|
204
|
-
# this test must be discussed or rewritten to make sense now
|
205
|
-
@pytest.mark.skip("FIXME: No banner")
|
206
|
-
def test_no_python_wheel(self):
|
207
|
-
self.pyscript_run(
|
208
|
-
"""
|
209
|
-
<py-config>
|
210
|
-
packages = ["opsdroid"]
|
211
|
-
</py-config>
|
212
|
-
""",
|
213
|
-
wait_for_pyscript=False,
|
214
|
-
)
|
215
|
-
|
216
|
-
expected_alert_banner_msg = (
|
217
|
-
"(PY1001): Unable to install package(s) 'opsdroid'. "
|
218
|
-
"Reason: Can't find a pure Python 3 Wheel for package(s) 'opsdroid'"
|
219
|
-
)
|
220
|
-
|
221
|
-
alert_banner = self.page.wait_for_selector(".alert-banner")
|
222
|
-
assert expected_alert_banner_msg in alert_banner.inner_text()
|
223
|
-
self.check_py_errors("Can't find a pure Python 3 wheel for 'opsdroid'")
|
224
|
-
|
225
|
-
def test_dynamically_add_py_script_tag(self):
|
226
|
-
self.pyscript_run(
|
227
|
-
"""
|
228
|
-
<script>
|
229
|
-
function addPyScriptTag(event) {
|
230
|
-
let tag = document.createElement('py-script');
|
231
|
-
tag.innerHTML = "print('hello world')";
|
232
|
-
document.body.appendChild(tag);
|
233
|
-
}
|
234
|
-
addPyScriptTag()
|
235
|
-
</script>
|
236
|
-
""",
|
237
|
-
timeout=20000,
|
238
|
-
)
|
239
|
-
self.page.locator("py-script")
|
240
|
-
|
241
|
-
assert self.console.log.lines[-1] == "hello world"
|
242
|
-
|
243
|
-
def test_py_script_src_attribute(self):
|
244
|
-
self.writefile("foo.py", "print('hello from foo')")
|
245
|
-
self.pyscript_run(
|
246
|
-
"""
|
247
|
-
<py-script src="foo.py"></py-script>
|
248
|
-
"""
|
249
|
-
)
|
250
|
-
assert self.console.log.lines[-1] == "hello from foo"
|
251
|
-
|
252
|
-
def test_py_script_src_not_found(self):
|
253
|
-
self.pyscript_run(
|
254
|
-
"""
|
255
|
-
<py-script src="foo.py"></py-script>
|
256
|
-
""",
|
257
|
-
check_js_errors=False,
|
258
|
-
)
|
259
|
-
assert "Failed to load resource" in self.console.error.lines[0]
|
260
|
-
|
261
|
-
# TODO: we need to be sure errors make sense from both main and worker worlds
|
262
|
-
# expected_msg = "(PY0404): Fetching from URL foo.py failed with error 404"
|
263
|
-
# assert any((expected_msg in line) for line in self.console.js_error.lines)
|
264
|
-
# assert self.assert_banner_message(expected_msg)
|
265
|
-
|
266
|
-
# pyscript_tag = self.page.locator("py-script")
|
267
|
-
# assert pyscript_tag.inner_html() == ""
|
268
|
-
|
269
|
-
# self.check_js_errors(expected_msg)
|
270
|
-
|
271
|
-
# TODO: ... and we shouldn't: it's a module and we better don't leak in global
|
272
|
-
@pytest.mark.skip("DIFFERENT BEHAVIOUR: we don't expose pyscript on window")
|
273
|
-
def test_js_version(self):
|
274
|
-
self.pyscript_run(
|
275
|
-
"""
|
276
|
-
<py-script>
|
277
|
-
</py-script>
|
278
|
-
"""
|
279
|
-
)
|
280
|
-
self.page.add_script_tag(content="console.log(pyscript.version)")
|
281
|
-
|
282
|
-
assert (
|
283
|
-
re.match(r"\d{4}\.\d{2}\.\d+(\.[a-zA-Z0-9]+)?", self.console.log.lines[-1])
|
284
|
-
is not None
|
285
|
-
)
|
286
|
-
|
287
|
-
# TODO: ... and we shouldn't: it's a module and we better don't leak in global
|
288
|
-
@pytest.mark.skip("DIFFERENT BEHAVIOUR: we don't expose pyscript on window")
|
289
|
-
def test_python_version(self):
|
290
|
-
self.pyscript_run(
|
291
|
-
"""
|
292
|
-
<py-script>
|
293
|
-
import js
|
294
|
-
js.console.log(pyscript.__version__)
|
295
|
-
js.console.log(str(pyscript.version_info))
|
296
|
-
</py-script>
|
297
|
-
"""
|
298
|
-
)
|
299
|
-
assert (
|
300
|
-
re.match(r"\d{4}\.\d{2}\.\d+(\.[a-zA-Z0-9]+)?", self.console.log.lines[-2])
|
301
|
-
is not None
|
302
|
-
)
|
303
|
-
assert (
|
304
|
-
re.match(
|
305
|
-
r"version_info\(year=\d{4}, month=\d{2}, "
|
306
|
-
r"minor=\d+, releaselevel='([a-zA-Z0-9]+)?'\)",
|
307
|
-
self.console.log.lines[-1],
|
308
|
-
)
|
309
|
-
is not None
|
310
|
-
)
|
311
|
-
|
312
|
-
def test_assert_no_banners(self):
|
313
|
-
"""
|
314
|
-
Test that the DOM doesn't contain error/warning banners
|
315
|
-
"""
|
316
|
-
self.pyscript_run(
|
317
|
-
"""
|
318
|
-
<py-script>
|
319
|
-
import sys
|
320
|
-
print("hello world", file=sys.stderr)
|
321
|
-
</py-script>
|
322
|
-
"""
|
323
|
-
)
|
324
|
-
|
325
|
-
assert self.page.locator(".py-error").inner_text() == "hello world"
|
326
|
-
|
327
|
-
def test_getPySrc_returns_source_code(self):
|
328
|
-
self.pyscript_run(
|
329
|
-
"""
|
330
|
-
<py-script>print("hello world!")</py-script>
|
331
|
-
"""
|
332
|
-
)
|
333
|
-
|
334
|
-
pyscript_tag = self.page.locator("py-script")
|
335
|
-
assert pyscript_tag.inner_html() == ""
|
336
|
-
assert pyscript_tag.evaluate("node => node.srcCode") == 'print("hello world!")'
|
337
|
-
|
338
|
-
@pytest.mark.skip(reason="FIX TEST: works in chrome!")
|
339
|
-
def test_py_attribute_without_id(self):
|
340
|
-
self.pyscript_run(
|
341
|
-
"""
|
342
|
-
<button py-click="myfunc">Click me</button>
|
343
|
-
<py-script>
|
344
|
-
def myfunc(event):
|
345
|
-
print("hello world!")
|
346
|
-
</py-script>
|
347
|
-
"""
|
348
|
-
)
|
349
|
-
btn = self.page.wait_for_selector("button")
|
350
|
-
btn.click()
|
351
|
-
self.wait_for_console("hello world!")
|
352
|
-
assert self.console.log.lines[-1] == "hello world!"
|
353
|
-
assert self.console.error.lines == []
|