@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.
Files changed (41) hide show
  1. package/dist/core.js +3 -3
  2. package/dist/core.js.map +1 -1
  3. package/dist/error-e4fe78fd.js +2 -0
  4. package/dist/error-e4fe78fd.js.map +1 -0
  5. package/package.json +2 -2
  6. package/src/config.js +1 -1
  7. package/src/core.js +20 -1
  8. package/src/exceptions.js +7 -6
  9. package/src/plugins/error.js +2 -2
  10. package/src/stdlib/pyscript/display.py +7 -0
  11. package/src/stdlib/pyscript.js +1 -1
  12. package/types/config.d.ts +2 -1
  13. package/types/exceptions.d.ts +6 -5
  14. package/dist/error-87e0706c.js +0 -2
  15. package/dist/error-87e0706c.js.map +0 -1
  16. package/tests/integration/__init__.py +0 -0
  17. package/tests/integration/conftest.py +0 -184
  18. package/tests/integration/support.py +0 -1038
  19. package/tests/integration/test_00_support.py +0 -495
  20. package/tests/integration/test_01_basic.py +0 -353
  21. package/tests/integration/test_02_display.py +0 -452
  22. package/tests/integration/test_03_element.py +0 -303
  23. package/tests/integration/test_assets/line_plot.png +0 -0
  24. package/tests/integration/test_assets/tripcolor.png +0 -0
  25. package/tests/integration/test_async.py +0 -197
  26. package/tests/integration/test_event_handling.py +0 -193
  27. package/tests/integration/test_importmap.py +0 -66
  28. package/tests/integration/test_interpreter.py +0 -98
  29. package/tests/integration/test_plugins.py +0 -419
  30. package/tests/integration/test_py_config.py +0 -294
  31. package/tests/integration/test_py_repl.py +0 -663
  32. package/tests/integration/test_py_terminal.py +0 -270
  33. package/tests/integration/test_runtime_attributes.py +0 -64
  34. package/tests/integration/test_script_type.py +0 -121
  35. package/tests/integration/test_shadow_root.py +0 -33
  36. package/tests/integration/test_splashscreen.py +0 -124
  37. package/tests/integration/test_stdio_handling.py +0 -370
  38. package/tests/integration/test_style.py +0 -47
  39. package/tests/integration/test_warnings_and_banners.py +0 -32
  40. package/tests/integration/test_zz_examples.py +0 -419
  41. 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 == []