reflex 0.6.0__py3-none-any.whl → 0.6.0a1__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.

Potentially problematic release.


This version of reflex might be problematic. Click here for more details.

Files changed (253) hide show
  1. reflex/.templates/jinja/custom_components/pyproject.toml.jinja2 +2 -2
  2. reflex/.templates/jinja/web/pages/_app.js.jinja2 +1 -1
  3. reflex/.templates/jinja/web/pages/utils.js.jinja2 +2 -2
  4. reflex/.templates/web/components/reflex/chakra_color_mode_provider.js +36 -0
  5. reflex/.templates/web/utils/state.js +1 -3
  6. reflex/__init__.py +2 -8
  7. reflex/__init__.pyi +1 -2
  8. reflex/app.py +2 -4
  9. reflex/app_module_for_backend.py +1 -1
  10. reflex/base.py +1 -1
  11. reflex/compiler/compiler.py +2 -2
  12. reflex/compiler/utils.py +3 -3
  13. reflex/components/base/app_wrap.py +2 -2
  14. reflex/components/base/app_wrap.pyi +27 -17
  15. reflex/components/base/bare.py +5 -4
  16. reflex/components/base/body.pyi +27 -17
  17. reflex/components/base/document.pyi +131 -81
  18. reflex/components/base/error_boundary.py +7 -6
  19. reflex/components/base/error_boundary.pyi +33 -20
  20. reflex/components/base/fragment.pyi +27 -17
  21. reflex/components/base/head.pyi +53 -33
  22. reflex/components/base/link.py +1 -1
  23. reflex/components/base/link.pyi +54 -33
  24. reflex/components/base/meta.pyi +105 -65
  25. reflex/components/base/script.py +2 -1
  26. reflex/components/base/script.pyi +38 -21
  27. reflex/components/component.py +47 -53
  28. reflex/components/core/banner.py +27 -23
  29. reflex/components/core/banner.pyi +171 -134
  30. reflex/components/core/client_side_routing.py +3 -2
  31. reflex/components/core/client_side_routing.pyi +54 -33
  32. reflex/components/core/clipboard.py +1 -2
  33. reflex/components/core/clipboard.pyi +33 -20
  34. reflex/components/core/cond.py +5 -5
  35. reflex/components/core/debounce.py +5 -5
  36. reflex/components/core/debounce.pyi +33 -20
  37. reflex/components/core/foreach.py +4 -3
  38. reflex/components/core/html.py +1 -1
  39. reflex/components/core/html.pyi +46 -35
  40. reflex/components/core/match.py +17 -17
  41. reflex/components/core/upload.py +23 -17
  42. reflex/components/core/upload.pyi +124 -78
  43. reflex/components/datadisplay/code.py +10 -9
  44. reflex/components/datadisplay/code.pyi +409 -299
  45. reflex/components/datadisplay/dataeditor.py +10 -8
  46. reflex/components/datadisplay/dataeditor.pyi +53 -40
  47. reflex/components/el/element.pyi +27 -17
  48. reflex/components/el/elements/base.py +1 -1
  49. reflex/components/el/elements/base.pyi +45 -34
  50. reflex/components/el/elements/forms.py +16 -16
  51. reflex/components/el/elements/forms.pyi +707 -554
  52. reflex/components/el/elements/inline.py +1 -1
  53. reflex/components/el/elements/inline.pyi +1218 -937
  54. reflex/components/el/elements/media.py +1 -1
  55. reflex/components/el/elements/media.pyi +997 -786
  56. reflex/components/el/elements/metadata.py +6 -3
  57. reflex/components/el/elements/metadata.pyi +242 -181
  58. reflex/components/el/elements/other.py +1 -1
  59. reflex/components/el/elements/other.pyi +306 -235
  60. reflex/components/el/elements/scripts.py +1 -1
  61. reflex/components/el/elements/scripts.pyi +140 -109
  62. reflex/components/el/elements/sectioning.py +2 -0
  63. reflex/components/el/elements/sectioning.pyi +647 -496
  64. reflex/components/el/elements/tables.py +1 -1
  65. reflex/components/el/elements/tables.pyi +452 -351
  66. reflex/components/el/elements/typography.py +1 -1
  67. reflex/components/el/elements/typography.pyi +657 -506
  68. reflex/components/gridjs/datatable.py +9 -6
  69. reflex/components/gridjs/datatable.pyi +56 -35
  70. reflex/components/lucide/icon.py +1 -1
  71. reflex/components/lucide/icon.pyi +54 -33
  72. reflex/components/markdown/markdown.py +31 -26
  73. reflex/components/markdown/markdown.pyi +37 -27
  74. reflex/components/moment/moment.py +12 -13
  75. reflex/components/moment/moment.pyi +35 -23
  76. reflex/components/next/base.pyi +27 -17
  77. reflex/components/next/image.py +1 -1
  78. reflex/components/next/image.pyi +37 -22
  79. reflex/components/next/link.py +1 -1
  80. reflex/components/next/link.pyi +28 -17
  81. reflex/components/next/video.py +1 -1
  82. reflex/components/next/video.pyi +28 -17
  83. reflex/components/plotly/plotly.py +13 -12
  84. reflex/components/plotly/plotly.pyi +54 -39
  85. reflex/components/props.py +1 -1
  86. reflex/components/radix/__init__.pyi +0 -1
  87. reflex/components/radix/primitives/__init__.pyi +0 -1
  88. reflex/components/radix/primitives/accordion.py +4 -4
  89. reflex/components/radix/primitives/accordion.pyi +495 -424
  90. reflex/components/radix/primitives/base.py +1 -1
  91. reflex/components/radix/primitives/base.pyi +54 -33
  92. reflex/components/radix/primitives/drawer.py +1 -1
  93. reflex/components/radix/primitives/drawer.pyi +273 -172
  94. reflex/components/radix/primitives/form.py +1 -1
  95. reflex/components/radix/primitives/form.pyi +364 -257
  96. reflex/components/radix/primitives/progress.py +1 -1
  97. reflex/components/radix/primitives/progress.pyi +282 -231
  98. reflex/components/radix/primitives/slider.py +1 -1
  99. reflex/components/radix/primitives/slider.pyi +138 -87
  100. reflex/components/radix/themes/base.py +24 -3
  101. reflex/components/radix/themes/base.pyi +250 -178
  102. reflex/components/radix/themes/color_mode.py +5 -5
  103. reflex/components/radix/themes/color_mode.pyi +220 -187
  104. reflex/components/radix/themes/components/alert_dialog.py +1 -1
  105. reflex/components/radix/themes/components/alert_dialog.pyi +207 -136
  106. reflex/components/radix/themes/components/aspect_ratio.py +1 -1
  107. reflex/components/radix/themes/components/aspect_ratio.pyi +28 -17
  108. reflex/components/radix/themes/components/avatar.py +1 -1
  109. reflex/components/radix/themes/components/avatar.pyi +81 -70
  110. reflex/components/radix/themes/components/badge.py +1 -1
  111. reflex/components/radix/themes/components/badge.pyi +99 -88
  112. reflex/components/radix/themes/components/button.py +1 -1
  113. reflex/components/radix/themes/components/button.pyi +109 -98
  114. reflex/components/radix/themes/components/callout.py +1 -1
  115. reflex/components/radix/themes/components/callout.pyi +373 -322
  116. reflex/components/radix/themes/components/card.py +1 -1
  117. reflex/components/radix/themes/components/card.pyi +49 -38
  118. reflex/components/radix/themes/components/checkbox.py +2 -1
  119. reflex/components/radix/themes/components/checkbox.pyi +245 -208
  120. reflex/components/radix/themes/components/checkbox_cards.py +1 -1
  121. reflex/components/radix/themes/components/checkbox_cards.pyi +115 -94
  122. reflex/components/radix/themes/components/checkbox_group.py +1 -1
  123. reflex/components/radix/themes/components/checkbox_group.pyi +107 -86
  124. reflex/components/radix/themes/components/context_menu.py +1 -1
  125. reflex/components/radix/themes/components/context_menu.pyi +319 -238
  126. reflex/components/radix/themes/components/data_list.py +1 -1
  127. reflex/components/radix/themes/components/data_list.pyi +171 -130
  128. reflex/components/radix/themes/components/dialog.py +1 -1
  129. reflex/components/radix/themes/components/dialog.pyi +210 -139
  130. reflex/components/radix/themes/components/dropdown_menu.py +1 -1
  131. reflex/components/radix/themes/components/dropdown_menu.pyi +332 -249
  132. reflex/components/radix/themes/components/hover_card.py +1 -1
  133. reflex/components/radix/themes/components/hover_card.pyi +131 -90
  134. reflex/components/radix/themes/components/icon_button.py +3 -2
  135. reflex/components/radix/themes/components/icon_button.pyi +109 -98
  136. reflex/components/radix/themes/components/inset.py +1 -1
  137. reflex/components/radix/themes/components/inset.pyi +58 -47
  138. reflex/components/radix/themes/components/popover.py +1 -1
  139. reflex/components/radix/themes/components/popover.pyi +136 -95
  140. reflex/components/radix/themes/components/progress.py +1 -1
  141. reflex/components/radix/themes/components/progress.pyi +82 -71
  142. reflex/components/radix/themes/components/radio.py +1 -1
  143. reflex/components/radix/themes/components/radio.pyi +80 -69
  144. reflex/components/radix/themes/components/radio_cards.py +1 -1
  145. reflex/components/radix/themes/components/radio_cards.pyi +119 -98
  146. reflex/components/radix/themes/components/radio_group.py +11 -8
  147. reflex/components/radix/themes/components/radio_group.pyi +271 -228
  148. reflex/components/radix/themes/components/scroll_area.py +1 -1
  149. reflex/components/radix/themes/components/scroll_area.pyi +32 -21
  150. reflex/components/radix/themes/components/segmented_control.py +1 -1
  151. reflex/components/radix/themes/components/segmented_control.pyi +113 -90
  152. reflex/components/radix/themes/components/select.py +3 -2
  153. reflex/components/radix/themes/components/select.pyi +471 -374
  154. reflex/components/radix/themes/components/separator.py +2 -1
  155. reflex/components/radix/themes/components/separator.pyi +80 -69
  156. reflex/components/radix/themes/components/skeleton.py +1 -1
  157. reflex/components/radix/themes/components/skeleton.pyi +34 -23
  158. reflex/components/radix/themes/components/slider.py +3 -2
  159. reflex/components/radix/themes/components/slider.pyi +88 -75
  160. reflex/components/radix/themes/components/spinner.py +1 -1
  161. reflex/components/radix/themes/components/spinner.pyi +30 -19
  162. reflex/components/radix/themes/components/switch.py +1 -1
  163. reflex/components/radix/themes/components/switch.pyi +84 -71
  164. reflex/components/radix/themes/components/table.py +1 -1
  165. reflex/components/radix/themes/components/table.pyi +332 -261
  166. reflex/components/radix/themes/components/tabs.py +1 -1
  167. reflex/components/radix/themes/components/tabs.pyi +194 -139
  168. reflex/components/radix/themes/components/text_area.py +1 -1
  169. reflex/components/radix/themes/components/text_area.pyi +111 -96
  170. reflex/components/radix/themes/components/text_field.py +1 -1
  171. reflex/components/radix/themes/components/text_field.pyi +286 -247
  172. reflex/components/radix/themes/components/tooltip.py +1 -1
  173. reflex/components/radix/themes/components/tooltip.pyi +37 -26
  174. reflex/components/radix/themes/layout/__init__.pyi +0 -1
  175. reflex/components/radix/themes/layout/base.py +1 -1
  176. reflex/components/radix/themes/layout/base.pyi +67 -56
  177. reflex/components/radix/themes/layout/box.pyi +45 -34
  178. reflex/components/radix/themes/layout/center.pyi +67 -56
  179. reflex/components/radix/themes/layout/container.py +2 -1
  180. reflex/components/radix/themes/layout/container.pyi +47 -36
  181. reflex/components/radix/themes/layout/flex.py +1 -1
  182. reflex/components/radix/themes/layout/flex.pyi +67 -56
  183. reflex/components/radix/themes/layout/grid.py +1 -1
  184. reflex/components/radix/themes/layout/grid.pyi +75 -64
  185. reflex/components/radix/themes/layout/list.py +6 -5
  186. reflex/components/radix/themes/layout/list.pyi +244 -193
  187. reflex/components/radix/themes/layout/section.py +2 -1
  188. reflex/components/radix/themes/layout/section.pyi +47 -36
  189. reflex/components/radix/themes/layout/spacer.pyi +67 -56
  190. reflex/components/radix/themes/layout/stack.py +1 -1
  191. reflex/components/radix/themes/layout/stack.pyi +159 -128
  192. reflex/components/radix/themes/typography/blockquote.py +1 -1
  193. reflex/components/radix/themes/typography/blockquote.pyi +100 -89
  194. reflex/components/radix/themes/typography/code.py +1 -1
  195. reflex/components/radix/themes/typography/code.pyi +101 -90
  196. reflex/components/radix/themes/typography/heading.py +1 -1
  197. reflex/components/radix/themes/typography/heading.pyi +107 -96
  198. reflex/components/radix/themes/typography/link.py +1 -1
  199. reflex/components/radix/themes/typography/link.pyi +113 -102
  200. reflex/components/radix/themes/typography/text.py +1 -1
  201. reflex/components/radix/themes/typography/text.pyi +572 -501
  202. reflex/components/react_player/audio.pyi +60 -33
  203. reflex/components/react_player/react_player.py +1 -1
  204. reflex/components/react_player/react_player.pyi +60 -33
  205. reflex/components/react_player/video.pyi +60 -33
  206. reflex/components/recharts/cartesian.py +3 -2
  207. reflex/components/recharts/cartesian.pyi +861 -678
  208. reflex/components/recharts/charts.py +5 -4
  209. reflex/components/recharts/charts.pyi +357 -252
  210. reflex/components/recharts/general.py +2 -1
  211. reflex/components/recharts/general.pyi +231 -180
  212. reflex/components/recharts/polar.py +5 -4
  213. reflex/components/recharts/polar.pyi +181 -144
  214. reflex/components/recharts/recharts.pyi +53 -33
  215. reflex/components/sonner/toast.py +17 -16
  216. reflex/components/sonner/toast.pyi +47 -36
  217. reflex/components/suneditor/editor.py +3 -2
  218. reflex/components/suneditor/editor.pyi +78 -55
  219. reflex/components/tags/cond_tag.py +4 -6
  220. reflex/components/tags/iter_tag.py +16 -28
  221. reflex/components/tags/match_tag.py +4 -6
  222. reflex/components/tags/tag.py +23 -40
  223. reflex/custom_components/custom_components.py +1 -3
  224. reflex/event.py +65 -113
  225. reflex/experimental/client_state.py +24 -25
  226. reflex/experimental/hooks.py +16 -16
  227. reflex/experimental/layout.py +5 -5
  228. reflex/experimental/layout.pyi +187 -136
  229. reflex/{vars → ivars}/__init__.py +2 -6
  230. reflex/{vars → ivars}/base.py +216 -599
  231. reflex/{vars → ivars}/function.py +19 -15
  232. reflex/{vars → ivars}/number.py +20 -41
  233. reflex/{vars → ivars}/object.py +30 -28
  234. reflex/{vars → ivars}/sequence.py +50 -53
  235. reflex/middleware/hydrate_middleware.py +0 -2
  236. reflex/middleware/middleware.py +3 -3
  237. reflex/state.py +82 -148
  238. reflex/style.py +22 -21
  239. reflex/utils/exceptions.py +0 -20
  240. reflex/utils/format.py +34 -54
  241. reflex/utils/imports.py +73 -16
  242. reflex/utils/prerequisites.py +15 -35
  243. reflex/utils/pyi_generator.py +8 -13
  244. reflex/utils/serializers.py +22 -12
  245. reflex/utils/telemetry.py +2 -3
  246. reflex/utils/types.py +5 -10
  247. reflex/vars.py +501 -0
  248. {reflex-0.6.0.dist-info → reflex-0.6.0a1.dist-info}/METADATA +5 -4
  249. reflex-0.6.0a1.dist-info/RECORD +384 -0
  250. reflex-0.6.0.dist-info/RECORD +0 -382
  251. {reflex-0.6.0.dist-info → reflex-0.6.0a1.dist-info}/LICENSE +0 -0
  252. {reflex-0.6.0.dist-info → reflex-0.6.0a1.dist-info}/WHEEL +0 -0
  253. {reflex-0.6.0.dist-info → reflex-0.6.0a1.dist-info}/entry_points.txt +0 -0
@@ -2,43 +2,31 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
- import dataclasses
6
5
  import inspect
7
- from typing import (
8
- TYPE_CHECKING,
9
- Any,
10
- Callable,
11
- Iterable,
12
- Tuple,
13
- Type,
14
- Union,
15
- get_args,
16
- )
6
+ from typing import TYPE_CHECKING, Any, Callable, List, Tuple, Type, Union, get_args
17
7
 
18
8
  from reflex.components.tags.tag import Tag
19
- from reflex.vars import LiteralArrayVar, Var, get_unique_variable_name
9
+ from reflex.ivars.base import ImmutableVar
10
+ from reflex.vars import Var
20
11
 
21
12
  if TYPE_CHECKING:
22
13
  from reflex.components.component import Component
23
14
 
24
15
 
25
- @dataclasses.dataclass()
26
16
  class IterTag(Tag):
27
17
  """An iterator tag."""
28
18
 
29
19
  # The var to iterate over.
30
- iterable: Var[Iterable] = dataclasses.field(
31
- default_factory=lambda: LiteralArrayVar.create([])
32
- )
20
+ iterable: Var[List]
33
21
 
34
22
  # The component render function for each item in the iterable.
35
- render_fn: Callable = dataclasses.field(default_factory=lambda: lambda x: x)
23
+ render_fn: Callable
36
24
 
37
25
  # The name of the arg var.
38
- arg_var_name: str = dataclasses.field(default_factory=get_unique_variable_name)
26
+ arg_var_name: str
39
27
 
40
28
  # The name of the index var.
41
- index_var_name: str = dataclasses.field(default_factory=get_unique_variable_name)
29
+ index_var_name: str
42
30
 
43
31
  def get_iterable_var_type(self) -> Type:
44
32
  """Get the type of the iterable var.
@@ -46,7 +34,7 @@ class IterTag(Tag):
46
34
  Returns:
47
35
  The type of the iterable var.
48
36
  """
49
- iterable = self.iterable
37
+ iterable = self.iterable.upcast()
50
38
  try:
51
39
  if iterable._var_type.mro()[0] == dict:
52
40
  # Arg is a tuple of (key, value).
@@ -67,8 +55,8 @@ class IterTag(Tag):
67
55
  Returns:
68
56
  The index var.
69
57
  """
70
- return Var(
71
- _js_expr=self.index_var_name,
58
+ return ImmutableVar(
59
+ _var_name=self.index_var_name,
72
60
  _var_type=int,
73
61
  ).guess_type()
74
62
 
@@ -80,8 +68,8 @@ class IterTag(Tag):
80
68
  Returns:
81
69
  The arg var.
82
70
  """
83
- return Var(
84
- _js_expr=self.arg_var_name,
71
+ return ImmutableVar(
72
+ _var_name=self.arg_var_name,
85
73
  _var_type=self.get_iterable_var_type(),
86
74
  ).guess_type()
87
75
 
@@ -93,8 +81,8 @@ class IterTag(Tag):
93
81
  Returns:
94
82
  The index var.
95
83
  """
96
- return Var(
97
- _js_expr=self.index_var_name,
84
+ return ImmutableVar(
85
+ _var_name=self.index_var_name,
98
86
  _var_type=int,
99
87
  ).guess_type()
100
88
 
@@ -106,8 +94,8 @@ class IterTag(Tag):
106
94
  Returns:
107
95
  The arg var.
108
96
  """
109
- return Var(
110
- _js_expr=self.arg_var_name,
97
+ return ImmutableVar(
98
+ _var_name=self.arg_var_name,
111
99
  _var_type=self.get_iterable_var_type(),
112
100
  ).guess_type()
113
101
 
@@ -1,21 +1,19 @@
1
1
  """Tag to conditionally match cases."""
2
2
 
3
- import dataclasses
4
3
  from typing import Any, List
5
4
 
6
5
  from reflex.components.tags.tag import Tag
7
- from reflex.vars.base import Var
6
+ from reflex.vars import Var
8
7
 
9
8
 
10
- @dataclasses.dataclass()
11
9
  class MatchTag(Tag):
12
10
  """A match tag."""
13
11
 
14
12
  # The condition to determine which case to match.
15
- cond: Var[Any] = dataclasses.field(default_factory=lambda: Var.create(True))
13
+ cond: Var[Any]
16
14
 
17
15
  # The list of match cases to be matched.
18
- match_cases: List[Any] = dataclasses.field(default_factory=list)
16
+ match_cases: List[Any]
19
17
 
20
18
  # The catchall case to match.
21
- default: Any = dataclasses.field(default=Var.create(None))
19
+ default: Any
@@ -2,23 +2,22 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
- import dataclasses
6
- from typing import Any, Dict, List, Optional, Tuple, Union
5
+ from typing import Any, Dict, List, Optional, Set, Tuple, Union
7
6
 
7
+ from reflex.base import Base
8
8
  from reflex.event import EventChain
9
+ from reflex.ivars.base import ImmutableVar, LiteralVar
9
10
  from reflex.utils import format, types
10
- from reflex.vars.base import LiteralVar, Var
11
11
 
12
12
 
13
- @dataclasses.dataclass()
14
- class Tag:
13
+ class Tag(Base):
15
14
  """A React tag."""
16
15
 
17
16
  # The name of the tag.
18
17
  name: str = ""
19
18
 
20
19
  # The props of the tag.
21
- props: Dict[str, Any] = dataclasses.field(default_factory=dict)
20
+ props: Dict[str, Any] = {}
22
21
 
23
22
  # The inner contents of the tag.
24
23
  contents: str = ""
@@ -27,18 +26,25 @@ class Tag:
27
26
  args: Optional[Tuple[str, ...]] = None
28
27
 
29
28
  # Special props that aren't key value pairs.
30
- special_props: List[Var] = dataclasses.field(default_factory=list)
29
+ special_props: Set[ImmutableVar] = set()
31
30
 
32
31
  # The children components.
33
- children: List[Any] = dataclasses.field(default_factory=list)
34
-
35
- def __post_init__(self):
36
- """Post initialize the tag."""
37
- object.__setattr__(
38
- self,
39
- "props",
40
- {name: LiteralVar.create(value) for name, value in self.props.items()},
41
- )
32
+ children: List[Any] = []
33
+
34
+ def __init__(self, *args, **kwargs):
35
+ """Initialize the tag.
36
+
37
+ Args:
38
+ *args: Args to initialize the tag.
39
+ **kwargs: Kwargs to initialize the tag.
40
+ """
41
+ # Convert any props to vars.
42
+ if "props" in kwargs:
43
+ kwargs["props"] = {
44
+ name: LiteralVar.create(value)
45
+ for name, value in kwargs["props"].items()
46
+ }
47
+ super().__init__(*args, **kwargs)
42
48
 
43
49
  def format_props(self) -> List:
44
50
  """Format the tag's props.
@@ -48,29 +54,6 @@ class Tag:
48
54
  """
49
55
  return format.format_props(*self.special_props, **self.props)
50
56
 
51
- def set(self, **kwargs: Any):
52
- """Set the tag's fields.
53
-
54
- Args:
55
- kwargs: The fields to set.
56
-
57
- Returns:
58
- The tag with the fields
59
- """
60
- for name, value in kwargs.items():
61
- setattr(self, name, value)
62
-
63
- return self
64
-
65
- def __iter__(self):
66
- """Iterate over the tag's fields.
67
-
68
- Yields:
69
- Tuple[str, Any]: The field name and value.
70
- """
71
- for field in dataclasses.fields(self):
72
- yield field.name, getattr(self, field.name)
73
-
74
57
  def add_props(self, **kwargs: Optional[Any]) -> Tag:
75
58
  """Add props to the tag.
76
59
 
@@ -109,7 +92,7 @@ class Tag:
109
92
  return self
110
93
 
111
94
  @staticmethod
112
- def is_valid_prop(prop: Optional[Var]) -> bool:
95
+ def is_valid_prop(prop: Optional[ImmutableVar]) -> bool:
113
96
  """Check if the prop is valid.
114
97
 
115
98
  Args:
@@ -65,9 +65,7 @@ def _create_package_config(module_name: str, package_name: str):
65
65
  with open(CustomComponents.PYPROJECT_TOML, "w") as f:
66
66
  f.write(
67
67
  templates.CUSTOM_COMPONENTS_PYPROJECT_TOML.render(
68
- module_name=module_name,
69
- package_name=package_name,
70
- reflex_version=constants.Reflex.VERSION,
68
+ module_name=module_name, package_name=package_name
71
69
  )
72
70
  )
73
71
 
reflex/event.py CHANGED
@@ -2,7 +2,6 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
- import dataclasses
6
5
  import inspect
7
6
  import types
8
7
  import urllib.parse
@@ -19,13 +18,14 @@ from typing import (
19
18
  )
20
19
 
21
20
  from reflex import constants
21
+ from reflex.base import Base
22
+ from reflex.ivars.base import ImmutableVar, LiteralVar
23
+ from reflex.ivars.function import FunctionStringVar, FunctionVar
24
+ from reflex.ivars.object import ObjectVar
22
25
  from reflex.utils import format
23
26
  from reflex.utils.exceptions import EventFnArgMismatch, EventHandlerArgMismatch
24
27
  from reflex.utils.types import ArgsSpec
25
- from reflex.vars import VarData
26
- from reflex.vars.base import LiteralVar, Var
27
- from reflex.vars.function import FunctionStringVar, FunctionVar
28
- from reflex.vars.object import ObjectVar
28
+ from reflex.vars import Var, VarData
29
29
 
30
30
  try:
31
31
  from typing import Annotated
@@ -33,11 +33,7 @@ except ImportError:
33
33
  from typing_extensions import Annotated
34
34
 
35
35
 
36
- @dataclasses.dataclass(
37
- init=True,
38
- frozen=True,
39
- )
40
- class Event:
36
+ class Event(Base):
41
37
  """An event that describes any state change in the app."""
42
38
 
43
39
  # The token to specify the client that the event is for.
@@ -47,10 +43,10 @@ class Event:
47
43
  name: str
48
44
 
49
45
  # The routing data where event occurred
50
- router_data: Dict[str, Any] = dataclasses.field(default_factory=dict)
46
+ router_data: Dict[str, Any] = {}
51
47
 
52
48
  # The event payload.
53
- payload: Dict[str, Any] = dataclasses.field(default_factory=dict)
49
+ payload: Dict[str, Any] = {}
54
50
 
55
51
  @property
56
52
  def substate_token(self) -> str:
@@ -85,15 +81,11 @@ def background(fn):
85
81
  return fn
86
82
 
87
83
 
88
- @dataclasses.dataclass(
89
- init=True,
90
- frozen=True,
91
- )
92
- class EventActionsMixin:
84
+ class EventActionsMixin(Base):
93
85
  """Mixin for DOM event actions."""
94
86
 
95
87
  # Whether to `preventDefault` or `stopPropagation` on the event.
96
- event_actions: Dict[str, Union[bool, int]] = dataclasses.field(default_factory=dict)
88
+ event_actions: Dict[str, Union[bool, int]] = {}
97
89
 
98
90
  @property
99
91
  def stop_propagation(self):
@@ -102,9 +94,8 @@ class EventActionsMixin:
102
94
  Returns:
103
95
  New EventHandler-like with stopPropagation set to True.
104
96
  """
105
- return dataclasses.replace(
106
- self,
107
- event_actions={"stopPropagation": True, **self.event_actions},
97
+ return self.copy(
98
+ update={"event_actions": {"stopPropagation": True, **self.event_actions}},
108
99
  )
109
100
 
110
101
  @property
@@ -114,9 +105,8 @@ class EventActionsMixin:
114
105
  Returns:
115
106
  New EventHandler-like with preventDefault set to True.
116
107
  """
117
- return dataclasses.replace(
118
- self,
119
- event_actions={"preventDefault": True, **self.event_actions},
108
+ return self.copy(
109
+ update={"event_actions": {"preventDefault": True, **self.event_actions}},
120
110
  )
121
111
 
122
112
  def throttle(self, limit_ms: int):
@@ -128,9 +118,8 @@ class EventActionsMixin:
128
118
  Returns:
129
119
  New EventHandler-like with throttle set to limit_ms.
130
120
  """
131
- return dataclasses.replace(
132
- self,
133
- event_actions={"throttle": limit_ms, **self.event_actions},
121
+ return self.copy(
122
+ update={"event_actions": {"throttle": limit_ms, **self.event_actions}},
134
123
  )
135
124
 
136
125
  def debounce(self, delay_ms: int):
@@ -142,25 +131,26 @@ class EventActionsMixin:
142
131
  Returns:
143
132
  New EventHandler-like with debounce set to delay_ms.
144
133
  """
145
- return dataclasses.replace(
146
- self,
147
- event_actions={"debounce": delay_ms, **self.event_actions},
134
+ return self.copy(
135
+ update={"event_actions": {"debounce": delay_ms, **self.event_actions}},
148
136
  )
149
137
 
150
138
 
151
- @dataclasses.dataclass(
152
- init=True,
153
- frozen=True,
154
- )
155
139
  class EventHandler(EventActionsMixin):
156
140
  """An event handler responds to an event to update the state."""
157
141
 
158
142
  # The function to call in response to the event.
159
- fn: Any = dataclasses.field(default=None)
143
+ fn: Any
160
144
 
161
145
  # The full name of the state class this event handler is attached to.
162
146
  # Empty string means this event handler is a server side event.
163
- state_full_name: str = dataclasses.field(default="")
147
+ state_full_name: str = ""
148
+
149
+ class Config:
150
+ """The Pydantic config."""
151
+
152
+ # Needed to allow serialization of Callable.
153
+ frozen = True
164
154
 
165
155
  @classmethod
166
156
  def __class_getitem__(cls, args_spec: str) -> Annotated:
@@ -201,7 +191,7 @@ class EventHandler(EventActionsMixin):
201
191
 
202
192
  # Get the function args.
203
193
  fn_args = inspect.getfullargspec(self.fn).args[1:]
204
- fn_args = (Var(_js_expr=arg) for arg in fn_args)
194
+ fn_args = (ImmutableVar.create_safe(arg) for arg in fn_args)
205
195
 
206
196
  # Construct the payload.
207
197
  values = []
@@ -225,10 +215,6 @@ class EventHandler(EventActionsMixin):
225
215
  )
226
216
 
227
217
 
228
- @dataclasses.dataclass(
229
- init=True,
230
- frozen=True,
231
- )
232
218
  class EventSpec(EventActionsMixin):
233
219
  """An event specification.
234
220
 
@@ -237,37 +223,23 @@ class EventSpec(EventActionsMixin):
237
223
  """
238
224
 
239
225
  # The event handler.
240
- handler: EventHandler = dataclasses.field(default=None) # type: ignore
226
+ handler: EventHandler
241
227
 
242
228
  # The handler on the client to process event.
243
- client_handler_name: str = dataclasses.field(default="")
229
+ client_handler_name: str = ""
244
230
 
245
231
  # The arguments to pass to the function.
246
- args: Tuple[Tuple[Var, Var], ...] = dataclasses.field(default_factory=tuple)
232
+ args: Tuple[Tuple[ImmutableVar, ImmutableVar], ...] = ()
247
233
 
248
- def __init__(
249
- self,
250
- handler: EventHandler,
251
- event_actions: Dict[str, Union[bool, int]] | None = None,
252
- client_handler_name: str = "",
253
- args: Tuple[Tuple[Var, Var], ...] = tuple(),
254
- ):
255
- """Initialize an EventSpec.
234
+ class Config:
235
+ """The Pydantic config."""
256
236
 
257
- Args:
258
- event_actions: The event actions.
259
- handler: The event handler.
260
- client_handler_name: The client handler name.
261
- args: The arguments to pass to the function.
262
- """
263
- if event_actions is None:
264
- event_actions = {}
265
- object.__setattr__(self, "event_actions", event_actions)
266
- object.__setattr__(self, "handler", handler)
267
- object.__setattr__(self, "client_handler_name", client_handler_name)
268
- object.__setattr__(self, "args", args or tuple())
269
-
270
- def with_args(self, args: Tuple[Tuple[Var, Var], ...]) -> EventSpec:
237
+ # Required to allow tuple fields.
238
+ frozen = True
239
+
240
+ def with_args(
241
+ self, args: Tuple[Tuple[ImmutableVar, ImmutableVar], ...]
242
+ ) -> EventSpec:
271
243
  """Copy the event spec, with updated args.
272
244
 
273
245
  Args:
@@ -283,7 +255,7 @@ class EventSpec(EventActionsMixin):
283
255
  event_actions=self.event_actions.copy(),
284
256
  )
285
257
 
286
- def add_args(self, *args: Var) -> EventSpec:
258
+ def add_args(self, *args: ImmutableVar) -> EventSpec:
287
259
  """Add arguments to the event spec.
288
260
 
289
261
  Args:
@@ -299,7 +271,7 @@ class EventSpec(EventActionsMixin):
299
271
 
300
272
  # Get the remaining unfilled function args.
301
273
  fn_args = inspect.getfullargspec(self.handler.fn).args[1 + len(self.args) :]
302
- fn_args = (Var(_js_expr=arg) for arg in fn_args)
274
+ fn_args = (ImmutableVar.create_safe(arg) for arg in fn_args)
303
275
 
304
276
  # Construct the payload.
305
277
  values = []
@@ -314,9 +286,6 @@ class EventSpec(EventActionsMixin):
314
286
  return self.with_args(self.args + new_payload)
315
287
 
316
288
 
317
- @dataclasses.dataclass(
318
- frozen=True,
319
- )
320
289
  class CallableEventSpec(EventSpec):
321
290
  """Decorate an EventSpec-returning function to act as both a EventSpec and a function.
322
291
 
@@ -336,13 +305,10 @@ class CallableEventSpec(EventSpec):
336
305
  if fn is not None:
337
306
  default_event_spec = fn()
338
307
  super().__init__(
339
- event_actions=default_event_spec.event_actions,
340
- client_handler_name=default_event_spec.client_handler_name,
341
- args=default_event_spec.args,
342
- handler=default_event_spec.handler,
308
+ fn=fn, # type: ignore
309
+ **default_event_spec.dict(),
343
310
  **kwargs,
344
311
  )
345
- object.__setattr__(self, "fn", fn)
346
312
  else:
347
313
  super().__init__(**kwargs)
348
314
 
@@ -366,16 +332,12 @@ class CallableEventSpec(EventSpec):
366
332
  return self.fn(*args, **kwargs)
367
333
 
368
334
 
369
- @dataclasses.dataclass(
370
- init=True,
371
- frozen=True,
372
- )
373
335
  class EventChain(EventActionsMixin):
374
336
  """Container for a chain of events that will be executed in order."""
375
337
 
376
- events: List[EventSpec] = dataclasses.field(default_factory=list)
338
+ events: List[EventSpec]
377
339
 
378
- args_spec: Optional[Callable] = dataclasses.field(default=None)
340
+ args_spec: Optional[Callable]
379
341
 
380
342
 
381
343
  # These chains can be used for their side effects when no other events are desired.
@@ -383,22 +345,14 @@ stop_propagation = EventChain(events=[], args_spec=lambda: []).stop_propagation
383
345
  prevent_default = EventChain(events=[], args_spec=lambda: []).prevent_default
384
346
 
385
347
 
386
- @dataclasses.dataclass(
387
- init=True,
388
- frozen=True,
389
- )
390
- class Target:
348
+ class Target(Base):
391
349
  """A Javascript event target."""
392
350
 
393
351
  checked: bool = False
394
352
  value: Any = None
395
353
 
396
354
 
397
- @dataclasses.dataclass(
398
- init=True,
399
- frozen=True,
400
- )
401
- class FrontendEvent:
355
+ class FrontendEvent(Base):
402
356
  """A Javascript event."""
403
357
 
404
358
  target: Target = Target()
@@ -406,11 +360,7 @@ class FrontendEvent:
406
360
  value: Any = None
407
361
 
408
362
 
409
- @dataclasses.dataclass(
410
- init=True,
411
- frozen=True,
412
- )
413
- class FileUpload:
363
+ class FileUpload(Base):
414
364
  """Class to represent a file upload."""
415
365
 
416
366
  upload_id: Optional[str] = None
@@ -445,15 +395,15 @@ class FileUpload:
445
395
  upload_id = self.upload_id or DEFAULT_UPLOAD_ID
446
396
  spec_args = [
447
397
  (
448
- Var(_js_expr="files"),
449
- Var(
450
- _js_expr="filesById",
398
+ ImmutableVar.create_safe("files"),
399
+ ImmutableVar(
400
+ _var_name="filesById",
451
401
  _var_type=Dict[str, Any],
452
402
  _var_data=VarData.merge(upload_files_context_var_data),
453
403
  ).to(ObjectVar)[LiteralVar.create(upload_id)],
454
404
  ),
455
405
  (
456
- Var(_js_expr="upload_id"),
406
+ ImmutableVar.create_safe("upload_id"),
457
407
  LiteralVar.create(upload_id),
458
408
  ),
459
409
  ]
@@ -473,7 +423,7 @@ class FileUpload:
473
423
  ) # type: ignore
474
424
  else:
475
425
  raise ValueError(f"{on_upload_progress} is not a valid event handler.")
476
- if isinstance(events, Var):
426
+ if isinstance(events, ImmutableVar):
477
427
  raise ValueError(f"{on_upload_progress} cannot return a var {events}.")
478
428
  on_upload_progress_chain = EventChain(
479
429
  events=events,
@@ -482,7 +432,7 @@ class FileUpload:
482
432
  formatted_chain = str(format.format_prop(on_upload_progress_chain))
483
433
  spec_args.append(
484
434
  (
485
- Var(_js_expr="on_upload_progress"),
435
+ ImmutableVar.create_safe("on_upload_progress"),
486
436
  FunctionStringVar(
487
437
  formatted_chain.strip("{}"),
488
438
  ).to(FunctionVar, EventChain),
@@ -522,7 +472,7 @@ def server_side(name: str, sig: inspect.Signature, **kwargs) -> EventSpec:
522
472
  handler=EventHandler(fn=fn),
523
473
  args=tuple(
524
474
  (
525
- Var(_js_expr=k),
475
+ ImmutableVar.create_safe(k),
526
476
  LiteralVar.create(v),
527
477
  )
528
478
  for k, v in kwargs.items()
@@ -728,9 +678,9 @@ def set_clipboard(content: str) -> EventSpec:
728
678
 
729
679
 
730
680
  def download(
731
- url: str | Var | None = None,
732
- filename: Optional[str | Var] = None,
733
- data: str | bytes | Var | None = None,
681
+ url: str | ImmutableVar | None = None,
682
+ filename: Optional[str | ImmutableVar] = None,
683
+ data: str | bytes | ImmutableVar | None = None,
734
684
  ) -> EventSpec:
735
685
  """Download the file at a given path or with the specified data.
736
686
 
@@ -766,7 +716,7 @@ def download(
766
716
  if isinstance(data, str):
767
717
  # Caller provided a plain text string to download.
768
718
  url = "data:text/plain," + urllib.parse.quote(data)
769
- elif isinstance(data, Var):
719
+ elif isinstance(data, ImmutableVar):
770
720
  # Need to check on the frontend if the Var already looks like a data: URI.
771
721
 
772
722
  is_data_url = (data.js_type() == "string") & (
@@ -923,13 +873,15 @@ def parse_args_spec(arg_spec: ArgsSpec):
923
873
  annotations = get_type_hints(arg_spec)
924
874
  return arg_spec(
925
875
  *[
926
- Var(f"_{l_arg}").to(annotations.get(l_arg, FrontendEvent))
876
+ ImmutableVar(f"_{l_arg}").to(
877
+ ObjectVar, annotations.get(l_arg, FrontendEvent)
878
+ )
927
879
  for l_arg in spec.args
928
880
  ]
929
881
  )
930
882
 
931
883
 
932
- def call_event_fn(fn: Callable, arg_spec: ArgsSpec) -> list[EventSpec] | Var:
884
+ def call_event_fn(fn: Callable, arg_spec: ArgsSpec) -> list[EventSpec] | ImmutableVar:
933
885
  """Call a function to a list of event specs.
934
886
 
935
887
  The function should return a single EventSpec, a list of EventSpecs, or a
@@ -970,7 +922,7 @@ def call_event_fn(fn: Callable, arg_spec: ArgsSpec) -> list[EventSpec] | Var:
970
922
  out = fn(*parsed_args)
971
923
 
972
924
  # If the function returns a Var, assume it's an EventChain and render it directly.
973
- if isinstance(out, Var):
925
+ if isinstance(out, ImmutableVar):
974
926
  return out
975
927
 
976
928
  # Convert the output to a list.
@@ -999,7 +951,7 @@ def call_event_fn(fn: Callable, arg_spec: ArgsSpec) -> list[EventSpec] | Var:
999
951
 
1000
952
  def get_handler_args(
1001
953
  event_spec: EventSpec,
1002
- ) -> tuple[tuple[Var, Var], ...]:
954
+ ) -> tuple[tuple[ImmutableVar, ImmutableVar], ...]:
1003
955
  """Get the handler args for the given event spec.
1004
956
 
1005
957
  Args:
@@ -1050,7 +1002,7 @@ def fix_events(
1050
1002
  e = e()
1051
1003
  assert isinstance(e, EventSpec), f"Unexpected event type, {type(e)}."
1052
1004
  name = format.format_event_handler(e.handler)
1053
- payload = {k._js_expr: v._decode() for k, v in e.args} # type: ignore
1005
+ payload = {k._var_name: v._decode() for k, v in e.args} # type: ignore
1054
1006
 
1055
1007
  # Filter router_data to reduce payload size
1056
1008
  event_router_data = {