reactpy 2.0.0b2__py3-none-any.whl → 2.0.0b4__py3-none-any.whl
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.
- reactpy/__init__.py +1 -3
- reactpy/_console/rewrite_keys.py +2 -4
- reactpy/core/component.py +1 -1
- reactpy/core/events.py +46 -15
- reactpy/core/hooks.py +8 -2
- reactpy/core/layout.py +3 -1
- reactpy/core/serve.py +3 -22
- reactpy/core/vdom.py +0 -1
- reactpy/executors/asgi/__init__.py +2 -2
- reactpy/executors/asgi/pyscript.py +2 -2
- reactpy/executors/utils.py +1 -3
- reactpy/pyscript/component_template.py +3 -6
- reactpy/pyscript/layout_handler.py +1 -1
- reactpy/pyscript/utils.py +1 -7
- reactpy/static/index.js +2 -2
- reactpy/static/index.js.map +12 -11
- reactpy/static/morphdom/morphdom-esm.js +5 -0
- reactpy/static/morphdom/morphdom-factory.js +5 -0
- reactpy/static/morphdom/morphdom-umd.js +5 -0
- reactpy/static/morphdom/morphdom-umd.min.js +1 -1
- reactpy/static/morphdom/morphdom.js +5 -0
- reactpy/static/pyscript/codemirror-BYspKCDy.js +2 -0
- reactpy/static/pyscript/codemirror-BYspKCDy.js.map +1 -0
- reactpy/static/pyscript/codemirror_commands-BLDaEdQ6.js +2 -0
- reactpy/static/pyscript/codemirror_commands-BLDaEdQ6.js.map +1 -0
- reactpy/static/pyscript/codemirror_lang-python-CkOVBHci.js +2 -0
- reactpy/static/pyscript/codemirror_lang-python-CkOVBHci.js.map +1 -0
- reactpy/static/pyscript/codemirror_language-DOkvasqm.js +2 -0
- reactpy/static/pyscript/codemirror_language-DOkvasqm.js.map +1 -0
- reactpy/static/pyscript/codemirror_state-BIAL8JKm.js +2 -0
- reactpy/static/pyscript/{codemirror_state-1UkzIAPK.js.map → codemirror_state-BIAL8JKm.js.map} +1 -1
- reactpy/static/pyscript/codemirror_view-Bt4sLgyA.js +2 -0
- reactpy/static/pyscript/codemirror_view-Bt4sLgyA.js.map +1 -0
- reactpy/static/pyscript/core-PTfg6inS.js +4 -0
- reactpy/static/pyscript/core-PTfg6inS.js.map +1 -0
- reactpy/static/pyscript/core.css +1 -1
- reactpy/static/pyscript/core.js +1 -1
- reactpy/static/pyscript/{deprecations-manager-B8Tz2RBD.js → deprecations-manager-DIDxhyRq.js} +2 -2
- reactpy/static/pyscript/{deprecations-manager-B8Tz2RBD.js.map → deprecations-manager-DIDxhyRq.js.map} +1 -1
- reactpy/static/pyscript/{donkey-83vCPSep.js → donkey-CLhmQOjG.js} +2 -2
- reactpy/static/pyscript/{donkey-83vCPSep.js.map → donkey-CLhmQOjG.js.map} +1 -1
- reactpy/static/pyscript/error-uzvvriog.js +2 -0
- reactpy/static/pyscript/{error-Bd5T9j4s.js.map → error-uzvvriog.js.map} +1 -1
- reactpy/static/pyscript/index-jZ1aOVVJ.js +2 -0
- reactpy/static/pyscript/index-jZ1aOVVJ.js.map +1 -0
- reactpy/static/pyscript/mpy-CnF17tqI.js +2 -0
- reactpy/static/pyscript/mpy-CnF17tqI.js.map +1 -0
- reactpy/static/pyscript/py-BZSSqcx3.js +2 -0
- reactpy/static/pyscript/{py-CdW1_TfR.js.map → py-BZSSqcx3.js.map} +1 -1
- reactpy/static/pyscript/py-editor-DZ0Dxzzk.js +2 -0
- reactpy/static/pyscript/py-editor-DZ0Dxzzk.js.map +1 -0
- reactpy/static/pyscript/py-game-bqieV522.js +2 -0
- reactpy/static/pyscript/py-game-bqieV522.js.map +1 -0
- reactpy/static/pyscript/py-terminal-DYY4WN57.js +2 -0
- reactpy/static/pyscript/{py-terminal-C3QERaDG.js.map → py-terminal-DYY4WN57.js.map} +1 -1
- reactpy/static/pyscript/service-worker.js +1 -0
- reactpy/static/pyscript/storage.js +1 -1
- reactpy/static/pyscript/storage.js.map +1 -1
- reactpy/static/pyscript/toml-BK2RWy-G.js +3 -0
- reactpy/static/pyscript/{toml-DiUM0_qs.js.map → toml-BK2RWy-G.js.map} +1 -1
- reactpy/static/pyscript/toml-Blg7Izee.js +3 -0
- reactpy/static/pyscript/toml-Blg7Izee.js.map +1 -0
- reactpy/static/pyscript/xterm-DrSYbXEP.js +2 -0
- reactpy/static/pyscript/xterm-DrSYbXEP.js.map +1 -0
- reactpy/static/pyscript/xterm-readline-CK_45Ygx.js +2 -0
- reactpy/static/pyscript/xterm-readline-CK_45Ygx.js.map +1 -0
- reactpy/static/pyscript/xterm.css +1 -1
- reactpy/static/pyscript/xterm_addon-fit--gyF3PcZ.js.map +1 -1
- reactpy/static/pyscript/xterm_addon-web-links-D95xh2la.js +2 -0
- reactpy/static/pyscript/xterm_addon-web-links-D95xh2la.js.map +1 -0
- reactpy/static/pyscript/zip-pccs084i.js +2 -0
- reactpy/static/pyscript/zip-pccs084i.js.map +1 -0
- reactpy/templatetags/__init__.py +2 -2
- reactpy/templatetags/jinja.py +1 -1
- reactpy/testing/backend.py +1 -1
- reactpy/types.py +16 -0
- reactpy/utils.py +5 -5
- reactpy/web/__init__.py +6 -0
- reactpy/web/module.py +320 -62
- reactpy/web/utils.py +1 -1
- reactpy/widgets.py +3 -25
- {reactpy-2.0.0b2.dist-info → reactpy-2.0.0b4.dist-info}/METADATA +2 -3
- reactpy-2.0.0b4.dist-info/RECORD +116 -0
- {reactpy-2.0.0b2.dist-info → reactpy-2.0.0b4.dist-info}/WHEEL +1 -1
- reactpy/static/pyscript/codemirror-DNtCVICy.js +0 -2
- reactpy/static/pyscript/codemirror-DNtCVICy.js.map +0 -1
- reactpy/static/pyscript/codemirror_commands-DvCG1qNv.js +0 -2
- reactpy/static/pyscript/codemirror_commands-DvCG1qNv.js.map +0 -1
- reactpy/static/pyscript/codemirror_lang-python-BgZ6XoEX.js +0 -2
- reactpy/static/pyscript/codemirror_lang-python-BgZ6XoEX.js.map +0 -1
- reactpy/static/pyscript/codemirror_language-ddx8nifT.js +0 -2
- reactpy/static/pyscript/codemirror_language-ddx8nifT.js.map +0 -1
- reactpy/static/pyscript/codemirror_state-1UkzIAPK.js +0 -2
- reactpy/static/pyscript/codemirror_view-C2ObO--u.js +0 -2
- reactpy/static/pyscript/codemirror_view-C2ObO--u.js.map +0 -1
- reactpy/static/pyscript/core-BsIVS0z4.js +0 -4
- reactpy/static/pyscript/core-BsIVS0z4.js.map +0 -1
- reactpy/static/pyscript/error-Bd5T9j4s.js +0 -2
- reactpy/static/pyscript/index-978lpDXp.js +0 -2
- reactpy/static/pyscript/index-978lpDXp.js.map +0 -1
- reactpy/static/pyscript/mpy-De_qSCIU.js +0 -2
- reactpy/static/pyscript/mpy-De_qSCIU.js.map +0 -1
- reactpy/static/pyscript/py-CdW1_TfR.js +0 -2
- reactpy/static/pyscript/py-editor-MNjBwLfD.js +0 -2
- reactpy/static/pyscript/py-editor-MNjBwLfD.js.map +0 -1
- reactpy/static/pyscript/py-game-Did5BuBI.js +0 -2
- reactpy/static/pyscript/py-game-Did5BuBI.js.map +0 -1
- reactpy/static/pyscript/py-terminal-C3QERaDG.js +0 -2
- reactpy/static/pyscript/toml-BLBSZ43A.js +0 -3
- reactpy/static/pyscript/toml-BLBSZ43A.js.map +0 -1
- reactpy/static/pyscript/toml-DiUM0_qs.js +0 -3
- reactpy/static/pyscript/xterm-7LwxAMsn.js +0 -2
- reactpy/static/pyscript/xterm-7LwxAMsn.js.map +0 -1
- reactpy/static/pyscript/xterm-readline-e8QPhSrm.js +0 -2
- reactpy/static/pyscript/xterm-readline-e8QPhSrm.js.map +0 -1
- reactpy/static/pyscript/xterm_addon-web-links-Cnej-nJ6.js +0 -2
- reactpy/static/pyscript/xterm_addon-web-links-Cnej-nJ6.js.map +0 -1
- reactpy/static/pyscript/zip-CFEEYRfx.js +0 -2
- reactpy/static/pyscript/zip-CFEEYRfx.js.map +0 -1
- reactpy-2.0.0b2.dist-info/RECORD +0 -115
- {reactpy-2.0.0b2.dist-info → reactpy-2.0.0b4.dist-info}/entry_points.txt +0 -0
- {reactpy-2.0.0b2.dist-info → reactpy-2.0.0b4.dist-info}/licenses/LICENSE +0 -0
reactpy/templatetags/__init__.py
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
from reactpy.templatetags.jinja import
|
|
1
|
+
from reactpy.templatetags.jinja import ReactPyJinja
|
|
2
2
|
|
|
3
|
-
__all__ = ["
|
|
3
|
+
__all__ = ["ReactPyJinja"]
|
reactpy/templatetags/jinja.py
CHANGED
|
@@ -7,7 +7,7 @@ from reactpy.executors.utils import server_side_component_html
|
|
|
7
7
|
from reactpy.pyscript.utils import pyscript_component_html, pyscript_setup_html
|
|
8
8
|
|
|
9
9
|
|
|
10
|
-
class
|
|
10
|
+
class ReactPyJinja(StandaloneTag): # type: ignore
|
|
11
11
|
safe_output = True
|
|
12
12
|
tags: ClassVar[set[str]] = {"component", "pyscript_component", "pyscript_setup"}
|
|
13
13
|
|
reactpy/testing/backend.py
CHANGED
|
@@ -119,7 +119,7 @@ class BackendFixture:
|
|
|
119
119
|
self.log_records = self._exit_stack.enter_context(capture_reactpy_logs())
|
|
120
120
|
|
|
121
121
|
# Wait for the server to start
|
|
122
|
-
self.webserver.config.
|
|
122
|
+
self.webserver.config.get_loop_factory()
|
|
123
123
|
self.webserver_task = asyncio.create_task(self.webserver.serve())
|
|
124
124
|
await asyncio.sleep(1)
|
|
125
125
|
|
reactpy/types.py
CHANGED
|
@@ -1071,3 +1071,19 @@ class CustomVdomConstructor(Protocol):
|
|
|
1071
1071
|
class EllipsisRepr:
|
|
1072
1072
|
def __repr__(self) -> str:
|
|
1073
1073
|
return "..."
|
|
1074
|
+
|
|
1075
|
+
|
|
1076
|
+
class Event(dict):
|
|
1077
|
+
"""
|
|
1078
|
+
A light `dict` wrapper for event data passed to event handler functions.
|
|
1079
|
+
"""
|
|
1080
|
+
|
|
1081
|
+
def __getattr__(self, name: str) -> Any:
|
|
1082
|
+
value = self.get(name)
|
|
1083
|
+
return Event(value) if isinstance(value, dict) else value
|
|
1084
|
+
|
|
1085
|
+
def preventDefault(self) -> None:
|
|
1086
|
+
"""Prevent the default action of the event."""
|
|
1087
|
+
|
|
1088
|
+
def stopPropagation(self) -> None:
|
|
1089
|
+
"""Stop the event from propagating."""
|
reactpy/utils.py
CHANGED
|
@@ -45,6 +45,8 @@ class Ref(Generic[_RefValue]):
|
|
|
45
45
|
self.current = new
|
|
46
46
|
return old
|
|
47
47
|
|
|
48
|
+
__hash__ = None # type: ignore
|
|
49
|
+
|
|
48
50
|
def __eq__(self, other: object) -> bool:
|
|
49
51
|
try:
|
|
50
52
|
return isinstance(other, Ref) and (other.current == self.current)
|
|
@@ -111,19 +113,17 @@ def string_to_reactpy(
|
|
|
111
113
|
try:
|
|
112
114
|
root_node: etree._Element = fromstring(
|
|
113
115
|
html.strip(),
|
|
114
|
-
parser=etree.HTMLParser(
|
|
116
|
+
parser=etree.HTMLParser( # type: ignore
|
|
115
117
|
remove_comments=True,
|
|
116
118
|
remove_pis=True,
|
|
117
119
|
remove_blank_text=True,
|
|
118
120
|
recover=not strict,
|
|
119
121
|
),
|
|
120
122
|
)
|
|
121
|
-
except
|
|
122
|
-
if not strict:
|
|
123
|
-
raise e # nocov
|
|
123
|
+
except Exception as e:
|
|
124
124
|
msg = (
|
|
125
125
|
"An error has occurred while parsing the HTML.\n\n"
|
|
126
|
-
"This HTML may be malformatted, or may not
|
|
126
|
+
"This HTML may be malformatted, or may not adhere to the HTML5 spec.\n"
|
|
127
127
|
"If you believe the exception above was due to something intentional, you "
|
|
128
128
|
"can disable the strict parameter on string_to_reactpy().\n"
|
|
129
129
|
"Otherwise, repair your broken HTML and try again."
|
reactpy/web/__init__.py
CHANGED
|
@@ -3,6 +3,9 @@ from reactpy.web.module import (
|
|
|
3
3
|
module_from_file,
|
|
4
4
|
module_from_string,
|
|
5
5
|
module_from_url,
|
|
6
|
+
reactjs_component_from_file,
|
|
7
|
+
reactjs_component_from_string,
|
|
8
|
+
reactjs_component_from_url,
|
|
6
9
|
)
|
|
7
10
|
|
|
8
11
|
__all__ = [
|
|
@@ -10,4 +13,7 @@ __all__ = [
|
|
|
10
13
|
"module_from_file",
|
|
11
14
|
"module_from_string",
|
|
12
15
|
"module_from_url",
|
|
16
|
+
"reactjs_component_from_file",
|
|
17
|
+
"reactjs_component_from_string",
|
|
18
|
+
"reactjs_component_from_url",
|
|
13
19
|
]
|
reactpy/web/module.py
CHANGED
|
@@ -7,6 +7,7 @@ from dataclasses import dataclass
|
|
|
7
7
|
from pathlib import Path
|
|
8
8
|
from typing import Any, NewType, overload
|
|
9
9
|
|
|
10
|
+
from reactpy._warnings import warn
|
|
10
11
|
from reactpy.config import REACTPY_DEBUG, REACTPY_WEB_MODULES_DIR
|
|
11
12
|
from reactpy.core.vdom import Vdom
|
|
12
13
|
from reactpy.types import ImportSourceDict, VdomConstructor
|
|
@@ -27,71 +28,138 @@ URL_SOURCE = SourceType("URL")
|
|
|
27
28
|
"""A source loaded from a URL, usually a CDN"""
|
|
28
29
|
|
|
29
30
|
|
|
30
|
-
|
|
31
|
+
_URL_WEB_MODULE_CACHE: dict[str, WebModule] = {}
|
|
32
|
+
_FILE_WEB_MODULE_CACHE: dict[str, WebModule] = {}
|
|
33
|
+
_STRING_WEB_MODULE_CACHE: dict[str, WebModule] = {}
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
@overload
|
|
37
|
+
def reactjs_component_from_url(
|
|
38
|
+
url: str,
|
|
39
|
+
import_names: str,
|
|
40
|
+
fallback: Any | None = ...,
|
|
41
|
+
resolve_imports: bool | None = ...,
|
|
42
|
+
resolve_imports_depth: int = ...,
|
|
43
|
+
unmount_before_update: bool = ...,
|
|
44
|
+
allow_children: bool = ...,
|
|
45
|
+
) -> VdomConstructor: ...
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
@overload
|
|
49
|
+
def reactjs_component_from_url(
|
|
50
|
+
url: str,
|
|
51
|
+
import_names: list[str] | tuple[str, ...],
|
|
52
|
+
fallback: Any | None = ...,
|
|
53
|
+
resolve_imports: bool | None = ...,
|
|
54
|
+
resolve_imports_depth: int = ...,
|
|
55
|
+
unmount_before_update: bool = ...,
|
|
56
|
+
allow_children: bool = ...,
|
|
57
|
+
) -> list[VdomConstructor]: ...
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def reactjs_component_from_url(
|
|
31
61
|
url: str,
|
|
62
|
+
import_names: str | list[str] | tuple[str, ...],
|
|
32
63
|
fallback: Any | None = None,
|
|
33
|
-
|
|
34
|
-
|
|
64
|
+
resolve_imports: bool | None = None,
|
|
65
|
+
resolve_imports_depth: int = 5,
|
|
35
66
|
unmount_before_update: bool = False,
|
|
36
|
-
|
|
37
|
-
|
|
67
|
+
allow_children: bool = True,
|
|
68
|
+
) -> VdomConstructor | list[VdomConstructor]:
|
|
69
|
+
"""Import a component from a URL.
|
|
38
70
|
|
|
39
71
|
Parameters:
|
|
40
72
|
url:
|
|
41
|
-
|
|
42
|
-
|
|
73
|
+
The URL to import the component from.
|
|
74
|
+
import_names:
|
|
75
|
+
One or more component names to import. If given as a string, a single component
|
|
76
|
+
will be returned. If a list is given, then a list of components will be
|
|
77
|
+
returned.
|
|
43
78
|
fallback:
|
|
44
79
|
What to temporarily display while the module is being loaded.
|
|
45
80
|
resolve_imports:
|
|
46
|
-
Whether to try and find all the named
|
|
47
|
-
|
|
48
|
-
How deeply to search for those
|
|
81
|
+
Whether to try and find all the named imports of this module.
|
|
82
|
+
resolve_imports_depth:
|
|
83
|
+
How deeply to search for those imports.
|
|
49
84
|
unmount_before_update:
|
|
50
85
|
Cause the component to be unmounted before each update. This option should
|
|
51
86
|
only be used if the imported package fails to re-render when props change.
|
|
52
87
|
Using this option has negative performance consequences since all DOM
|
|
53
88
|
elements must be changed on each render. See :issue:`461` for more info.
|
|
89
|
+
allow_children:
|
|
90
|
+
Whether or not these components can have children.
|
|
54
91
|
"""
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
),
|
|
69
|
-
unmount_before_update=unmount_before_update,
|
|
70
|
-
)
|
|
92
|
+
key = f"{url}{resolve_imports}{resolve_imports_depth}{unmount_before_update}"
|
|
93
|
+
if key in _URL_WEB_MODULE_CACHE:
|
|
94
|
+
module = _URL_WEB_MODULE_CACHE[key]
|
|
95
|
+
else:
|
|
96
|
+
module = _module_from_url(
|
|
97
|
+
url,
|
|
98
|
+
fallback=fallback,
|
|
99
|
+
resolve_imports=resolve_imports,
|
|
100
|
+
resolve_imports_depth=resolve_imports_depth,
|
|
101
|
+
unmount_before_update=unmount_before_update,
|
|
102
|
+
)
|
|
103
|
+
_URL_WEB_MODULE_CACHE[key] = module
|
|
104
|
+
return _vdom_from_web_module(module, import_names, fallback, allow_children)
|
|
71
105
|
|
|
72
106
|
|
|
73
|
-
|
|
107
|
+
@overload
|
|
108
|
+
def reactjs_component_from_file(
|
|
109
|
+
name: str,
|
|
110
|
+
file: str | Path,
|
|
111
|
+
import_names: str,
|
|
112
|
+
fallback: Any | None = ...,
|
|
113
|
+
resolve_imports: bool | None = ...,
|
|
114
|
+
resolve_imports_depth: int = ...,
|
|
115
|
+
unmount_before_update: bool = ...,
|
|
116
|
+
symlink: bool = ...,
|
|
117
|
+
allow_children: bool = ...,
|
|
118
|
+
) -> VdomConstructor: ...
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
@overload
|
|
122
|
+
def reactjs_component_from_file(
|
|
74
123
|
name: str,
|
|
75
124
|
file: str | Path,
|
|
125
|
+
import_names: list[str] | tuple[str, ...],
|
|
126
|
+
fallback: Any | None = ...,
|
|
127
|
+
resolve_imports: bool | None = ...,
|
|
128
|
+
resolve_imports_depth: int = ...,
|
|
129
|
+
unmount_before_update: bool = ...,
|
|
130
|
+
symlink: bool = ...,
|
|
131
|
+
allow_children: bool = ...,
|
|
132
|
+
) -> list[VdomConstructor]: ...
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
def reactjs_component_from_file(
|
|
136
|
+
name: str,
|
|
137
|
+
file: str | Path,
|
|
138
|
+
import_names: str | list[str] | tuple[str, ...],
|
|
76
139
|
fallback: Any | None = None,
|
|
77
|
-
|
|
78
|
-
|
|
140
|
+
resolve_imports: bool | None = None,
|
|
141
|
+
resolve_imports_depth: int = 5,
|
|
79
142
|
unmount_before_update: bool = False,
|
|
80
143
|
symlink: bool = False,
|
|
81
|
-
|
|
82
|
-
|
|
144
|
+
allow_children: bool = True,
|
|
145
|
+
) -> VdomConstructor | list[VdomConstructor]:
|
|
146
|
+
"""Import a component from a file.
|
|
83
147
|
|
|
84
148
|
Parameters:
|
|
85
149
|
name:
|
|
86
150
|
The name of the package
|
|
87
151
|
file:
|
|
88
152
|
The file from which the content of the web module will be created.
|
|
153
|
+
import_names:
|
|
154
|
+
One or more component names to import. If given as a string, a single component
|
|
155
|
+
will be returned. If a list is given, then a list of components will be
|
|
156
|
+
returned.
|
|
89
157
|
fallback:
|
|
90
158
|
What to temporarily display while the module is being loaded.
|
|
91
159
|
resolve_imports:
|
|
92
|
-
Whether to try and find all the named
|
|
93
|
-
|
|
94
|
-
How deeply to search for those
|
|
160
|
+
Whether to try and find all the named imports of this module.
|
|
161
|
+
resolve_imports_depth:
|
|
162
|
+
How deeply to search for those imports.
|
|
95
163
|
unmount_before_update:
|
|
96
164
|
Cause the component to be unmounted before each update. This option should
|
|
97
165
|
only be used if the imported package fails to re-render when props change.
|
|
@@ -99,7 +167,203 @@ def module_from_file(
|
|
|
99
167
|
elements must be changed on each render. See :issue:`461` for more info.
|
|
100
168
|
symlink:
|
|
101
169
|
Whether the web module should be saved as a symlink to the given ``file``.
|
|
170
|
+
allow_children:
|
|
171
|
+
Whether or not these components can have children.
|
|
172
|
+
"""
|
|
173
|
+
key = f"{name}{resolve_imports}{resolve_imports_depth}{unmount_before_update}"
|
|
174
|
+
if key in _FILE_WEB_MODULE_CACHE:
|
|
175
|
+
module = _FILE_WEB_MODULE_CACHE[key]
|
|
176
|
+
else:
|
|
177
|
+
module = _module_from_file(
|
|
178
|
+
name,
|
|
179
|
+
file,
|
|
180
|
+
fallback=fallback,
|
|
181
|
+
resolve_imports=resolve_imports,
|
|
182
|
+
resolve_imports_depth=resolve_imports_depth,
|
|
183
|
+
unmount_before_update=unmount_before_update,
|
|
184
|
+
symlink=symlink,
|
|
185
|
+
)
|
|
186
|
+
_FILE_WEB_MODULE_CACHE[key] = module
|
|
187
|
+
return _vdom_from_web_module(module, import_names, fallback, allow_children)
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
@overload
|
|
191
|
+
def reactjs_component_from_string(
|
|
192
|
+
name: str,
|
|
193
|
+
content: str,
|
|
194
|
+
import_names: str,
|
|
195
|
+
fallback: Any | None = ...,
|
|
196
|
+
resolve_imports: bool | None = ...,
|
|
197
|
+
resolve_imports_depth: int = ...,
|
|
198
|
+
unmount_before_update: bool = ...,
|
|
199
|
+
allow_children: bool = ...,
|
|
200
|
+
) -> VdomConstructor: ...
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
@overload
|
|
204
|
+
def reactjs_component_from_string(
|
|
205
|
+
name: str,
|
|
206
|
+
content: str,
|
|
207
|
+
import_names: list[str] | tuple[str, ...],
|
|
208
|
+
fallback: Any | None = ...,
|
|
209
|
+
resolve_imports: bool | None = ...,
|
|
210
|
+
resolve_imports_depth: int = ...,
|
|
211
|
+
unmount_before_update: bool = ...,
|
|
212
|
+
allow_children: bool = ...,
|
|
213
|
+
) -> list[VdomConstructor]: ...
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
def reactjs_component_from_string(
|
|
217
|
+
name: str,
|
|
218
|
+
content: str,
|
|
219
|
+
import_names: str | list[str] | tuple[str, ...],
|
|
220
|
+
fallback: Any | None = None,
|
|
221
|
+
resolve_imports: bool | None = None,
|
|
222
|
+
resolve_imports_depth: int = 5,
|
|
223
|
+
unmount_before_update: bool = False,
|
|
224
|
+
allow_children: bool = True,
|
|
225
|
+
) -> VdomConstructor | list[VdomConstructor]:
|
|
226
|
+
"""Import a component from a string.
|
|
227
|
+
|
|
228
|
+
Parameters:
|
|
229
|
+
name:
|
|
230
|
+
The name of the package
|
|
231
|
+
content:
|
|
232
|
+
The contents of the web module
|
|
233
|
+
import_names:
|
|
234
|
+
One or more component names to import. If given as a string, a single component
|
|
235
|
+
will be returned. If a list is given, then a list of components will be
|
|
236
|
+
returned.
|
|
237
|
+
fallback:
|
|
238
|
+
What to temporarily display while the module is being loaded.
|
|
239
|
+
resolve_imports:
|
|
240
|
+
Whether to try and find all the named imports of this module.
|
|
241
|
+
resolve_imports_depth:
|
|
242
|
+
How deeply to search for those imports.
|
|
243
|
+
unmount_before_update:
|
|
244
|
+
Cause the component to be unmounted before each update. This option should
|
|
245
|
+
only be used if the imported package fails to re-render when props change.
|
|
246
|
+
Using this option has negative performance consequences since all DOM
|
|
247
|
+
elements must be changed on each render. See :issue:`461` for more info.
|
|
248
|
+
allow_children:
|
|
249
|
+
Whether or not these components can have children.
|
|
102
250
|
"""
|
|
251
|
+
key = f"{name}{resolve_imports}{resolve_imports_depth}{unmount_before_update}"
|
|
252
|
+
if key in _STRING_WEB_MODULE_CACHE:
|
|
253
|
+
module = _STRING_WEB_MODULE_CACHE[key]
|
|
254
|
+
else:
|
|
255
|
+
module = _module_from_string(
|
|
256
|
+
name,
|
|
257
|
+
content,
|
|
258
|
+
fallback=fallback,
|
|
259
|
+
resolve_imports=resolve_imports,
|
|
260
|
+
resolve_imports_depth=resolve_imports_depth,
|
|
261
|
+
unmount_before_update=unmount_before_update,
|
|
262
|
+
)
|
|
263
|
+
_STRING_WEB_MODULE_CACHE[key] = module
|
|
264
|
+
return _vdom_from_web_module(module, import_names, fallback, allow_children)
|
|
265
|
+
|
|
266
|
+
|
|
267
|
+
def module_from_url(
|
|
268
|
+
url: str,
|
|
269
|
+
fallback: Any | None = None,
|
|
270
|
+
resolve_exports: bool | None = None,
|
|
271
|
+
resolve_exports_depth: int = 5,
|
|
272
|
+
unmount_before_update: bool = False,
|
|
273
|
+
) -> WebModule: # pragma: no cover
|
|
274
|
+
warn(
|
|
275
|
+
"module_from_url is deprecated, use reactjs_component_from_url instead",
|
|
276
|
+
DeprecationWarning,
|
|
277
|
+
)
|
|
278
|
+
return _module_from_url(
|
|
279
|
+
url,
|
|
280
|
+
fallback=fallback,
|
|
281
|
+
resolve_imports=resolve_exports,
|
|
282
|
+
resolve_imports_depth=resolve_exports_depth,
|
|
283
|
+
unmount_before_update=unmount_before_update,
|
|
284
|
+
)
|
|
285
|
+
|
|
286
|
+
|
|
287
|
+
def module_from_file(
|
|
288
|
+
name: str,
|
|
289
|
+
file: str | Path,
|
|
290
|
+
fallback: Any | None = None,
|
|
291
|
+
resolve_exports: bool | None = None,
|
|
292
|
+
resolve_exports_depth: int = 5,
|
|
293
|
+
unmount_before_update: bool = False,
|
|
294
|
+
symlink: bool = False,
|
|
295
|
+
) -> WebModule: # pragma: no cover
|
|
296
|
+
warn(
|
|
297
|
+
"module_from_file is deprecated, use reactjs_component_from_file instead",
|
|
298
|
+
DeprecationWarning,
|
|
299
|
+
)
|
|
300
|
+
return _module_from_file(
|
|
301
|
+
name,
|
|
302
|
+
file,
|
|
303
|
+
fallback=fallback,
|
|
304
|
+
resolve_imports=resolve_exports,
|
|
305
|
+
resolve_imports_depth=resolve_exports_depth,
|
|
306
|
+
unmount_before_update=unmount_before_update,
|
|
307
|
+
symlink=symlink,
|
|
308
|
+
)
|
|
309
|
+
|
|
310
|
+
|
|
311
|
+
def module_from_string(
|
|
312
|
+
name: str,
|
|
313
|
+
content: str,
|
|
314
|
+
fallback: Any | None = None,
|
|
315
|
+
resolve_exports: bool | None = None,
|
|
316
|
+
resolve_exports_depth: int = 5,
|
|
317
|
+
unmount_before_update: bool = False,
|
|
318
|
+
) -> WebModule: # pragma: no cover
|
|
319
|
+
warn(
|
|
320
|
+
"module_from_string is deprecated, use reactjs_component_from_string instead",
|
|
321
|
+
DeprecationWarning,
|
|
322
|
+
)
|
|
323
|
+
return _module_from_string(
|
|
324
|
+
name,
|
|
325
|
+
content,
|
|
326
|
+
fallback=fallback,
|
|
327
|
+
resolve_imports=resolve_exports,
|
|
328
|
+
resolve_imports_depth=resolve_exports_depth,
|
|
329
|
+
unmount_before_update=unmount_before_update,
|
|
330
|
+
)
|
|
331
|
+
|
|
332
|
+
|
|
333
|
+
def _module_from_url(
|
|
334
|
+
url: str,
|
|
335
|
+
fallback: Any | None = None,
|
|
336
|
+
resolve_imports: bool | None = None,
|
|
337
|
+
resolve_imports_depth: int = 5,
|
|
338
|
+
unmount_before_update: bool = False,
|
|
339
|
+
) -> WebModule:
|
|
340
|
+
return WebModule(
|
|
341
|
+
source=url,
|
|
342
|
+
source_type=URL_SOURCE,
|
|
343
|
+
default_fallback=fallback,
|
|
344
|
+
file=None,
|
|
345
|
+
export_names=(
|
|
346
|
+
resolve_module_exports_from_url(url, resolve_imports_depth)
|
|
347
|
+
if (
|
|
348
|
+
resolve_imports
|
|
349
|
+
if resolve_imports is not None
|
|
350
|
+
else REACTPY_DEBUG.current
|
|
351
|
+
)
|
|
352
|
+
else None
|
|
353
|
+
),
|
|
354
|
+
unmount_before_update=unmount_before_update,
|
|
355
|
+
)
|
|
356
|
+
|
|
357
|
+
|
|
358
|
+
def _module_from_file(
|
|
359
|
+
name: str,
|
|
360
|
+
file: str | Path,
|
|
361
|
+
fallback: Any | None = None,
|
|
362
|
+
resolve_imports: bool | None = None,
|
|
363
|
+
resolve_imports_depth: int = 5,
|
|
364
|
+
unmount_before_update: bool = False,
|
|
365
|
+
symlink: bool = False,
|
|
366
|
+
) -> WebModule:
|
|
103
367
|
name += module_name_suffix(name)
|
|
104
368
|
|
|
105
369
|
source_file = Path(file).resolve()
|
|
@@ -124,10 +388,10 @@ def module_from_file(
|
|
|
124
388
|
default_fallback=fallback,
|
|
125
389
|
file=target_file,
|
|
126
390
|
export_names=(
|
|
127
|
-
resolve_module_exports_from_file(source_file,
|
|
391
|
+
resolve_module_exports_from_file(source_file, resolve_imports_depth)
|
|
128
392
|
if (
|
|
129
|
-
|
|
130
|
-
if
|
|
393
|
+
resolve_imports
|
|
394
|
+
if resolve_imports is not None
|
|
131
395
|
else REACTPY_DEBUG.current
|
|
132
396
|
)
|
|
133
397
|
else None
|
|
@@ -152,33 +416,14 @@ def _copy_file(target: Path, source: Path, symlink: bool) -> None:
|
|
|
152
416
|
shutil.copy(source, target)
|
|
153
417
|
|
|
154
418
|
|
|
155
|
-
def
|
|
419
|
+
def _module_from_string(
|
|
156
420
|
name: str,
|
|
157
421
|
content: str,
|
|
158
422
|
fallback: Any | None = None,
|
|
159
|
-
|
|
160
|
-
|
|
423
|
+
resolve_imports: bool | None = None,
|
|
424
|
+
resolve_imports_depth: int = 5,
|
|
161
425
|
unmount_before_update: bool = False,
|
|
162
426
|
) -> WebModule:
|
|
163
|
-
"""Load a :class:`WebModule` whose ``content`` comes from a string.
|
|
164
|
-
|
|
165
|
-
Parameters:
|
|
166
|
-
name:
|
|
167
|
-
The name of the package
|
|
168
|
-
content:
|
|
169
|
-
The contents of the web module
|
|
170
|
-
fallback:
|
|
171
|
-
What to temporarily display while the module is being loaded.
|
|
172
|
-
resolve_imports:
|
|
173
|
-
Whether to try and find all the named exports of this module.
|
|
174
|
-
resolve_exports_depth:
|
|
175
|
-
How deeply to search for those exports.
|
|
176
|
-
unmount_before_update:
|
|
177
|
-
Cause the component to be unmounted before each update. This option should
|
|
178
|
-
only be used if the imported package fails to re-render when props change.
|
|
179
|
-
Using this option has negative performance consequences since all DOM
|
|
180
|
-
elements must be changed on each render. See :issue:`461` for more info.
|
|
181
|
-
"""
|
|
182
427
|
name += module_name_suffix(name)
|
|
183
428
|
|
|
184
429
|
target_file = _web_module_path(name)
|
|
@@ -199,10 +444,10 @@ def module_from_string(
|
|
|
199
444
|
default_fallback=fallback,
|
|
200
445
|
file=target_file,
|
|
201
446
|
export_names=(
|
|
202
|
-
resolve_module_exports_from_file(target_file,
|
|
447
|
+
resolve_module_exports_from_file(target_file, resolve_imports_depth)
|
|
203
448
|
if (
|
|
204
|
-
|
|
205
|
-
if
|
|
449
|
+
resolve_imports
|
|
450
|
+
if resolve_imports is not None
|
|
206
451
|
else REACTPY_DEBUG.current
|
|
207
452
|
)
|
|
208
453
|
else None
|
|
@@ -244,6 +489,19 @@ def export(
|
|
|
244
489
|
export_names: str | list[str] | tuple[str, ...],
|
|
245
490
|
fallback: Any | None = None,
|
|
246
491
|
allow_children: bool = True,
|
|
492
|
+
) -> VdomConstructor | list[VdomConstructor]: # pragma: no cover
|
|
493
|
+
warn(
|
|
494
|
+
"export is deprecated, use reactjs_component_from_* functions instead",
|
|
495
|
+
DeprecationWarning,
|
|
496
|
+
)
|
|
497
|
+
return _vdom_from_web_module(web_module, export_names, fallback, allow_children)
|
|
498
|
+
|
|
499
|
+
|
|
500
|
+
def _vdom_from_web_module(
|
|
501
|
+
web_module: WebModule,
|
|
502
|
+
export_names: str | list[str] | tuple[str, ...],
|
|
503
|
+
fallback: Any | None = None,
|
|
504
|
+
allow_children: bool = True,
|
|
247
505
|
) -> VdomConstructor | list[VdomConstructor]:
|
|
248
506
|
"""Return one or more VDOM constructors from a :class:`WebModule`
|
|
249
507
|
|
reactpy/web/utils.py
CHANGED
|
@@ -12,7 +12,7 @@ def module_name_suffix(name: str) -> str:
|
|
|
12
12
|
if name.startswith("@"):
|
|
13
13
|
name = name[1:]
|
|
14
14
|
head, _, tail = name.partition("@") # handle version identifier
|
|
15
|
-
|
|
15
|
+
_, _, tail = tail.partition("/") # get section after version
|
|
16
16
|
return PurePosixPath(tail or head).suffix or ".js"
|
|
17
17
|
|
|
18
18
|
|
reactpy/widgets.py
CHANGED
|
@@ -2,12 +2,11 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
from base64 import b64encode
|
|
4
4
|
from collections.abc import Sequence
|
|
5
|
-
from typing import
|
|
5
|
+
from typing import Any, Callable, Protocol, TypeVar
|
|
6
6
|
|
|
7
7
|
import reactpy
|
|
8
8
|
from reactpy._html import html
|
|
9
|
-
from reactpy.
|
|
10
|
-
from reactpy.types import ComponentConstructor, VdomAttributes, VdomDict
|
|
9
|
+
from reactpy.types import VdomAttributes, VdomDict
|
|
11
10
|
|
|
12
11
|
|
|
13
12
|
def image(
|
|
@@ -22,11 +21,7 @@ def image(
|
|
|
22
21
|
if format == "svg":
|
|
23
22
|
format = "svg+xml" # noqa: A001
|
|
24
23
|
|
|
25
|
-
if isinstance(value, str)
|
|
26
|
-
bytes_value = value.encode()
|
|
27
|
-
else:
|
|
28
|
-
bytes_value = value
|
|
29
|
-
|
|
24
|
+
bytes_value = value.encode() if isinstance(value, str) else value
|
|
30
25
|
base64_value = b64encode(bytes_value).decode()
|
|
31
26
|
src = f"data:image/{format};base64,{base64_value}"
|
|
32
27
|
|
|
@@ -83,20 +78,3 @@ _CastTo_co = TypeVar("_CastTo_co", covariant=True)
|
|
|
83
78
|
|
|
84
79
|
class _CastFunc(Protocol[_CastTo_co]):
|
|
85
80
|
def __call__(self, value: str) -> _CastTo_co: ...
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
if TYPE_CHECKING:
|
|
89
|
-
from reactpy.testing.backend import _MountFunc
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
def hotswap(
|
|
93
|
-
update_on_change: bool = False,
|
|
94
|
-
) -> tuple[_MountFunc, ComponentConstructor]: # nocov
|
|
95
|
-
warn(
|
|
96
|
-
"The 'hotswap' function is deprecated and will be removed in a future release",
|
|
97
|
-
DeprecationWarning,
|
|
98
|
-
stacklevel=2,
|
|
99
|
-
)
|
|
100
|
-
from reactpy.testing.backend import _hotswap
|
|
101
|
-
|
|
102
|
-
return _hotswap(update_on_change)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: reactpy
|
|
3
|
-
Version: 2.0.
|
|
3
|
+
Version: 2.0.0b4
|
|
4
4
|
Summary: It's React, but in Python.
|
|
5
5
|
Project-URL: Changelog, https://reactpy.dev/docs/about/changelog.html
|
|
6
6
|
Project-URL: Documentation, https://reactpy.dev/
|
|
@@ -44,8 +44,7 @@ Requires-Dist: jinja2-simple-tags; extra == 'jinja'
|
|
|
44
44
|
Requires-Dist: jinja2>=3; extra == 'jinja'
|
|
45
45
|
Provides-Extra: testing
|
|
46
46
|
Requires-Dist: playwright; extra == 'testing'
|
|
47
|
-
|
|
48
|
-
Requires-Dist: uvicorn[standard]; extra == 'uvicorn'
|
|
47
|
+
Requires-Dist: uvicorn[standard]; extra == 'testing'
|
|
49
48
|
Description-Content-Type: text/markdown
|
|
50
49
|
|
|
51
50
|
# <img src="https://raw.githubusercontent.com/reactive-python/reactpy/main/branding/svg/reactpy-logo-square.svg" align="left" height="45"/> ReactPy
|