reactpy 2.0.0b3__py3-none-any.whl → 2.0.0b5__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 +2 -5
- reactpy/_console/rewrite_props.py +2 -2
- reactpy/_option.py +2 -1
- reactpy/config.py +2 -2
- reactpy/core/_life_cycle_hook.py +8 -9
- reactpy/core/_thread_local.py +2 -1
- reactpy/core/component.py +4 -38
- reactpy/core/events.py +61 -48
- reactpy/core/hooks.py +26 -30
- reactpy/core/layout.py +175 -188
- reactpy/core/serve.py +9 -28
- reactpy/core/vdom.py +6 -7
- reactpy/executors/asgi/__init__.py +9 -4
- reactpy/executors/asgi/middleware.py +1 -2
- reactpy/executors/asgi/pyscript.py +3 -7
- reactpy/executors/asgi/standalone.py +4 -6
- reactpy/executors/asgi/types.py +2 -2
- reactpy/pyscript/components.py +3 -3
- reactpy/pyscript/utils.py +50 -53
- reactpy/static/index.js +2 -2
- reactpy/static/index.js.map +6 -6
- reactpy/testing/backend.py +2 -1
- reactpy/testing/common.py +3 -5
- reactpy/types.py +116 -47
- reactpy/utils.py +7 -7
- reactpy/web/module.py +87 -6
- reactpy/widgets.py +4 -26
- {reactpy-2.0.0b3.dist-info → reactpy-2.0.0b5.dist-info}/METADATA +4 -7
- {reactpy-2.0.0b3.dist-info → reactpy-2.0.0b5.dist-info}/RECORD +32 -32
- {reactpy-2.0.0b3.dist-info → reactpy-2.0.0b5.dist-info}/WHEEL +0 -0
- {reactpy-2.0.0b3.dist-info → reactpy-2.0.0b5.dist-info}/entry_points.txt +0 -0
- {reactpy-2.0.0b3.dist-info → reactpy-2.0.0b5.dist-info}/licenses/LICENSE +0 -0
reactpy/types.py
CHANGED
|
@@ -1,22 +1,24 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
import inspect
|
|
4
|
+
from collections.abc import Awaitable, Callable, Mapping, Sequence
|
|
4
5
|
from dataclasses import dataclass
|
|
5
6
|
from pathlib import Path
|
|
6
7
|
from types import TracebackType
|
|
7
8
|
from typing import (
|
|
8
9
|
Any,
|
|
9
|
-
Callable,
|
|
10
10
|
Generic,
|
|
11
11
|
Literal,
|
|
12
|
+
NamedTuple,
|
|
13
|
+
NotRequired,
|
|
12
14
|
Protocol,
|
|
15
|
+
TypeAlias,
|
|
16
|
+
TypedDict,
|
|
13
17
|
TypeVar,
|
|
18
|
+
Unpack,
|
|
14
19
|
overload,
|
|
15
|
-
runtime_checkable,
|
|
16
20
|
)
|
|
17
21
|
|
|
18
|
-
from typing_extensions import NamedTuple, NotRequired, TypeAlias, TypedDict, Unpack
|
|
19
|
-
|
|
20
22
|
CarrierType = TypeVar("CarrierType")
|
|
21
23
|
_Type = TypeVar("_Type")
|
|
22
24
|
|
|
@@ -26,54 +28,84 @@ class State(NamedTuple, Generic[_Type]):
|
|
|
26
28
|
set_value: Callable[[_Type | Callable[[_Type], _Type]], None]
|
|
27
29
|
|
|
28
30
|
|
|
29
|
-
ComponentConstructor = Callable[..., "
|
|
31
|
+
ComponentConstructor = Callable[..., "Component"]
|
|
30
32
|
"""Simple function returning a new component"""
|
|
31
33
|
|
|
32
|
-
RootComponentConstructor = Callable[[], "
|
|
34
|
+
RootComponentConstructor = Callable[[], "Component"]
|
|
33
35
|
"""The root component should be constructed by a function accepting no arguments."""
|
|
34
36
|
|
|
35
37
|
|
|
36
38
|
Key: TypeAlias = str | int
|
|
37
39
|
|
|
38
40
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
"""The expected interface for all component-like objects"""
|
|
42
|
-
|
|
43
|
-
key: Key | None
|
|
44
|
-
"""An identifier which is unique amongst a component's immediate siblings"""
|
|
41
|
+
class Component:
|
|
42
|
+
"""An object for rending component models."""
|
|
45
43
|
|
|
46
|
-
type
|
|
47
|
-
"""The function or class defining the behavior of this component
|
|
44
|
+
__slots__ = "__weakref__", "_args", "_func", "_kwargs", "_sig", "key", "type"
|
|
48
45
|
|
|
49
|
-
|
|
50
|
-
|
|
46
|
+
def __init__(
|
|
47
|
+
self,
|
|
48
|
+
function: Callable[..., Component | VdomDict | str | None],
|
|
49
|
+
key: Any | None,
|
|
50
|
+
args: tuple[Any, ...],
|
|
51
|
+
kwargs: dict[str, Any],
|
|
52
|
+
sig: inspect.Signature,
|
|
53
|
+
) -> None:
|
|
54
|
+
self.key = key
|
|
55
|
+
self.type = function
|
|
56
|
+
self._args = args
|
|
57
|
+
self._kwargs = kwargs
|
|
58
|
+
self._sig = sig
|
|
59
|
+
|
|
60
|
+
def render(self) -> Component | VdomDict | str | None:
|
|
61
|
+
return self.type(*self._args, **self._kwargs)
|
|
51
62
|
|
|
52
|
-
def
|
|
53
|
-
|
|
63
|
+
def __repr__(self) -> str:
|
|
64
|
+
try:
|
|
65
|
+
args = self._sig.bind(*self._args, **self._kwargs).arguments
|
|
66
|
+
except TypeError:
|
|
67
|
+
return f"{self.type.__name__}(...)"
|
|
68
|
+
else:
|
|
69
|
+
items = ", ".join(f"{k}={v!r}" for k, v in args.items())
|
|
70
|
+
if items:
|
|
71
|
+
return f"{self.type.__name__}({id(self):02x}, {items})"
|
|
72
|
+
else:
|
|
73
|
+
return f"{self.type.__name__}({id(self):02x})"
|
|
54
74
|
|
|
55
75
|
|
|
56
76
|
_Render_co = TypeVar("_Render_co", covariant=True)
|
|
57
77
|
_Event_contra = TypeVar("_Event_contra", contravariant=True)
|
|
58
78
|
|
|
59
79
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
80
|
+
class BaseLayout(Protocol[_Render_co, _Event_contra]):
|
|
81
|
+
"""Renders and delivers views, and submits events to handlers."""
|
|
82
|
+
|
|
83
|
+
__slots__: tuple[str, ...] = (
|
|
84
|
+
"__weakref__",
|
|
85
|
+
"_event_handlers",
|
|
86
|
+
"_model_states_by_life_cycle_state_id",
|
|
87
|
+
"_render_tasks",
|
|
88
|
+
"_render_tasks_ready",
|
|
89
|
+
"_rendering_queue",
|
|
90
|
+
"_root_life_cycle_state_id",
|
|
91
|
+
"root",
|
|
92
|
+
)
|
|
63
93
|
|
|
64
94
|
async def render(
|
|
65
95
|
self,
|
|
66
|
-
) -> _Render_co:
|
|
96
|
+
) -> _Render_co:
|
|
97
|
+
"""Render an update to a view"""
|
|
98
|
+
...
|
|
67
99
|
|
|
68
|
-
async def deliver(
|
|
69
|
-
|
|
70
|
-
|
|
100
|
+
async def deliver(self, event: _Event_contra) -> None:
|
|
101
|
+
"""Relay an event to its respective handler"""
|
|
102
|
+
...
|
|
71
103
|
|
|
72
104
|
async def __aenter__(
|
|
73
105
|
self,
|
|
74
|
-
) ->
|
|
75
|
-
|
|
76
|
-
|
|
106
|
+
) -> BaseLayout[_Render_co, _Event_contra]:
|
|
107
|
+
"""Prepare the layout for its first render"""
|
|
108
|
+
...
|
|
77
109
|
|
|
78
110
|
async def __aexit__(
|
|
79
111
|
self,
|
|
@@ -82,6 +114,7 @@ class LayoutType(Protocol[_Render_co, _Event_contra]):
|
|
|
82
114
|
traceback: TracebackType,
|
|
83
115
|
) -> bool | None:
|
|
84
116
|
"""Clean up the view after its final render"""
|
|
117
|
+
...
|
|
85
118
|
|
|
86
119
|
|
|
87
120
|
class CssStyleTypeDict(TypedDict, total=False):
|
|
@@ -787,7 +820,7 @@ class VdomTypeDict(TypedDict):
|
|
|
787
820
|
|
|
788
821
|
tagName: str
|
|
789
822
|
key: NotRequired[Key | None]
|
|
790
|
-
children: NotRequired[Sequence[
|
|
823
|
+
children: NotRequired[Sequence[Component | VdomChild]]
|
|
791
824
|
attributes: NotRequired[VdomAttributes]
|
|
792
825
|
eventHandlers: NotRequired[EventHandlerDict]
|
|
793
826
|
inlineJavaScript: NotRequired[InlineJavaScriptDict]
|
|
@@ -815,7 +848,7 @@ class VdomDict(dict):
|
|
|
815
848
|
@overload
|
|
816
849
|
def __getitem__(
|
|
817
850
|
self, key: Literal["children"]
|
|
818
|
-
) -> Sequence[
|
|
851
|
+
) -> Sequence[Component | VdomChild]: ...
|
|
819
852
|
@overload
|
|
820
853
|
def __getitem__(self, key: Literal["attributes"]) -> VdomAttributes: ...
|
|
821
854
|
@overload
|
|
@@ -833,7 +866,7 @@ class VdomDict(dict):
|
|
|
833
866
|
def __setitem__(self, key: Literal["key"], value: Key | None) -> None: ...
|
|
834
867
|
@overload
|
|
835
868
|
def __setitem__(
|
|
836
|
-
self, key: Literal["children"], value: Sequence[
|
|
869
|
+
self, key: Literal["children"], value: Sequence[Component | VdomChild]
|
|
837
870
|
) -> None: ...
|
|
838
871
|
@overload
|
|
839
872
|
def __setitem__(
|
|
@@ -857,7 +890,7 @@ class VdomDict(dict):
|
|
|
857
890
|
super().__setitem__(key, value)
|
|
858
891
|
|
|
859
892
|
|
|
860
|
-
VdomChild: TypeAlias =
|
|
893
|
+
VdomChild: TypeAlias = Component | VdomDict | str | None | Any
|
|
861
894
|
"""A single child element of a :class:`VdomDict`"""
|
|
862
895
|
|
|
863
896
|
VdomChildren: TypeAlias = Sequence[VdomChild] | VdomChild
|
|
@@ -907,19 +940,26 @@ class EventHandlerFunc(Protocol):
|
|
|
907
940
|
async def __call__(self, data: Sequence[Any]) -> None: ...
|
|
908
941
|
|
|
909
942
|
|
|
910
|
-
|
|
911
|
-
class EventHandlerType(Protocol):
|
|
943
|
+
class BaseEventHandler:
|
|
912
944
|
"""Defines a handler for some event"""
|
|
913
945
|
|
|
946
|
+
__slots__ = (
|
|
947
|
+
"__weakref__",
|
|
948
|
+
"function",
|
|
949
|
+
"prevent_default",
|
|
950
|
+
"stop_propagation",
|
|
951
|
+
"target",
|
|
952
|
+
)
|
|
953
|
+
|
|
954
|
+
function: EventHandlerFunc
|
|
955
|
+
"""A coroutine which can respond to an event and its data"""
|
|
956
|
+
|
|
914
957
|
prevent_default: bool
|
|
915
958
|
"""Whether to block the event from propagating further up the DOM"""
|
|
916
959
|
|
|
917
960
|
stop_propagation: bool
|
|
918
961
|
"""Stops the default action associate with the event from taking place."""
|
|
919
962
|
|
|
920
|
-
function: EventHandlerFunc
|
|
921
|
-
"""A coroutine which can respond to an event and its data"""
|
|
922
|
-
|
|
923
963
|
target: str | None
|
|
924
964
|
"""Typically left as ``None`` except when a static target is useful.
|
|
925
965
|
|
|
@@ -932,10 +972,10 @@ class EventHandlerType(Protocol):
|
|
|
932
972
|
"""
|
|
933
973
|
|
|
934
974
|
|
|
935
|
-
EventHandlerMapping = Mapping[str,
|
|
975
|
+
EventHandlerMapping = Mapping[str, BaseEventHandler]
|
|
936
976
|
"""A generic mapping between event names to their handlers"""
|
|
937
977
|
|
|
938
|
-
EventHandlerDict: TypeAlias = dict[str,
|
|
978
|
+
EventHandlerDict: TypeAlias = dict[str, BaseEventHandler]
|
|
939
979
|
"""A dict mapping between event names to their handlers"""
|
|
940
980
|
|
|
941
981
|
InlineJavaScriptMapping = Mapping[str, InlineJavaScript]
|
|
@@ -991,17 +1031,30 @@ class Context(Protocol[_Type]):
|
|
|
991
1031
|
*children: Any,
|
|
992
1032
|
value: _Type = ...,
|
|
993
1033
|
key: Key | None = ...,
|
|
994
|
-
) ->
|
|
1034
|
+
) -> ContextProvider[_Type]: ...
|
|
995
1035
|
|
|
996
1036
|
|
|
997
|
-
class
|
|
998
|
-
|
|
1037
|
+
class ContextProvider(Component, Generic[_Type]):
|
|
1038
|
+
def __init__(
|
|
1039
|
+
self,
|
|
1040
|
+
*children: Any,
|
|
1041
|
+
value: _Type,
|
|
1042
|
+
key: Key | None,
|
|
1043
|
+
type: Context[_Type],
|
|
1044
|
+
) -> None:
|
|
1045
|
+
self.children = children
|
|
1046
|
+
self.key = key
|
|
1047
|
+
self.type = type
|
|
1048
|
+
self.value = value
|
|
999
1049
|
|
|
1000
|
-
|
|
1001
|
-
|
|
1050
|
+
def render(self) -> VdomDict:
|
|
1051
|
+
from reactpy.core.hooks import HOOK_STACK
|
|
1002
1052
|
|
|
1003
|
-
|
|
1004
|
-
|
|
1053
|
+
HOOK_STACK.current_hook().set_context_provider(self)
|
|
1054
|
+
return VdomDict(tagName="", children=self.children)
|
|
1055
|
+
|
|
1056
|
+
def __repr__(self) -> str:
|
|
1057
|
+
return f"ContextProvider({self.type})"
|
|
1005
1058
|
|
|
1006
1059
|
|
|
1007
1060
|
@dataclass
|
|
@@ -1071,3 +1124,19 @@ class CustomVdomConstructor(Protocol):
|
|
|
1071
1124
|
class EllipsisRepr:
|
|
1072
1125
|
def __repr__(self) -> str:
|
|
1073
1126
|
return "..."
|
|
1127
|
+
|
|
1128
|
+
|
|
1129
|
+
class Event(dict):
|
|
1130
|
+
"""
|
|
1131
|
+
A light `dict` wrapper for event data passed to event handler functions.
|
|
1132
|
+
"""
|
|
1133
|
+
|
|
1134
|
+
def __getattr__(self, name: str) -> Any:
|
|
1135
|
+
value = self.get(name)
|
|
1136
|
+
return Event(value) if isinstance(value, dict) else value
|
|
1137
|
+
|
|
1138
|
+
def preventDefault(self) -> None:
|
|
1139
|
+
"""Prevent the default action of the event."""
|
|
1140
|
+
|
|
1141
|
+
def stopPropagation(self) -> None:
|
|
1142
|
+
"""Stop the event from propagating."""
|
reactpy/utils.py
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import re
|
|
4
|
-
from collections.abc import Iterable
|
|
4
|
+
from collections.abc import Callable, Iterable
|
|
5
5
|
from importlib import import_module
|
|
6
6
|
from itertools import chain
|
|
7
|
-
from typing import Any,
|
|
7
|
+
from typing import Any, Generic, TypeVar, cast
|
|
8
8
|
|
|
9
9
|
from lxml import etree
|
|
10
10
|
from lxml.html import fromstring
|
|
11
11
|
|
|
12
12
|
from reactpy import html
|
|
13
13
|
from reactpy.transforms import RequiredTransforms, attributes_to_reactjs
|
|
14
|
-
from reactpy.types import
|
|
14
|
+
from reactpy.types import Component, VdomDict
|
|
15
15
|
|
|
16
16
|
_RefValue = TypeVar("_RefValue")
|
|
17
17
|
_ModelTransform = Callable[[VdomDict], Any]
|
|
@@ -63,7 +63,7 @@ class Ref(Generic[_RefValue]):
|
|
|
63
63
|
return f"{type(self).__name__}({current})"
|
|
64
64
|
|
|
65
65
|
|
|
66
|
-
def reactpy_to_string(root: VdomDict |
|
|
66
|
+
def reactpy_to_string(root: VdomDict | Component) -> str:
|
|
67
67
|
"""Convert a ReactPy component or `reactpy.html` element into an HTML string.
|
|
68
68
|
|
|
69
69
|
Parameters:
|
|
@@ -186,7 +186,7 @@ def _add_vdom_to_etree(parent: etree._Element, vdom: VdomDict | dict[str, Any])
|
|
|
186
186
|
|
|
187
187
|
for c in vdom.get("children", []):
|
|
188
188
|
if hasattr(c, "render"):
|
|
189
|
-
c = component_to_vdom(cast(
|
|
189
|
+
c = component_to_vdom(cast(Component, c))
|
|
190
190
|
if isinstance(c, dict):
|
|
191
191
|
_add_vdom_to_etree(element, c)
|
|
192
192
|
|
|
@@ -232,14 +232,14 @@ def _generate_vdom_children(
|
|
|
232
232
|
)
|
|
233
233
|
|
|
234
234
|
|
|
235
|
-
def component_to_vdom(component:
|
|
235
|
+
def component_to_vdom(component: Component) -> VdomDict:
|
|
236
236
|
"""Convert the first render of a component into a VDOM dictionary"""
|
|
237
237
|
result = component.render()
|
|
238
238
|
|
|
239
239
|
if isinstance(result, dict):
|
|
240
240
|
return result
|
|
241
241
|
if hasattr(result, "render"):
|
|
242
|
-
return component_to_vdom(cast(
|
|
242
|
+
return component_to_vdom(cast(Component, result))
|
|
243
243
|
elif isinstance(result, str):
|
|
244
244
|
return html.div(result)
|
|
245
245
|
return html.fragment()
|
reactpy/web/module.py
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import filecmp
|
|
4
|
+
import hashlib
|
|
4
5
|
import logging
|
|
5
6
|
import shutil
|
|
6
7
|
from dataclasses import dataclass
|
|
@@ -33,6 +34,30 @@ _FILE_WEB_MODULE_CACHE: dict[str, WebModule] = {}
|
|
|
33
34
|
_STRING_WEB_MODULE_CACHE: dict[str, WebModule] = {}
|
|
34
35
|
|
|
35
36
|
|
|
37
|
+
@overload
|
|
38
|
+
def reactjs_component_from_url(
|
|
39
|
+
url: str,
|
|
40
|
+
import_names: str,
|
|
41
|
+
fallback: Any | None = ...,
|
|
42
|
+
resolve_imports: bool | None = ...,
|
|
43
|
+
resolve_imports_depth: int = ...,
|
|
44
|
+
unmount_before_update: bool = ...,
|
|
45
|
+
allow_children: bool = ...,
|
|
46
|
+
) -> VdomConstructor: ...
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
@overload
|
|
50
|
+
def reactjs_component_from_url(
|
|
51
|
+
url: str,
|
|
52
|
+
import_names: list[str] | tuple[str, ...],
|
|
53
|
+
fallback: Any | None = ...,
|
|
54
|
+
resolve_imports: bool | None = ...,
|
|
55
|
+
resolve_imports_depth: int = ...,
|
|
56
|
+
unmount_before_update: bool = ...,
|
|
57
|
+
allow_children: bool = ...,
|
|
58
|
+
) -> list[VdomConstructor]: ...
|
|
59
|
+
|
|
60
|
+
|
|
36
61
|
def reactjs_component_from_url(
|
|
37
62
|
url: str,
|
|
38
63
|
import_names: str | list[str] | tuple[str, ...],
|
|
@@ -80,10 +105,38 @@ def reactjs_component_from_url(
|
|
|
80
105
|
return _vdom_from_web_module(module, import_names, fallback, allow_children)
|
|
81
106
|
|
|
82
107
|
|
|
108
|
+
@overload
|
|
109
|
+
def reactjs_component_from_file(
|
|
110
|
+
file: str | Path,
|
|
111
|
+
import_names: str,
|
|
112
|
+
name: str = "",
|
|
113
|
+
fallback: Any | None = ...,
|
|
114
|
+
resolve_imports: bool | None = ...,
|
|
115
|
+
resolve_imports_depth: int = ...,
|
|
116
|
+
unmount_before_update: bool = ...,
|
|
117
|
+
symlink: bool = ...,
|
|
118
|
+
allow_children: bool = ...,
|
|
119
|
+
) -> VdomConstructor: ...
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
@overload
|
|
123
|
+
def reactjs_component_from_file(
|
|
124
|
+
file: str | Path,
|
|
125
|
+
import_names: list[str] | tuple[str, ...],
|
|
126
|
+
name: str = "",
|
|
127
|
+
fallback: Any | None = ...,
|
|
128
|
+
resolve_imports: bool | None = ...,
|
|
129
|
+
resolve_imports_depth: int = ...,
|
|
130
|
+
unmount_before_update: bool = ...,
|
|
131
|
+
symlink: bool = ...,
|
|
132
|
+
allow_children: bool = ...,
|
|
133
|
+
) -> list[VdomConstructor]: ...
|
|
134
|
+
|
|
135
|
+
|
|
83
136
|
def reactjs_component_from_file(
|
|
84
|
-
name: str,
|
|
85
137
|
file: str | Path,
|
|
86
138
|
import_names: str | list[str] | tuple[str, ...],
|
|
139
|
+
name: str = "",
|
|
87
140
|
fallback: Any | None = None,
|
|
88
141
|
resolve_imports: bool | None = None,
|
|
89
142
|
resolve_imports_depth: int = 5,
|
|
@@ -94,14 +147,14 @@ def reactjs_component_from_file(
|
|
|
94
147
|
"""Import a component from a file.
|
|
95
148
|
|
|
96
149
|
Parameters:
|
|
97
|
-
name:
|
|
98
|
-
The name of the package
|
|
99
150
|
file:
|
|
100
151
|
The file from which the content of the web module will be created.
|
|
101
152
|
import_names:
|
|
102
153
|
One or more component names to import. If given as a string, a single component
|
|
103
154
|
will be returned. If a list is given, then a list of components will be
|
|
104
155
|
returned.
|
|
156
|
+
name:
|
|
157
|
+
The human-readable name of the ReactJS package
|
|
105
158
|
fallback:
|
|
106
159
|
What to temporarily display while the module is being loaded.
|
|
107
160
|
resolve_imports:
|
|
@@ -118,6 +171,7 @@ def reactjs_component_from_file(
|
|
|
118
171
|
allow_children:
|
|
119
172
|
Whether or not these components can have children.
|
|
120
173
|
"""
|
|
174
|
+
name = name or hashlib.sha256(str(file).encode()).hexdigest()[:10]
|
|
121
175
|
key = f"{name}{resolve_imports}{resolve_imports_depth}{unmount_before_update}"
|
|
122
176
|
if key in _FILE_WEB_MODULE_CACHE:
|
|
123
177
|
module = _FILE_WEB_MODULE_CACHE[key]
|
|
@@ -135,10 +189,36 @@ def reactjs_component_from_file(
|
|
|
135
189
|
return _vdom_from_web_module(module, import_names, fallback, allow_children)
|
|
136
190
|
|
|
137
191
|
|
|
192
|
+
@overload
|
|
193
|
+
def reactjs_component_from_string(
|
|
194
|
+
content: str,
|
|
195
|
+
import_names: str,
|
|
196
|
+
name: str = "",
|
|
197
|
+
fallback: Any | None = ...,
|
|
198
|
+
resolve_imports: bool | None = ...,
|
|
199
|
+
resolve_imports_depth: int = ...,
|
|
200
|
+
unmount_before_update: bool = ...,
|
|
201
|
+
allow_children: bool = ...,
|
|
202
|
+
) -> VdomConstructor: ...
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
@overload
|
|
206
|
+
def reactjs_component_from_string(
|
|
207
|
+
content: str,
|
|
208
|
+
import_names: list[str] | tuple[str, ...],
|
|
209
|
+
name: str = "",
|
|
210
|
+
fallback: Any | None = ...,
|
|
211
|
+
resolve_imports: bool | None = ...,
|
|
212
|
+
resolve_imports_depth: int = ...,
|
|
213
|
+
unmount_before_update: bool = ...,
|
|
214
|
+
allow_children: bool = ...,
|
|
215
|
+
) -> list[VdomConstructor]: ...
|
|
216
|
+
|
|
217
|
+
|
|
138
218
|
def reactjs_component_from_string(
|
|
139
|
-
name: str,
|
|
140
219
|
content: str,
|
|
141
220
|
import_names: str | list[str] | tuple[str, ...],
|
|
221
|
+
name: str = "",
|
|
142
222
|
fallback: Any | None = None,
|
|
143
223
|
resolve_imports: bool | None = None,
|
|
144
224
|
resolve_imports_depth: int = 5,
|
|
@@ -148,14 +228,14 @@ def reactjs_component_from_string(
|
|
|
148
228
|
"""Import a component from a string.
|
|
149
229
|
|
|
150
230
|
Parameters:
|
|
151
|
-
name:
|
|
152
|
-
The name of the package
|
|
153
231
|
content:
|
|
154
232
|
The contents of the web module
|
|
155
233
|
import_names:
|
|
156
234
|
One or more component names to import. If given as a string, a single component
|
|
157
235
|
will be returned. If a list is given, then a list of components will be
|
|
158
236
|
returned.
|
|
237
|
+
name:
|
|
238
|
+
The human-readable name of the ReactJS package
|
|
159
239
|
fallback:
|
|
160
240
|
What to temporarily display while the module is being loaded.
|
|
161
241
|
resolve_imports:
|
|
@@ -170,6 +250,7 @@ def reactjs_component_from_string(
|
|
|
170
250
|
allow_children:
|
|
171
251
|
Whether or not these components can have children.
|
|
172
252
|
"""
|
|
253
|
+
name = name or hashlib.sha256(content.encode()).hexdigest()[:10]
|
|
173
254
|
key = f"{name}{resolve_imports}{resolve_imports_depth}{unmount_before_update}"
|
|
174
255
|
if key in _STRING_WEB_MODULE_CACHE:
|
|
175
256
|
module = _STRING_WEB_MODULE_CACHE[key]
|
reactpy/widgets.py
CHANGED
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
from base64 import b64encode
|
|
4
|
-
from collections.abc import Sequence
|
|
5
|
-
from typing import
|
|
4
|
+
from collections.abc import Callable, Sequence
|
|
5
|
+
from typing import Any, 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.0b5
|
|
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/
|
|
@@ -8,28 +8,26 @@ Project-URL: Source, https://github.com/reactive-python/reactpy
|
|
|
8
8
|
Author-email: Mark Bakhit <archiethemonger@gmail.com>, Ryan Morshead <ryan.morshead@gmail.com>
|
|
9
9
|
License-Expression: MIT
|
|
10
10
|
License-File: LICENSE
|
|
11
|
-
Keywords:
|
|
11
|
+
Keywords: asgi,components,interactive,javascript,react,reactive,reactjs,reactpy,server,website,wsgi
|
|
12
12
|
Classifier: Development Status :: 5 - Production/Stable
|
|
13
13
|
Classifier: Programming Language :: Python
|
|
14
|
-
Classifier: Programming Language :: Python :: 3.10
|
|
15
14
|
Classifier: Programming Language :: Python :: 3.11
|
|
16
15
|
Classifier: Programming Language :: Python :: 3.12
|
|
17
16
|
Classifier: Programming Language :: Python :: 3.13
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
18
18
|
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
19
19
|
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
|
20
|
-
Requires-Python: >=3.
|
|
20
|
+
Requires-Python: >=3.11
|
|
21
21
|
Requires-Dist: anyio>=3
|
|
22
22
|
Requires-Dist: fastjsonschema>=2.14.5
|
|
23
23
|
Requires-Dist: lxml>=4
|
|
24
24
|
Requires-Dist: requests>=2
|
|
25
|
-
Requires-Dist: typing-extensions>=3.10
|
|
26
25
|
Provides-Extra: all
|
|
27
26
|
Requires-Dist: asgi-tools; extra == 'all'
|
|
28
27
|
Requires-Dist: asgiref; extra == 'all'
|
|
29
28
|
Requires-Dist: jinja2-simple-tags; extra == 'all'
|
|
30
29
|
Requires-Dist: jinja2>=3; extra == 'all'
|
|
31
30
|
Requires-Dist: orjson; extra == 'all'
|
|
32
|
-
Requires-Dist: pip; extra == 'all'
|
|
33
31
|
Requires-Dist: playwright; extra == 'all'
|
|
34
32
|
Requires-Dist: servestatic; extra == 'all'
|
|
35
33
|
Requires-Dist: uvicorn[standard]; extra == 'all'
|
|
@@ -37,7 +35,6 @@ Provides-Extra: asgi
|
|
|
37
35
|
Requires-Dist: asgi-tools; extra == 'asgi'
|
|
38
36
|
Requires-Dist: asgiref; extra == 'asgi'
|
|
39
37
|
Requires-Dist: orjson; extra == 'asgi'
|
|
40
|
-
Requires-Dist: pip; extra == 'asgi'
|
|
41
38
|
Requires-Dist: servestatic; extra == 'asgi'
|
|
42
39
|
Provides-Extra: jinja
|
|
43
40
|
Requires-Dist: jinja2-simple-tags; extra == 'jinja'
|