8000 FIX to display function handling null element reference, and wrong ta… · LakshmanKishore/pyscript@a00a675 · GitHub
[go: up one dir, main page]

Skip to content

Commit a00a675

Browse files
authored
FIX to display function handling null element reference, and wrong target parameter values (pyscript#1784)
* blacked * More robust code for display, with tests Display now includes more robust controls when checking the input target parameters, with appropriate exception raised (i.e. ValueError or TypeError) whether target is either an empty string, or a not-string, not-None type, respectively. The TypeError aligns with other similar behaviour with other Pyton functions (e.g. str.split with integer separator). Also, now display raises a ValueError whether the target element is not found or not existing. All changes are supported by tests. * traceback lines in check_py_error & removed clones check_py_error function now automatically includes check of the traceback in console errors. This way tests in basic and display have been refactored, and lots of duplicated code removed. * removed useless console check lines. If check_py_errors function is running, those console log lines are useless to check.
1 parent a08f891 commit a00a675

File tree

5 files changed

+91
-15
lines changed

5 files changed

+91
-15
lines changed

pyscript.core/src/stdlib/pyscript/__init__.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,14 @@
2929
# pyscript.magic_js. This is the blessed way to access them from pyscript,
3030
# as it works transparently in both the main thread and worker cases.
3131

32-
from pyscript.magic_js import RUNNING_IN_WORKER, PyWorker, window, document, sync, current_target
32+
from pyscript.magic_js import (
33+
RUNNING_IN_WORKER,
34+
PyWorker,
35+
window,
36+
document,
37+
sync,
38+
current_target,
39+
)
3340
from pyscript.display import HTML, display
3441

3542
try:
@@ -38,6 +45,5 @@
3845
from pyscript.util import NotSupported
3946

4047
when = NotSupported(
41-
"pyscript.when",
42-
"pyscript.when currently not available with this interpreter"
48+
"pyscript.when", "pyscript.when currently not available with this interpreter"
4349
)

pyscript.core/src/stdlib/pyscript/display.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,9 +148,23 @@ def _write(element, value, append=False):
148148
def display(*values, target=None, append=True):
149149
if target is None:
150150
target = current_target()
151+
elif not isinstance(target, str):
152+
raise TypeError(f"target must be str or None, not {target.__class__.__name__}")
153+
elif target == "":
154+
raise ValueError("Cannot have an empty target")
155+
elif target.startswith("#"):
156+
# note: here target is str and not None!
157+
# align with @when behavior
158+
target = target[1:]
151159

152160
element = document.getElementById(target)
153161

162+
# If target cannot be found on the page, a ValueError is raised
163+
if element is None:
164+
raise ValueError(
165+
f"Invalid selector with id={target}. Cannot be found in the page."
166+
)
167+
154168
# if element is a <script type="py">, it has a 'target' attribute which
155169
# points to the visual element holding the displayed values. In that case,
156170
# use that.

pyscript.core/src/stdlib/pyscript/magic_js.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,9 @@
77
import polyscript
88

99
PyWorker = NotSupported(
10-
'pyscript.PyWorker',
11-
'pyscript.PyWorker works only when running in the main thread')
10+
"pyscript.PyWorker",
11+
"pyscript.PyWorker works only when running in the main thread",
12+
)
1213
window = polyscript.xworker.window
1314
document = window.document
1415
sync = polyscript.xworker.sync
@@ -21,11 +22,12 @@ def current_target():
2122
else:
2223
import _pyscript
2324
from _pyscript import PyWorker
25+
2426
window = globalThis
2527
document = globalThis.document
2628
sync = NotSupported(
27-
'pyscript.sync',
28-
'pyscript.sync works only when running in a worker')
29+
"pyscript.sync", "pyscript.sync works only when running in a worker"
30+
)
2931

3032
# in MAIN the current element target exist, just use it
3133
def current_target():

pyscript.core/tests/integration/test_01_basic.py

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -106,10 +106,6 @@ def test_python_exception(self):
106106
assert "hello pyscript" in self.console.log.lines
107107
self.check_py_errors("Exception: this is an error")
108108
#
109-
# check that we sent the traceback to the console
110-
tb_lines = self.console.error.lines[-1].splitlines()
111-
assert tb_lines[0] == "PythonError: Traceback (most recent call last):"
112-
#
113109
# check that we show the traceback in the page. Note that here we
114110
# display the "raw" python traceback, without the "[pyexec] Python
115111
# exception:" line (which is useful in the console, but not for the
@@ -138,10 +134,6 @@ def onclick(event):
138134

139135
self.check_py_errors("Exception: this is an error inside handler")
140136

141-
## error in console
142-
tb_lines = self.console.error.lines[-1].splitlines()
143-
assert tb_lines[0] == "PythonError: Traceback (most recent call last):"
144-
145137
## error in DOM
146138
tb_lines = self.page.locator(".py-error").inner_text().splitlines()
147139
assert tb_lines[0] == "Traceback (most recent call last):"

pyscript.core/tests/integration/test_02_display.py

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
from PIL import Image
1212

1313
from .support import (
14+
PageErrors,
1415
PyScriptTest,
1516
filter_inner_text,
1617
filter_page_content,
@@ -72,6 +73,67 @@ def test_target_parameter(self):
7273
mydiv = self.page.locator("#mydiv")
7374
assert mydiv.inner_text() == "hello world"
7475

76+
def test_target_parameter_with_sharp(self):
77+
self.pyscript_run(
78+
"""
79+
<script type="py">
80+
from pyscript import display
81+
display('hello world', target="#mydiv")
82+
</script>
83+
<div id="mydiv"></div>
84+
"""
85+
)
86+
mydiv = self.page.locator("#mydiv")
87+
assert mydiv.inner_text() == "hello world"
88+
89+
def test_non_existing_id_target_raises_value_error(self):
90+
self.pyscript_run(
91+
"""
92+
<script type="py">
93+
from pyscript import display
94+
display('hello world', target="non-existing")
95+
</script>
96+
"""
97+
)
98+
error_msg = (
99+
f"Invalid selector with id=non-existing. Cannot be found in the page."
100+
)
101+
self.check_py_errors(f"ValueError: {error_msg}")
102+
103+
def test_empty_string_target_raises_value_error(self):
104+
self.pyscript_run(
105+
"""
106+
<script type="py">
107+
from pyscript import display
108+
display('hello world', target="")
109+
</script>
110+
"""
111+
)
112+
self.check_py_errors(f"ValueError: Cannot have an empty target")
113+
114+
def test_non_string_target_values_raise_typerror(self):
115+
self.pyscript_run(
116+
"""
117+
<script type="py">
118+
from pyscript import display
119+
display("hello False", target=False)
120+
</script>
121+
"""
122+
)
123+
error_msg = f"target must be str or None, not bool"
124+
self.check_py_errors(f"TypeError: {error_msg}")
125+
126+
self.pyscript_run(
127+
"""
128+
<script type="py">
129+
from pyscript import display
130+
display("hello False", target=123)
131+
</script>
132+
"""
133+
)
134+
error_msg = f"target must be str or None, not int"
135+
self.check_py_errors(f"TypeError: {error_msg}")
136+
75137
@skip_worker("NEXT: display(target=...) does not work")
76138
def test_tag_target_attribute(self):
77139
self.pyscript_run(

0 commit comments

Comments
 (0)
0