reactpy 2.0.0b4__py3-none-any.whl → 2.0.0b6__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.
Files changed (55) hide show
  1. reactpy/__init__.py +3 -2
  2. reactpy/_console/rewrite_props.py +2 -2
  3. reactpy/_html.py +11 -9
  4. reactpy/_option.py +2 -1
  5. reactpy/config.py +2 -2
  6. reactpy/core/_life_cycle_hook.py +12 -10
  7. reactpy/core/_thread_local.py +2 -1
  8. reactpy/core/component.py +4 -38
  9. reactpy/core/events.py +61 -36
  10. reactpy/core/hooks.py +25 -35
  11. reactpy/core/layout.py +193 -201
  12. reactpy/core/serve.py +17 -22
  13. reactpy/core/vdom.py +9 -12
  14. reactpy/executors/asgi/__init__.py +9 -4
  15. reactpy/executors/asgi/middleware.py +1 -2
  16. reactpy/executors/asgi/pyscript.py +3 -7
  17. reactpy/executors/asgi/standalone.py +4 -6
  18. reactpy/executors/asgi/types.py +2 -2
  19. reactpy/pyscript/components.py +3 -3
  20. reactpy/pyscript/utils.py +49 -46
  21. reactpy/reactjs/__init__.py +353 -0
  22. reactpy/reactjs/module.py +203 -0
  23. reactpy/reactjs/types.py +7 -0
  24. reactpy/reactjs/utils.py +183 -0
  25. reactpy/static/index-h31022cd.js +5 -0
  26. reactpy/static/index-h31022cd.js.map +11 -0
  27. reactpy/static/index-sbddj6ms.js +5 -0
  28. reactpy/static/index-sbddj6ms.js.map +10 -0
  29. reactpy/static/index-y71bxs88.js +5 -0
  30. reactpy/static/index-y71bxs88.js.map +10 -0
  31. reactpy/static/index.js +2 -2
  32. reactpy/static/index.js.map +6 -10
  33. reactpy/static/react-dom.js +4 -0
  34. reactpy/static/react-dom.js.map +11 -0
  35. reactpy/static/react-jsx-runtime.js +4 -0
  36. reactpy/static/react-jsx-runtime.js.map +9 -0
  37. reactpy/static/react.js +4 -0
  38. reactpy/static/react.js.map +10 -0
  39. reactpy/testing/backend.py +6 -5
  40. reactpy/testing/common.py +3 -5
  41. reactpy/testing/display.py +2 -1
  42. reactpy/testing/logs.py +1 -1
  43. reactpy/transforms.py +2 -2
  44. reactpy/types.py +117 -58
  45. reactpy/utils.py +8 -8
  46. reactpy/web/__init__.py +0 -6
  47. reactpy/web/module.py +37 -470
  48. reactpy/web/utils.py +2 -158
  49. reactpy/widgets.py +2 -2
  50. {reactpy-2.0.0b4.dist-info → reactpy-2.0.0b6.dist-info}/METADATA +4 -7
  51. {reactpy-2.0.0b4.dist-info → reactpy-2.0.0b6.dist-info}/RECORD +54 -39
  52. reactpy/web/templates/react.js +0 -61
  53. {reactpy-2.0.0b4.dist-info → reactpy-2.0.0b6.dist-info}/WHEEL +0 -0
  54. {reactpy-2.0.0b4.dist-info → reactpy-2.0.0b6.dist-info}/entry_points.txt +0 -0
  55. {reactpy-2.0.0b4.dist-info → reactpy-2.0.0b6.dist-info}/licenses/LICENSE +0 -0
reactpy/types.py CHANGED
@@ -1,22 +1,25 @@
1
1
  from __future__ import annotations
2
2
 
3
- from collections.abc import Awaitable, Mapping, Sequence
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
+ NewType,
14
+ NotRequired,
12
15
  Protocol,
16
+ TypeAlias,
17
+ TypedDict,
13
18
  TypeVar,
19
+ Unpack,
14
20
  overload,
15
- runtime_checkable,
16
21
  )
17
22
 
18
- from typing_extensions import NamedTuple, NotRequired, TypeAlias, TypedDict, Unpack
19
-
20
23
  CarrierType = TypeVar("CarrierType")
21
24
  _Type = TypeVar("_Type")
22
25
 
@@ -26,54 +29,84 @@ class State(NamedTuple, Generic[_Type]):
26
29
  set_value: Callable[[_Type | Callable[[_Type], _Type]], None]
27
30
 
28
31
 
29
- ComponentConstructor = Callable[..., "ComponentType"]
32
+ ComponentConstructor = Callable[..., "Component"]
30
33
  """Simple function returning a new component"""
31
34
 
32
- RootComponentConstructor = Callable[[], "ComponentType"]
35
+ RootComponentConstructor = Callable[[], "Component"]
33
36
  """The root component should be constructed by a function accepting no arguments."""
34
37
 
35
38
 
36
39
  Key: TypeAlias = str | int
37
40
 
38
41
 
39
- @runtime_checkable
40
- class ComponentType(Protocol):
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"""
42
+ class Component:
43
+ """An object for rending component models."""
45
44
 
46
- type: Any
47
- """The function or class defining the behavior of this component
45
+ __slots__ = "__weakref__", "_args", "_func", "_kwargs", "_sig", "key", "type"
48
46
 
49
- This is used to see if two component instances share the same definition.
50
- """
47
+ def __init__(
48
+ self,
49
+ function: Callable[..., Component | VdomDict | str | None],
50
+ key: Any | None,
51
+ args: tuple[Any, ...],
52
+ kwargs: dict[str, Any],
53
+ sig: inspect.Signature,
54
+ ) -> None:
55
+ self.key = key
56
+ self.type = function
57
+ self._args = args
58
+ self._kwargs = kwargs
59
+ self._sig = sig
60
+
61
+ def render(self) -> Component | VdomDict | str | None:
62
+ return self.type(*self._args, **self._kwargs)
51
63
 
52
- def render(self) -> VdomDict | ComponentType | str | None:
53
- """Render the component's view model."""
64
+ def __repr__(self) -> str:
65
+ try:
66
+ args = self._sig.bind(*self._args, **self._kwargs).arguments
67
+ except TypeError:
68
+ return f"{self.type.__name__}(...)"
69
+ else:
70
+ items = ", ".join(f"{k}={v!r}" for k, v in args.items())
71
+ if items:
72
+ return f"{self.type.__name__}({id(self):02x}, {items})"
73
+ else:
74
+ return f"{self.type.__name__}({id(self):02x})"
54
75
 
55
76
 
56
77
  _Render_co = TypeVar("_Render_co", covariant=True)
57
78
  _Event_contra = TypeVar("_Event_contra", contravariant=True)
58
79
 
59
80
 
60
- @runtime_checkable
61
- class LayoutType(Protocol[_Render_co, _Event_contra]):
62
- """Renders and delivers, updates to views and events to handlers, respectively"""
81
+ class BaseLayout(Protocol[_Render_co, _Event_contra]):
82
+ """Renders and delivers views, and submits events to handlers."""
83
+
84
+ __slots__: tuple[str, ...] = (
85
+ "__weakref__",
86
+ "_event_handlers",
87
+ "_model_states_by_life_cycle_state_id",
88
+ "_render_tasks",
89
+ "_render_tasks_ready",
90
+ "_rendering_queue",
91
+ "_root_life_cycle_state_id",
92
+ "root",
93
+ )
63
94
 
64
95
  async def render(
65
96
  self,
66
- ) -> _Render_co: ... # Render an update to a view
97
+ ) -> _Render_co:
98
+ """Render an update to a view"""
99
+ ...
67
100
 
68
- async def deliver(
69
- self, event: _Event_contra
70
- ) -> None: ... # Relay an event to its respective handler
101
+ async def deliver(self, event: _Event_contra) -> None:
102
+ """Relay an event to its respective handler"""
103
+ ...
71
104
 
72
105
  async def __aenter__(
73
106
  self,
74
- ) -> LayoutType[
75
- _Render_co, _Event_contra
76
- ]: ... # Prepare the layout for its first render
107
+ ) -> BaseLayout[_Render_co, _Event_contra]:
108
+ """Prepare the layout for its first render"""
109
+ ...
77
110
 
78
111
  async def __aexit__(
79
112
  self,
@@ -82,6 +115,7 @@ class LayoutType(Protocol[_Render_co, _Event_contra]):
82
115
  traceback: TracebackType,
83
116
  ) -> bool | None:
84
117
  """Clean up the view after its final render"""
118
+ ...
85
119
 
86
120
 
87
121
  class CssStyleTypeDict(TypedDict, total=False):
@@ -500,7 +534,7 @@ class CssStyleTypeDict(TypedDict, total=False):
500
534
  zIndex: str | int
501
535
 
502
536
 
503
- # TODO: Enable `extra_items` on `CssStyleDict` when PEP 728 is merged, likely in Python 3.14. Ref: https://peps.python.org/pep-0728/
537
+ # TODO: Enable `extra_items` on `CssStyleDict` when PEP 728 is merged, likely in Python 3.15. Ref: https://peps.python.org/pep-0728/
504
538
  CssStyleDict = CssStyleTypeDict | dict[str, Any]
505
539
 
506
540
  EventFunc = Callable[[dict[str, Any]], Awaitable[None] | None]
@@ -510,8 +544,8 @@ class DangerouslySetInnerHTML(TypedDict):
510
544
  __html: str
511
545
 
512
546
 
513
- # TODO: It's probably better to break this one attributes dict down into what each specific
514
- # HTML node's attributes can be, and make sure those types are resolved correctly within `HtmlConstructor`
547
+ # TODO: It's probably better to break this down into what each HTML node's attributes can be,
548
+ # and make sure those types are resolved correctly within `HtmlConstructor`
515
549
  # TODO: This could be generated by parsing from `@types/react` in the future
516
550
  # https://www.npmjs.com/package/@types/react?activeTab=code
517
551
  VdomAttributesTypeDict = TypedDict(
@@ -764,7 +798,6 @@ VdomAttributes = VdomAttributesTypeDict | dict[str, Any]
764
798
 
765
799
  VdomDictKeys = Literal[
766
800
  "tagName",
767
- "key",
768
801
  "children",
769
802
  "attributes",
770
803
  "eventHandlers",
@@ -773,7 +806,6 @@ VdomDictKeys = Literal[
773
806
  ]
774
807
  ALLOWED_VDOM_KEYS = {
775
808
  "tagName",
776
- "key",
777
809
  "children",
778
810
  "attributes",
779
811
  "eventHandlers",
@@ -786,8 +818,7 @@ class VdomTypeDict(TypedDict):
786
818
  """TypedDict representation of what the `VdomDict` should look like."""
787
819
 
788
820
  tagName: str
789
- key: NotRequired[Key | None]
790
- children: NotRequired[Sequence[ComponentType | VdomChild]]
821
+ children: NotRequired[Sequence[Component | VdomChild]]
791
822
  attributes: NotRequired[VdomAttributes]
792
823
  eventHandlers: NotRequired[EventHandlerDict]
793
824
  inlineJavaScript: NotRequired[InlineJavaScriptDict]
@@ -811,11 +842,9 @@ class VdomDict(dict):
811
842
  @overload
812
843
  def __getitem__(self, key: Literal["tagName"]) -> str: ...
813
844
  @overload
814
- def __getitem__(self, key: Literal["key"]) -> Key | None: ...
815
- @overload
816
845
  def __getitem__(
817
846
  self, key: Literal["children"]
818
- ) -> Sequence[ComponentType | VdomChild]: ...
847
+ ) -> Sequence[Component | VdomChild]: ...
819
848
  @overload
820
849
  def __getitem__(self, key: Literal["attributes"]) -> VdomAttributes: ...
821
850
  @overload
@@ -830,10 +859,8 @@ class VdomDict(dict):
830
859
  @overload
831
860
  def __setitem__(self, key: Literal["tagName"], value: str) -> None: ...
832
861
  @overload
833
- def __setitem__(self, key: Literal["key"], value: Key | None) -> None: ...
834
- @overload
835
862
  def __setitem__(
836
- self, key: Literal["children"], value: Sequence[ComponentType | VdomChild]
863
+ self, key: Literal["children"], value: Sequence[Component | VdomChild]
837
864
  ) -> None: ...
838
865
  @overload
839
866
  def __setitem__(
@@ -857,7 +884,7 @@ class VdomDict(dict):
857
884
  super().__setitem__(key, value)
858
885
 
859
886
 
860
- VdomChild: TypeAlias = ComponentType | VdomDict | str | None | Any
887
+ VdomChild: TypeAlias = Component | VdomDict | str | None | Any
861
888
  """A single child element of a :class:`VdomDict`"""
862
889
 
863
890
  VdomChildren: TypeAlias = Sequence[VdomChild] | VdomChild
@@ -907,19 +934,26 @@ class EventHandlerFunc(Protocol):
907
934
  async def __call__(self, data: Sequence[Any]) -> None: ...
908
935
 
909
936
 
910
- @runtime_checkable
911
- class EventHandlerType(Protocol):
937
+ class BaseEventHandler:
912
938
  """Defines a handler for some event"""
913
939
 
940
+ __slots__ = (
941
+ "__weakref__",
942
+ "function",
943
+ "prevent_default",
944
+ "stop_propagation",
945
+ "target",
946
+ )
947
+
948
+ function: EventHandlerFunc
949
+ """A coroutine which can respond to an event and its data"""
950
+
914
951
  prevent_default: bool
915
952
  """Whether to block the event from propagating further up the DOM"""
916
953
 
917
954
  stop_propagation: bool
918
955
  """Stops the default action associate with the event from taking place."""
919
956
 
920
- function: EventHandlerFunc
921
- """A coroutine which can respond to an event and its data"""
922
-
923
957
  target: str | None
924
958
  """Typically left as ``None`` except when a static target is useful.
925
959
 
@@ -932,10 +966,10 @@ class EventHandlerType(Protocol):
932
966
  """
933
967
 
934
968
 
935
- EventHandlerMapping = Mapping[str, EventHandlerType]
969
+ EventHandlerMapping = Mapping[str, BaseEventHandler]
936
970
  """A generic mapping between event names to their handlers"""
937
971
 
938
- EventHandlerDict: TypeAlias = dict[str, EventHandlerType]
972
+ EventHandlerDict: TypeAlias = dict[str, BaseEventHandler]
939
973
  """A dict mapping between event names to their handlers"""
940
974
 
941
975
  InlineJavaScriptMapping = Mapping[str, InlineJavaScript]
@@ -991,17 +1025,30 @@ class Context(Protocol[_Type]):
991
1025
  *children: Any,
992
1026
  value: _Type = ...,
993
1027
  key: Key | None = ...,
994
- ) -> ContextProviderType[_Type]: ...
1028
+ ) -> ContextProvider[_Type]: ...
995
1029
 
996
1030
 
997
- class ContextProviderType(ComponentType, Protocol[_Type]):
998
- """A component which provides a context value to its children"""
1031
+ class ContextProvider(Component, Generic[_Type]):
1032
+ def __init__(
1033
+ self,
1034
+ *children: Any,
1035
+ value: _Type,
1036
+ key: Key | None,
1037
+ type: Context[_Type],
1038
+ ) -> None:
1039
+ self.children = children
1040
+ self.key = key
1041
+ self.type = type
1042
+ self.value = value
1043
+
1044
+ def render(self) -> VdomDict:
1045
+ from reactpy.core.hooks import HOOK_STACK
999
1046
 
1000
- type: Context[_Type]
1001
- """The context type"""
1047
+ HOOK_STACK.current_hook().set_context_provider(self)
1048
+ return VdomDict(tagName="", children=self.children)
1002
1049
 
1003
- @property
1004
- def value(self) -> _Type: ... # Current context value
1050
+ def __repr__(self) -> str:
1051
+ return f"ContextProvider({self.type})"
1005
1052
 
1006
1053
 
1007
1054
  @dataclass
@@ -1063,7 +1110,6 @@ class CustomVdomConstructor(Protocol):
1063
1110
  self,
1064
1111
  attributes: VdomAttributes,
1065
1112
  children: Sequence[VdomChildren],
1066
- key: Key | None,
1067
1113
  event_handlers: EventHandlerDict,
1068
1114
  ) -> VdomDict: ...
1069
1115
 
@@ -1087,3 +1133,16 @@ class Event(dict):
1087
1133
 
1088
1134
  def stopPropagation(self) -> None:
1089
1135
  """Stop the event from propagating."""
1136
+
1137
+
1138
+ SourceType = NewType("SourceType", str)
1139
+
1140
+
1141
+ @dataclass(frozen=True)
1142
+ class JavaScriptModule:
1143
+ source: str
1144
+ source_type: SourceType
1145
+ default_fallback: Any | None
1146
+ import_names: set[str] | None
1147
+ file: Path | None
1148
+ unmount_before_update: bool
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, Callable, Generic, TypeVar, cast
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 ComponentType, VdomDict
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 | ComponentType) -> str:
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(ComponentType, c))
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,17 +232,17 @@ def _generate_vdom_children(
232
232
  )
233
233
 
234
234
 
235
- def component_to_vdom(component: ComponentType) -> VdomDict:
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(ComponentType, result))
242
+ return component_to_vdom(cast(Component, result))
243
243
  elif isinstance(result, str):
244
244
  return html.div(result)
245
- return html.fragment()
245
+ return html()
246
246
 
247
247
 
248
248
  def _react_attribute_to_html(key: str, value: Any) -> tuple[str, str]:
reactpy/web/__init__.py CHANGED
@@ -3,9 +3,6 @@ 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,
9
6
  )
10
7
 
11
8
  __all__ = [
@@ -13,7 +10,4 @@ __all__ = [
13
10
  "module_from_file",
14
11
  "module_from_string",
15
12
  "module_from_url",
16
- "reactjs_component_from_file",
17
- "reactjs_component_from_string",
18
- "reactjs_component_from_url",
19
13
  ]