@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,270 +0,0 @@
1
- import time
2
-
3
- import pytest
4
- from playwright.sync_api import expect
5
-
6
- from .support import PyScriptTest, skip_worker
7
-
8
- pytest.skip(
9
- reason="FIX LATER: pyscript NEXT doesn't support the Terminal yet",
10
- allow_module_level=True,
11
- )
12
-
13
-
14
- class TestPyTerminal(PyScriptTest):
15
- def test_py_terminal(self):
16
- """
17
- 1. <py-terminal> should redirect stdout and stderr to the DOM
18
-
19
- 2. they also go to the console as usual
20
- """
21
- self.pyscript_run(
22
- """
23
- <py-terminal></py-terminal>
24
-
25
- <py-script>
26
- import sys
27
- print('hello world')
28
- print('this goes to stderr', file=sys.stderr)
29
- print('this goes to stdout')
30
- </py-script>
31
- """
32
- )
33
- term = self.page.locator("py-terminal")
34
- term_lines = term.inner_text().splitlines()
35
- assert term_lines == [
36
- "hello world",
37
- "this goes to stderr",
38
- "this goes to stdout",
39
- ]
40
- assert self.console.log.lines[-3:] == [
41
- "hello world",
42
- "this goes to stderr",
43
- "this goes to stdout",
44
- ]
45
-
46
- @skip_worker("FIXME: js.document")
47
- def test_two_terminals(self):
48
- """
49
- Multiple <py-terminal>s can cohexist.
50
- A <py-terminal> receives only output from the moment it is added to
51
- the DOM.
52
- """
53
- self.pyscript_run(
54
- """
55
- <py-terminal id="term1"></py-terminal>
56
-
57
- <py-script>
58
- import js
59
- print('one')
60
- term2 = js.document.createElement('py-terminal')
61
- term2.id = 'term2'
62
- js.document.body.append(term2)
63
-
64
- print('two')
65
- print('three')
66
- </py-script>
67
- """
68
- )
69
- term1 = self.page.locator("#term1")
70
- term2 = self.page.locator("#term2")
71
- term1_lines = term1.inner_text().splitlines()
72
- term2_lines = term2.inner_text().splitlines()
73
- assert term1_lines == ["one", "two", "three"]
74
- assert term2_lines == ["two", "three"]
75
-
76
- def test_auto_attribute(self):
77
- self.pyscript_run(
78
- """
79
- <py-terminal auto></py-terminal>
80
-
81
- <button id="my-button" py-click="print('hello world')">Click me</button>
82
- """
83
- )
84
- term = self.page.locator("py-terminal")
85
- expect(term).to_be_hidden()
86
- self.page.locator("button").click()
87
- expect(term).to_be_visible()
88
- assert term.inner_text() == "hello world\n"
89
-
90
- def test_config_auto(self):
91
- """
92
- config.terminal == "auto" is the default: a <py-terminal auto> is
93
- automatically added to the page
94
- """
95
- self.pyscript_run(
96
- """
97
- <button id="my-button" py-click="print('hello world')">Click me</button>
98
- """
99
- )
100
- term = self.page.locator("py-terminal")
101
- expect(term).to_be_hidden()
102
- assert "No <py-terminal> found, adding one" in self.console.info.text
103
- #
104
- self.page.locator("button").click()
105
- expect(term).to_be_visible()
106
- assert term.inner_text() == "hello world\n"
107
-
108
- def test_config_true(self):
109
- """
110
- If we set config.terminal == true, a <py-terminal> is automatically added
111
- """
112
- self.pyscript_run(
113
- """
114
- <py-config>
115
- terminal = true
116
- </py-config>
117
-
118
- <py-script>
119
- print('hello world')
120
- </py-script>
121
- """
122
- )
123
- term = self.page.locator("py-terminal")
124
- expect(term).to_be_visible()
125
- assert term.inner_text() == "hello world\n"
126
-
127
- def test_config_false(self):
128
- """
129
- If we set config.terminal == false, no <py-terminal> is added
130
- """
131
- self.pyscript_run(
132
- """
133
- <py-config>
134
- terminal = false
135
- </py-config>
136
- """
137
- )
138
- term = self.page.locator("py-terminal")
139
- assert term.count() == 0
140
-
141
- def test_config_docked(self):
142
- """
143
- config.docked == "docked" is also the default: a <py-terminal auto docked> is
144
- automatically added to the page
145
- """
146
- self.pyscript_run(
147
- """
148
- <button id="my-button" py-click="print('hello world')">Click me</button>
149
- """
150
- )
151
- term = self.page.locator("py-terminal")
152
- self.page.locator("button").click()
153
- expect(term).to_be_visible()
154
- assert term.get_attribute("docked") == ""
155
-
156
- def test_xterm_function(self):
157
- """Test a few basic behaviors of the xtermjs terminal.
158
-
159
- This test isn't meant to capture all of the behaviors of an xtermjs terminal;
160
- rather, it confirms with a few basic formatting sequences that (1) the xtermjs
161
- terminal is functioning/loaded correctly and (2) that output toward that terminal
162
- isn't being escaped in a way that prevents it reacting to escape seqeunces. The
163
- main goal is preventing regressions.
164
- """
165
- self.pyscript_run(
166
- """
167
- <py-config>
168
- xterm = true
169
- </py-config>
170
- <py-script>
171
- print("\x1b[33mYellow\x1b[0m")
172
- print("\x1b[4mUnderline\x1b[24m")
173
- print("\x1b[1mBold\x1b[22m")
174
- print("\x1b[3mItalic\x1b[23m")
175
- print("done")
176
- </py-script>
177
- """
178
- )
179
-
180
- # Wait for "done" to actually appear in the xterm; may be delayed,
181
- # since xtermjs processes its input buffer in chunks
182
- last_line = self.page.get_by_text("done")
183
- last_line.wait_for()
184
-
185
- # Yes, this is not ideal. However, per http://xtermjs.org/docs/guides/hooks/
186
- # "It is not possible to conclude, whether or when a certain chunk of data
187
- # will finally appear on the screen," which is what we'd really like to know.
188
- # By waiting for the "done" test to appear above, we get close, however it is
189
- # possible for the text to appear and not be 'processed' (i.e.) formatted. This
190
- # small delay should avoid that.
191
- time.sleep(1)
192
-
193
- rows = self.page.locator(".xterm-rows")
194
-
195
- # The following use locator.evaluate() and getComputedStyle to get
196
- # the computed CSS values; this tests that the lines are rendering
197
- # properly in a better way than just testing whether they
198
- # get the right css classes from xtermjs
199
-
200
- # First line should be yellow
201
- first_line = rows.locator("div").nth(0)
202
- first_char = first_line.locator("span").nth(0)
203
- color = first_char.evaluate(
204
- "(element) => getComputedStyle(element).getPropertyValue('color')"
205
- )
206
- assert color == "rgb(196, 160, 0)"
207
-
208
- # Second line should be underlined
209
- second_line = rows.locator("div").nth(1)
210
- first_char = second_line.locator("span").nth(0)
211
- text_decoration = first_char.evaluate(
212
- "(element) => getComputedStyle(element).getPropertyValue('text-decoration')"
213
- )
214
- assert "underline" in text_decoration
215
-
216
- # We'll make sure the 'bold' font weight is more than the
217
- # default font weight without specifying a specific value
218
- baseline_font_weight = first_char.evaluate(
219
- "(element) => getComputedStyle(element).getPropertyValue('font-weight')"
220
- )
221
-
222
- # Third line should be bold
223
- third_line = rows.locator("div").nth(2)
224
- first_char = third_line.locator("span").nth(0)
225
- font_weight = first_char.evaluate(
226
- "(element) => getComputedStyle(element).getPropertyValue('font-weight')"
227
- )
228
- assert int(font_weight) > int(baseline_font_weight)
229
-
230
- # Fourth line should be italic
231
- fourth_line = rows.locator("div").nth(3)
232
- first_char = fourth_line.locator("span").nth(0)
233
- font_style = first_char.evaluate(
234
- "(element) => getComputedStyle(element).getPropertyValue('font-style')"
235
- )
236
- assert font_style == "italic"
237
-
238
- def test_xterm_multiple(self):
239
- """Test whether multiple x-terms on the page all function"""
240
- self.pyscript_run(
241
- """
242
- <py-config>
243
- xterm = true
244
- </py-config>
245
- <py-script>
246
- print("\x1b[33mYellow\x1b[0m")
247
- print("done")
248
- </py-script>
249
- <py-terminal id="a"></py-terminal>
250
- <py-terminal id="b" data-testid="b"></py-terminal>
251
- """
252
- )
253
-
254
- # Wait for "done" to actually appear in the xterm; may be delayed,
255
- # since xtermjs processes its input buffer in chunks
256
- last_line = self.page.get_by_test_id("b").get_by_text("done")
257
- last_line.wait_for()
258
-
259
- # Yes, this is not ideal. See note in `test_xterm_function`
260
- time.sleep(1)
261
-
262
- rows = self.page.locator("#a .xterm-rows")
263
-
264
- # First line should be yellow
265
- first_line = rows.locator("div").nth(0)
266
- first_char = first_line.locator("span").nth(0)
267
- color = first_char.evaluate(
268
- "(element) => getComputedStyle(element).getPropertyValue('color')"
269
- )
270
- assert color == "rgb(196, 160, 0)"
@@ -1,64 +0,0 @@
1
- import pytest
2
-
3
- from .support import PyScriptTest
4
-
5
-
6
- class TestPyScriptRuntimeAttributes(PyScriptTest):
7
- @pytest.mark.skip("FIXME: Element interface is gone. Replace with PyDom")
8
- def test_injected_html_with_py_event(self):
9
- self.pyscript_run(
10
- r"""
11
- <div id="py-button-container"></div>
12
- <py-script>
13
- import js
14
-
15
- py_button = Element("py-button-container")
16
- py_button.element.innerHTML = '<button py-click="print_hello()"></button>'
17
-
18
- def print_hello():
19
- js.console.log("hello pyscript")
20
- </py-script>
21
- """
22
- )
23
- self.page.locator("button").click()
24
- assert self.console.log.lines == ["hello pyscript"]
25
-
26
- @pytest.mark.skip("FIXME: Element interface is gone. Replace with PyDom")
27
- def test_added_py_event(self):
28
- self.pyscript_run(
29
- r"""
30
- <button id="py-button"></button>
31
- <py-script>
32
- import js
33
-
34
- py_button = Element("py-button")
35
- py_button.element.setAttribute("py-click", "print_hello()")
36
-
37
- def print_hello():
38
- js.console.log("hello pyscript")
39
- </py-script>
40
- """
41
- )
42
- self.page.locator("button").click()
43
- assert self.console.log.lines == ["hello pyscript"]
44
-
45
- @pytest.mark.skip("FIXME: Element interface is gone. Replace with PyDom")
46
- def test_added_then_removed_py_event(self):
47
- self.pyscript_run(
48
- r"""
49
- <button id="py-button">live content</button>
50
- <py-script>
51
- import js
52
-
53
- py_button = Element("py-button")
54
- py_button.element.setAttribute("py-click", "print_hello()")
55
-
56
- def print_hello():
57
- js.console.log("hello pyscript")
58
- py_button.element.removeAttribute("py-click")
59
- </py-script>
60
- """
61
- )
62
- self.page.locator("button").click()
63
- self.page.locator("button").click()
64
- assert self.console.log.lines == ["hello pyscript"]
@@ -1,121 +0,0 @@
1
- import pytest
2
-
3
- from .support import PyScriptTest
4
-
5
-
6
- class TestScriptTypePyScript(PyScriptTest):
7
- def test_display_line_break(self):
8
- self.pyscript_run(
9
- r"""
10
- <script type="py">
11
- from pyscript import display
12
- display('hello\nworld')
13
- </script>
14
- """
15
- )
16
- text_content = self.page.locator("script-py").text_content()
17
- assert "hello\nworld" == text_content
18
-
19
- def test_amp(self):
20
- self.pyscript_run(
21
- r"""
22
- <script type="py">
23
- from pyscript import display
24
- display('a &amp; b')
25
- </script>
26
- """
27
- )
28
- text_content = self.page.locator("script-py").text_content()
29
- assert "a &amp; b" == text_content
30
-
31
- def test_quot(self):
32
- self.pyscript_run(
33
- r"""
34
- <script type="py">
35
- from pyscript import display
36
- display('a &quot; b')
37
- </script>
38
- """
39
- )
40
- text_content = self.page.locator("script-py").text_content()
41
- assert "a &quot; b" == text_content
42
-
43
- def test_lt_gt(self):
44
- self.pyscript_run(
45
- r"""
46
- <script type="py">
47
- from pyscript import display
48
- display('< &lt; &gt; >')
49
- </script>
50
- """
51
- )
52
- text_content = self.page.locator("script-py").text_content()
53
- assert "< &lt; &gt; >" == text_content
54
-
55
- def test_dynamically_add_script_type_py_tag(self):
56
- self.pyscript_run(
57
- """
58
- <script>
59
- function addPyScriptTag() {
60
- let tag = document.createElement('script');
61
- tag.type = 'py';
62
- tag.textContent = "print('hello world')";
63
- document.body.appendChild(tag);
64
- }
65
- addPyScriptTag();
66
- </script>
67
- """
68
- )
69
- # please note the test here was on timeout
70
- # incapable of finding a <button> after the script
71
- self.page.locator("script-py")
72
-
73
- assert self.console.log.lines[-1] == "hello world"
74
-
75
- def test_script_type_py_src_attribute(self):
76
- self.writefile("foo.py", "print('hello from foo')")
77
- self.pyscript_run(
78
- """
79
- <script type="py" src="foo.py"></script>
80
- """
81
- )
82
- assert self.console.log.lines[-1] == "hello from foo"
83
-
84
- @pytest.mark.skip("FIXME: test failure is unrelated")
85
- def test_script_type_py_worker_attribute(self):
86
- self.writefile("foo.py", "print('hello from foo')")
87
- self.pyscript_run(
88
- """
89
- <script type="py" worker="foo.py"></script>
90
- """
91
- )
92
- assert self.console.log.lines[-1] == "hello from foo"
93
-
94
- @pytest.mark.skip("FIXME: output attribute is not implemented")
95
- def test_script_type_py_output_attribute(self):
96
- self.pyscript_run(
97
- """
98
- <div id="first"></div>
99
- <script type="py" output="first">
100
- print("<p>Hello</p>")
101
- </script>
102
- """
103
- )
104
- text = self.page.locator("#first").text_content()
105
- assert "<p>Hello</p>" in text
106
-
107
- @pytest.mark.skip("FIXME: stderr attribute is not implemented")
108
- def test_script_type_py_stderr_attribute(self):
109
- self.pyscript_run(
110
- """
111
- <div id="stdout-div"></div>
112
- <div id="stderr-div"></div>
113
- <py-script output="stdout-div" stderr="stderr-div">
114
- import sys
115
- print("one.", file=sys.stderr)
116
- print("two.")
117
- </py-script>
118
- """
119
- )
120
- assert self.page.locator("#stdout-div").text_content() == "one.two."
121
- assert self.page.locator("#stderr-div").text_content() == "one."
@@ -1,33 +0,0 @@
1
- import pytest
2
-
3
- from .support import PyScriptTest
4
-
5
-
6
- class TestShadowRoot(PyScriptTest):
7
- # @skip_worker("FIXME: js.document")
8
- @pytest.mark.skip("FIXME: Element interface is gone. Replace with PyDom")
9
- def test_reachable_shadow_root(self):
10
- self.pyscript_run(
11
- r"""
12
- <script>
13
- // reason to wait for py-script is that it's the entry point for
14
- // all patches and the MutationObserver, otherwise being this a synchronous
15
- // script the constructor gets instantly invoked at the node before
16
- // py-script gets a chance to initialize itself.
17
- customElements.whenDefined('py-script').then(() => {
18
- customElements.define('s-r', class extends HTMLElement {
19
- constructor() {
20
- super().attachShadow({mode: 'closed'}).innerHTML =
21
- '<div id="shadowed">OK</div>';
22
- }
23
- });
24
- });
25
- </script>
26
- <s-r></s-r>
27
- <py-script>
28
- import js
29
- js.console.log(Element("shadowed").innerHtml)
30
- </py-script>
31
- """
32
- )
33
- assert self.console.log.lines[-1] == "OK"
@@ -1,124 +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="DECIDE: Should we remove the splashscreen?", allow_module_level=True
8
- )
9
-
10
-
11
- class TestSplashscreen(PyScriptTest):
12
- def test_autoshow_and_autoclose(self):
13
- """
14
- By default, we show the splashscreen and we close it when the loading is
15
- complete.
16
-
17
- XXX: this test is a bit fragile: now it works reliably because the
18
- startup is so slow that when we do expect(div).to_be_visible(), the
19
- splashscreen is still there. But in theory, if the startup become very
20
- fast, it could happen that by the time we arrive in python lang, it
21
- has already been removed.
22
- """
23
- self.pyscript_run(
24
- """
25
- <py-script>
26
- print('hello pyscript')
27
- </py-script>
28
- """,
29
- wait_for_pyscript=False,
30
- )
31
- div = self.page.locator("py-splashscreen > div")
32
- expect(div).to_be_visible()
33
- expect(div).to_contain_text("Python startup...")
34
- assert "Python startup..." in self.console.info.text
35
- #
36
- # now we wait for the startup to complete
37
- self.wait_for_pyscript()
38
- #
39
- # and now the splashscreen should have been removed
40
- expect(div).to_be_hidden()
41
- assert self.page.locator("py-locator").count() == 0
42
-
43
- assert "hello pyscript" in self.console.log.lines
44
-
45
- def test_autoclose_false(self):
46
- self.pyscript_run(
47
- """
48
- <py-config>
49
- [splashscreen]
50
- autoclose = false
51
- </py-config>
52
- <py-script>
53
- print('hello pyscript')
54
- </py-script>
55
- """,
56
- )
57
- div = self.page.locator("py-splashscreen > div")
58
- expect(div).to_be_visible()
59
- expect(div).to_contain_text("Python startup...")
60
- expect(div).to_contain_text("Startup complete")
61
- assert "hello pyscript" in self.console.log.lines
62
-
63
- def test_autoclose_loader_deprecated(self):
64
- self.pyscript_run(
65
- """
66
- <py-config>
67
- autoclose_loader = false
68
- </py-config>
69
- <py-script>
70
- print('hello pyscript')
71
- </py-script>
72
- """,
73
- )
74
- warning = self.page.locator(".py-warning")
75
- inner_text = warning.inner_html()
76
- assert "The setting autoclose_loader is deprecated" in inner_text
77
-
78
- div = self.page.locator("py-splashscreen > div")
79
- expect(div).to_be_visible()
80
- expect(div).to_contain_text("Python startup...")
81
- expect(div).to_contain_text("Startup complete")
82
- assert "hello pyscript" in self.console.log.lines
83
-
84
- def test_splashscreen_disabled_option(self):
85
- self.pyscript_run(
86
- """
87
- <py-config>
88
- [splashscreen]
89
- enabled = false
90
- </py-config>
91
-
92
- <py-script>
93
- def test():
94
- print("Hello pyscript!")
95
- test()
96
- </py-script>
97
- """,
98
- )
99
- assert self.page.locator("py-splashscreen").count() == 0
100
- assert self.console.log.lines[-1] == "Hello pyscript!"
101
- py_terminal = self.page.wait_for_selector("py-terminal")
102
- assert py_terminal.inner_text() == "Hello pyscript!\n"
103
-
104
- @skip_worker("FIXME: js.document")
105
- def test_splashscreen_custom_message(self):
106
- self.pyscript_run(
107
- """
108
- <py-config>
109
- [splashscreen]
110
- autoclose = false
111
- </py-config>
112
-
113
- <py-script>
114
- from js import document
115
-
116
- splashscreen = document.querySelector("py-splashscreen")
117
- splashscreen.log("Hello, world!")
118
- </py-script>
119
- """,
120
- )
121
-
122
- splashscreen = self.page.locator("py-splashscreen")
123
- assert splashscreen.count() == 1
124
- assert "Hello, world!" in splashscreen.inner_text()