@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.
Files changed (37) hide show
  1. package/dist/core.js +2 -2
  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/core.js +19 -33
  7. package/src/plugins/error.js +2 -2
  8. package/src/stdlib/pyscript/display.py +7 -0
  9. package/src/stdlib/pyscript.js +1 -1
  10. package/dist/error-87e0706c.js +0 -2
  11. package/dist/error-87e0706c.js.map +0 -1
  12. package/tests/integration/__init__.py +0 -0
  13. package/tests/integration/conftest.py +0 -184
  14. package/tests/integration/support.py +0 -1038
  15. package/tests/integration/test_00_support.py +0 -495
  16. package/tests/integration/test_01_basic.py +0 -353
  17. package/tests/integration/test_02_display.py +0 -452
  18. package/tests/integration/test_03_element.py +0 -303
  19. package/tests/integration/test_assets/line_plot.png +0 -0
  20. package/tests/integration/test_assets/tripcolor.png +0 -0
  21. package/tests/integration/test_async.py +0 -197
  22. package/tests/integration/test_event_handling.py +0 -193
  23. package/tests/integration/test_importmap.py +0 -66
  24. package/tests/integration/test_interpreter.py +0 -98
  25. package/tests/integration/test_plugins.py +0 -419
  26. package/tests/integration/test_py_config.py +0 -294
  27. package/tests/integration/test_py_repl.py +0 -663
  28. package/tests/integration/test_py_terminal.py +0 -270
  29. package/tests/integration/test_runtime_attributes.py +0 -64
  30. package/tests/integration/test_script_type.py +0 -121
  31. package/tests/integration/test_shadow_root.py +0 -33
  32. package/tests/integration/test_splashscreen.py +0 -124
  33. package/tests/integration/test_stdio_handling.py +0 -370
  34. package/tests/integration/test_style.py +0 -47
  35. package/tests/integration/test_warnings_and_banners.py +0 -32
  36. package/tests/integration/test_zz_examples.py +0 -419
  37. package/tests/integration/test_zzz_docs_snippets.py +0 -305
@@ -1,370 +0,0 @@
1
- import pytest
2
-
3
- from .support import PyScriptTest, skip_worker
4
-
5
- pytest.skip(reason="FIXME: entire stdio should be reviewed", allow_module_level=True)
6
-
7
-
8
- class TestOutputHandling(PyScriptTest):
9
- # Source of a script to test the TargetedStdio functionality
10
-
11
- def test_targeted_stdio_solo(self):
12
- self.pyscript_run(
13
- """
14
- <py-config>
15
- terminal = true
16
- </py-config>
17
- <py-terminal></py-terminal>
18
- <div id="container">
19
- <div id="first"></div>
20
- <div id="second"></div>
21
- <div id="third"></div>
22
- </div>
23
- <py-script output="first">print("first 1.")</py-script>
24
- <py-script output="second">print("second.")</py-script>
25
- <py-script output="third">print("third.")</py-script>
26
- <py-script output="first">print("first 2.")</py-script>
27
- <py-script>print("no output.")</py-script>
28
- """
29
- )
30
-
31
- # Check that page has desired parent/child structure, and that
32
- # Output divs are correctly located
33
- assert (container := self.page.locator("#container")).count() > 0
34
- assert (first_div := container.locator("#first")).count() > 0
35
- assert (second_div := container.locator("#second")).count() > 0
36
- assert (third_div := container.locator("#third")).count() > 0
37
-
38
- # Check that output ends up in proper div
39
- assert first_div.text_content() == "first 1.first 2."
40
- assert second_div.text_content() == "second."
41
- assert third_div.text_content() == "third."
42
-
43
- # Check that tag with no otuput attribute doesn't end up in container at all
44
- assert container.get_by_text("no output.").count() == 0
45
-
46
- # Check that all output ends up in py-terminal
47
- assert (
48
- self.page.locator("py-terminal").text_content()
49
- == "first 1.second.third.first 2.no output."
50
- )
51
-
52
- # Check that all output ends up in the dev console, in order
53
- last_index = -1
54
- for line in ["first 1.", "second.", "third.", "first 2.", "no output."]:
55
- assert (line_index := self.console.log.lines.index(line)) > -1
56
- assert line_index > last_index
57
- last_index = line_index
58
-
59
- self.assert_no_banners()
60
-
61
- def test_stdio_escape(self):
62
- # Test that text that looks like HTML tags is properly escaped in stdio
63
- self.pyscript_run(
64
- """
65
- <div id="first"></div>
66
- <py-script output="first">
67
- print("<p>Hello</p>")
68
- print('<img src="https://example.net">')
69
- </py-script>
70
- """
71
- )
72
-
73
- text = self.page.locator("#first").text_content()
74
-
75
- assert "<p>Hello</p>" in text
76
- assert '<img src="https://example.net">' in text
77
-
78
- self.assert_no_banners()
79
-
80
- def test_targeted_stdio_linebreaks(self):
81
- self.pyscript_run(
82
- """
83
- <div id="first"></div>
84
- <py-script output="first">
85
- print("one.")
86
- print("two.")
87
- print("three.")
88
- </py-script>
89
-
90
- <div id="second"></div>
91
- <py-script output="second">
92
- print("one.\\ntwo.\\nthree.")
93
- </py-script>
94
- """
95
- )
96
-
97
- # check line breaks at end of each input
98
- assert self.page.locator("#first").inner_html() == "one.<br>two.<br>three.<br>"
99
-
100
- # new lines are converted to line breaks
101
- assert self.page.locator("#second").inner_html() == "one.<br>two.<br>three.<br>"
102
-
103
- self.assert_no_banners()
104
-
105
- def test_targeted_stdio_async(self):
106
- # Test the behavior of stdio capture in async contexts
107
- self.pyscript_run(
108
- """
109
- <py-script>
110
- import asyncio
111
- import js
112
-
113
- async def coro(value, delay):
114
- print(value)
115
- await asyncio.sleep(delay)
116
- js.console.log(f"DONE {value}")
117
- </py-script>
118
-
119
- <div id="first"></div>
120
- <py-script>
121
- asyncio.ensure_future(coro("first", 1))
122
- </py-script>
123
-
124
- <div id="second"></div>
125
- <py-script output="second">
126
- asyncio.ensure_future(coro("second", 1))
127
- </py-script>
128
-
129
- <div id="third"></div>
130
- <py-script output="third">
131
- asyncio.ensure_future(coro("third", 0))
132
- </py-script>
133
-
134
- <py-script output="third">
135
- asyncio.ensure_future(coro("DONE", 3))
136
- </py-script>
137
- """
138
- )
139
-
140
- self.wait_for_console("DONE DONE")
141
-
142
- # py-script tags without output parameter should not send
143
- # stdout to element
144
- assert self.page.locator("#first").text_content() == ""
145
-
146
- # py-script tags with output parameter not expected to send
147
- # std to element in coroutine
148
- assert self.page.locator("#second").text_content() == ""
149
- assert self.page.locator("#third").text_content() == ""
150
-
151
- self.assert_no_banners()
152
-
153
- def test_targeted_stdio_interleaved(self):
154
- # Test that synchronous writes to stdout are placed correctly, even
155
- # While interleaved with scheduling coroutines in the same tag
156
- self.pyscript_run(
157
- """
158
- <div id="good"></div>
159
- <div id="bad"></div>
160
- <py-script output="good">
161
- import asyncio
162
- import js
163
-
164
- async def coro_bad(value, delay):
165
- print(value)
166
- await asyncio.sleep(delay)
167
-
168
- print("one.")
169
- asyncio.ensure_future(coro_bad("badone.", 0.1))
170
- print("two.")
171
- asyncio.ensure_future(coro_bad("badtwo.", 0.2))
172
- print("three.")
173
- asyncio.ensure_future(coro_bad("badthree.", 0))
174
- asyncio.ensure_future(coro_bad("DONE", 1))
175
- </py-script>
176
- """
177
- )
178
-
179
- # Three prints should appear from synchronous writes
180
- assert self.page.locator("#good").text_content() == "one.two.three."
181
-
182
- # Check that all output ends up in the dev console, in order
183
- last_index = -1
184
- for line in ["one.", "two.", "three.", "badthree.", "badone.", "badtwo."]:
185
- assert (line_index := self.console.log.lines.index(line)) > -1
186
- assert line_index > last_index
187
-
188
- self.assert_no_banners()
189
-
190
- @skip_worker("FIXME: js.document")
191
- def test_targeted_stdio_dynamic_tags(self):
192
- # Test that creating py-script tags via Python still leaves
193
- # stdio targets working
194
-
195
- self.pyscript_run(
196
- """
197
- <div id="first"></div>
198
- <div id="second"></div>
199
- <py-script output="first">
200
- print("first.")
201
-
202
- import js
203
- tag = js.document.createElement("py-script")
204
- tag.innerText = "print('second.')"
205
- tag.setAttribute("output", "second")
206
- js.document.body.appendChild(tag)
207
-
208
- print("first.")
209
- </py-script>
210
- """
211
- )
212
-
213
- # Ensure second tag was added to page
214
- assert (second_div := self.page.locator("#second")).count() > 0
215
-
216
- # Ensure output when to correct locations
217
- assert self.page.locator("#first").text_content() == "first.first."
218
- assert second_div.text_content() == "second."
219
-
220
- self.assert_no_banners()
221
-
222
- def test_stdio_stdout_id_errors(self):
223
- # Test that using an ID not present on the page as the Output
224
- # Attribute creates exactly 1 warning banner per missing id
225
- self.pyscript_run(
226
- """
227
- <py-script output="not-on-page">
228
- print("bad.")
229
- </py-script>
230
-
231
- <div id="on-page"></div>
232
- <py-script>
233
- print("good.")
234
- </py-script>
235
-
236
- <py-script output="not-on-page">
237
- print("bad.")
238
- </py-script>
239
- """
240
- )
241
-
242
- banner = self.page.query_selector_all(".py-warning")
243
- assert len(banner) == 1
244
- banner_content = banner[0].inner_text()
245
- expected = (
246
- 'output = "not-on-page" does not match the id of any element on the page.'
247
- )
248
-
249
- assert banner_content == expected
250
-
251
- def test_stdio_stderr_id_errors(self):
252
- # Test that using an ID not present on the page as the stderr
253
- # attribute creates exactly 1 warning banner per missing id
254
- self.pyscript_run(
255
- """
256
- <py-script stderr="not-on-page">
257
- import sys
258
- print("bad.", file=sys.stderr)
259
- </py-script>
260
-
261
- <div id="on-page"></div>
262
- <py-script>
263
- print("good.", file=sys.stderr)
264
- </py-script>
265
-
266
- <py-script stderr="not-on-page">
267
- print("bad.", file=sys.stderr)
268
- </py-script>
269
- """
270
- )
271
-
272
- banner = self.page.query_selector_all(".py-warning")
273
- assert len(banner) == 1
274
- banner_content = banner[0].inner_text()
275
- expected = (
276
- 'stderr = "not-on-page" does not match the id of any element on the page.'
277
- )
278
-
279
- assert banner_content == expected
280
-
281
- def test_stdio_stderr(self):
282
- # Test that stderr works, and routes to the same location as stdout
283
- # Also, script tags with the stderr attribute route to an additional location
284
- self.pyscript_run(
285
- """
286
- <div id="stdout-div"></div>
287
- <div id="stderr-div"></div>
288
- <py-script output="stdout-div" stderr="stderr-div">
289
- import sys
290
- print("one.", file=sys.stderr)
291
- print("two.")
292
- </py-script>
293
- """
294
- )
295
-
296
- assert self.page.locator("#stdout-div").text_content() == "one.two."
297
- assert self.page.locator("#stderr-div").text_content() == "one."
298
- self.assert_no_banners()
299
-
300
- @skip_worker("FIXME: js.document")
301
- def test_stdio_output_attribute_change(self):
302
- # If the user changes the 'output' attribute of a <py-script> tag mid-execution,
303
- # Output should no longer go to the selected div and a warning should appear
304
- self.pyscript_run(
305
- """
306
- <div id="first"></div>
307
- <div id="second"></div>
308
- <!-- There is no tag with id "third" -->
309
- <py-script id="pyscript-tag" output="first">
310
- print("one.")
311
-
312
- # Change the 'output' attribute of this tag
313
- import js
314
- this_tag = js.document.getElementById("pyscript-tag")
315
-
316
- this_tag.setAttribute("output", "second")
317
- print("two.")
318
-
319
- this_tag.setAttribute("output", "third")
320
- print("three.")
321
- </py-script>
322
- """
323
- )
324
-
325
- assert self.page.locator("#first").text_content() == "one."
326
- assert self.page.locator("#second").text_content() == "two."
327
- expected_alert_banner_msg = (
328
- 'output = "third" does not match the id of any element on the page.'
329
- )
330
-
331
- alert_banner = self.page.locator(".alert-banner")
332
- assert expected_alert_banner_msg in alert_banner.inner_text()
333
-
334
- @skip_worker("FIXME: js.document")
335
- def test_stdio_target_element_id_change(self):
336
- # If the user changes the ID of the targeted DOM element mid-execution,
337
- # Output should no longer go to the selected element and a warning should appear
338
- self.pyscript_run(
339
- """
340
- <div id="first"></div>
341
- <div id="second"></div>
342
- <!-- There is no tag with id "third" -->
343
- <py-script id="pyscript-tag" output="first">
344
- print("one.")
345
-
346
- # Change the ID of the targeted DIV to something else
347
- import js
348
- target_tag = js.document.getElementById("first")
349
-
350
- # should fail and show banner
351
- target_tag.setAttribute("id", "second")
352
- print("two.")
353
-
354
- # But changing both the 'output' attribute and the id of the target
355
- # should work
356
- target_tag.setAttribute("id", "third")
357
- js.document.getElementById("pyscript-tag").setAttribute("output", "third")
358
- print("three.")
359
- </py-script>
360
- """
361
- )
362
-
363
- # Note the ID of the div has changed by the time of this assert
364
- assert self.page.locator("#third").text_content() == "one.three."
365
-
366
- expected_alert_banner_msg = (
367
- 'output = "first" does not match the id of any element on the page.'
368
- )
369
- alert_banner = self.page.locator(".alert-banner")
370
- assert expected_alert_banner_msg in alert_banner.inner_text()
@@ -1,47 +0,0 @@
1
- import pytest
2
- from playwright.sync_api import expect
3
-
4
- from .support import PyScriptTest, skip_worker
5
-
6
- pytest.skip(
7
- reason="FIX TESTS: These tests should reflect new PyScript and remove/change css ",
8
- allow_module_level=True,
9
- )
10
-
11
-
12
- class TestStyle(PyScriptTest):
13
- def test_pyscript_not_defined(self):
14
- """Test raw elements that are not defined for display:none"""
15
- doc = """
16
- <html>
17
- <head>
18
- <link rel="stylesheet" href="build/pyscript.css" />
19
- </head>
20
- <body>
21
- <py-config>hello</py-config>
22
- <py-script>hello</py-script>
23
- <py-repl>hello</py-repl>
24
- </body>
25
- </html>
26
- """
27
- self.writefile("test-not-defined-css.html", doc)
28
- self.goto("test-not-defined-css.html")
29
- expect(self.page.locator("py-config")).to_be_hidden()
30
- expect(self.page.locator("py-script")).to_be_hidden()
31
- expect(self.page.locator("py-repl")).to_be_hidden()
32
-
33
- @skip_worker("FIXME: display()")
34
- def test_pyscript_defined(self):
35
- """Test elements have visibility that should"""
36
- self.pyscript_run(
37
- """
38
- <py-config>
39
- name = "foo"
40
- </py-config>
41
- <py-script>display("hello")</py-script>
42
- <py-repl>display("hello")</py-repl>
43
- """
44
- )
45
- expect(self.page.locator("py-config")).to_be_hidden()
46
- expect(self.page.locator("py-script")).to_be_visible()
47
- expect(self.page.locator("py-repl")).to_be_visible()
@@ -1,32 +0,0 @@
1
- import pytest
2
-
3
- from .support import PyScriptTest
4
-
5
- pytest.skip(reason="FIXME: Restore the banner", allow_module_level=True)
6
-
7
-
8
- class TestWarningsAndBanners(PyScriptTest):
9
- # Test the behavior of generated warning banners
10
-
11
- def test_create_singular_warning(self):
12
- # Use a script tag with an invalid output attribute to generate a warning, but only one
13
- self.pyscript_run(
14
- """
15
- <py-script output="foo">
16
- print("one.")
17
- print("two.")
18
- </py-script>
19
- <py-script output="foo">
20
- print("three.")
21
- </py-script>
22
- """
23
- )
24
-
25
- loc = self.page.locator(".alert-banner")
26
-
27
- # Only one banner should appear
28
- assert loc.count() == 1
29
- assert (
30
- loc.text_content()
31
- == 'output = "foo" does not match the id of any element on the page.'
32
- )