@pyscript/core 0.1.22 → 0.2.1
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.css +1 -1
- 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.css +3 -1
- package/src/core.js +170 -161
- package/src/plugins/error.js +2 -2
- package/src/stdlib/pyscript/__init__.py +10 -1
- package/src/stdlib/pyscript/display.py +7 -0
- package/src/stdlib/pyscript/util.py +3 -4
- package/src/stdlib/pyscript.js +3 -3
- 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,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
|
-
)
|