reflex 0.6.0a1__py3-none-any.whl → 0.6.0a2__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 (249) hide show
  1. reflex/.templates/jinja/web/pages/_app.js.jinja2 +1 -1
  2. reflex/.templates/jinja/web/pages/utils.js.jinja2 +2 -2
  3. reflex/__init__.py +8 -2
  4. reflex/__init__.pyi +2 -1
  5. reflex/app.py +4 -2
  6. reflex/base.py +1 -1
  7. reflex/compiler/compiler.py +2 -2
  8. reflex/compiler/utils.py +3 -3
  9. reflex/components/base/app_wrap.py +2 -2
  10. reflex/components/base/app_wrap.pyi +17 -27
  11. reflex/components/base/bare.py +4 -5
  12. reflex/components/base/body.pyi +17 -27
  13. reflex/components/base/document.pyi +81 -131
  14. reflex/components/base/error_boundary.py +6 -7
  15. reflex/components/base/error_boundary.pyi +20 -33
  16. reflex/components/base/fragment.pyi +17 -27
  17. reflex/components/base/head.pyi +33 -53
  18. reflex/components/base/link.py +1 -1
  19. reflex/components/base/link.pyi +33 -54
  20. reflex/components/base/meta.pyi +65 -105
  21. reflex/components/base/script.py +1 -2
  22. reflex/components/base/script.pyi +21 -38
  23. reflex/components/component.py +48 -47
  24. reflex/components/core/banner.py +23 -27
  25. reflex/components/core/banner.pyi +134 -171
  26. reflex/components/core/client_side_routing.py +2 -3
  27. reflex/components/core/client_side_routing.pyi +33 -54
  28. reflex/components/core/clipboard.py +2 -1
  29. reflex/components/core/clipboard.pyi +20 -33
  30. reflex/components/core/cond.py +5 -5
  31. reflex/components/core/debounce.py +5 -5
  32. reflex/components/core/debounce.pyi +20 -33
  33. reflex/components/core/foreach.py +3 -4
  34. reflex/components/core/html.py +1 -1
  35. reflex/components/core/html.pyi +35 -46
  36. reflex/components/core/match.py +17 -17
  37. reflex/components/core/upload.py +17 -23
  38. reflex/components/core/upload.pyi +78 -124
  39. reflex/components/datadisplay/code.py +9 -10
  40. reflex/components/datadisplay/code.pyi +302 -412
  41. reflex/components/datadisplay/dataeditor.py +8 -10
  42. reflex/components/datadisplay/dataeditor.pyi +40 -53
  43. reflex/components/el/element.pyi +17 -27
  44. reflex/components/el/elements/base.py +1 -1
  45. reflex/components/el/elements/base.pyi +34 -45
  46. reflex/components/el/elements/forms.py +16 -16
  47. reflex/components/el/elements/forms.pyi +554 -707
  48. reflex/components/el/elements/inline.py +1 -1
  49. reflex/components/el/elements/inline.pyi +937 -1218
  50. reflex/components/el/elements/media.py +1 -1
  51. reflex/components/el/elements/media.pyi +786 -997
  52. reflex/components/el/elements/metadata.py +3 -6
  53. reflex/components/el/elements/metadata.pyi +181 -242
  54. reflex/components/el/elements/other.py +1 -1
  55. reflex/components/el/elements/other.pyi +235 -306
  56. reflex/components/el/elements/scripts.py +1 -1
  57. reflex/components/el/elements/scripts.pyi +109 -140
  58. reflex/components/el/elements/sectioning.py +0 -2
  59. reflex/components/el/elements/sectioning.pyi +496 -647
  60. reflex/components/el/elements/tables.py +1 -1
  61. reflex/components/el/elements/tables.pyi +351 -452
  62. reflex/components/el/elements/typography.py +1 -1
  63. reflex/components/el/elements/typography.pyi +506 -657
  64. reflex/components/gridjs/datatable.py +6 -9
  65. reflex/components/gridjs/datatable.pyi +35 -56
  66. reflex/components/lucide/icon.py +1 -1
  67. reflex/components/lucide/icon.pyi +33 -54
  68. reflex/components/markdown/markdown.py +26 -31
  69. reflex/components/markdown/markdown.pyi +27 -37
  70. reflex/components/moment/moment.py +13 -12
  71. reflex/components/moment/moment.pyi +23 -35
  72. reflex/components/next/base.pyi +17 -27
  73. reflex/components/next/image.py +1 -1
  74. reflex/components/next/image.pyi +22 -37
  75. reflex/components/next/link.py +1 -1
  76. reflex/components/next/link.pyi +17 -28
  77. reflex/components/next/video.py +1 -1
  78. reflex/components/next/video.pyi +17 -28
  79. reflex/components/plotly/plotly.py +12 -13
  80. reflex/components/plotly/plotly.pyi +39 -54
  81. reflex/components/props.py +1 -1
  82. reflex/components/radix/__init__.pyi +1 -0
  83. reflex/components/radix/primitives/__init__.pyi +1 -0
  84. reflex/components/radix/primitives/accordion.py +4 -4
  85. reflex/components/radix/primitives/accordion.pyi +424 -495
  86. reflex/components/radix/primitives/base.py +1 -1
  87. reflex/components/radix/primitives/base.pyi +33 -54
  88. reflex/components/radix/primitives/drawer.py +1 -1
  89. reflex/components/radix/primitives/drawer.pyi +172 -273
  90. reflex/components/radix/primitives/form.py +1 -1
  91. reflex/components/radix/primitives/form.pyi +257 -364
  92. reflex/components/radix/primitives/progress.py +1 -1
  93. reflex/components/radix/primitives/progress.pyi +231 -282
  94. reflex/components/radix/primitives/slider.py +1 -1
  95. reflex/components/radix/primitives/slider.pyi +87 -138
  96. reflex/components/radix/themes/base.py +3 -24
  97. reflex/components/radix/themes/base.pyi +178 -250
  98. reflex/components/radix/themes/color_mode.py +5 -5
  99. reflex/components/radix/themes/color_mode.pyi +187 -220
  100. reflex/components/radix/themes/components/alert_dialog.py +1 -1
  101. reflex/components/radix/themes/components/alert_dialog.pyi +136 -207
  102. reflex/components/radix/themes/components/aspect_ratio.py +1 -1
  103. reflex/components/radix/themes/components/aspect_ratio.pyi +17 -28
  104. reflex/components/radix/themes/components/avatar.py +1 -1
  105. reflex/components/radix/themes/components/avatar.pyi +70 -81
  106. reflex/components/radix/themes/components/badge.py +1 -1
  107. reflex/components/radix/themes/components/badge.pyi +88 -99
  108. reflex/components/radix/themes/components/button.py +1 -1
  109. reflex/components/radix/themes/components/button.pyi +98 -109
  110. reflex/components/radix/themes/components/callout.py +1 -1
  111. reflex/components/radix/themes/components/callout.pyi +322 -373
  112. reflex/components/radix/themes/components/card.py +1 -1
  113. reflex/components/radix/themes/components/card.pyi +38 -49
  114. reflex/components/radix/themes/components/checkbox.py +1 -2
  115. reflex/components/radix/themes/components/checkbox.pyi +208 -245
  116. reflex/components/radix/themes/components/checkbox_cards.py +1 -1
  117. reflex/components/radix/themes/components/checkbox_cards.pyi +94 -115
  118. reflex/components/radix/themes/components/checkbox_group.py +1 -1
  119. reflex/components/radix/themes/components/checkbox_group.pyi +86 -107
  120. reflex/components/radix/themes/components/context_menu.py +1 -1
  121. reflex/components/radix/themes/components/context_menu.pyi +238 -319
  122. reflex/components/radix/themes/components/data_list.py +1 -1
  123. reflex/components/radix/themes/components/data_list.pyi +130 -171
  124. reflex/components/radix/themes/components/dialog.py +1 -1
  125. reflex/components/radix/themes/components/dialog.pyi +139 -210
  126. reflex/components/radix/themes/components/dropdown_menu.py +1 -1
  127. reflex/components/radix/themes/components/dropdown_menu.pyi +249 -332
  128. reflex/components/radix/themes/components/hover_card.py +1 -1
  129. reflex/components/radix/themes/components/hover_card.pyi +90 -131
  130. reflex/components/radix/themes/components/icon_button.py +2 -3
  131. reflex/components/radix/themes/components/icon_button.pyi +98 -109
  132. reflex/components/radix/themes/components/inset.py +1 -1
  133. reflex/components/radix/themes/components/inset.pyi +47 -58
  134. reflex/components/radix/themes/components/popover.py +1 -1
  135. reflex/components/radix/themes/components/popover.pyi +95 -136
  136. reflex/components/radix/themes/components/progress.py +1 -1
  137. reflex/components/radix/themes/components/progress.pyi +71 -82
  138. reflex/components/radix/themes/components/radio.py +1 -1
  139. reflex/components/radix/themes/components/radio.pyi +69 -80
  140. reflex/components/radix/themes/components/radio_cards.py +1 -1
  141. reflex/components/radix/themes/components/radio_cards.pyi +98 -119
  142. reflex/components/radix/themes/components/radio_group.py +8 -11
  143. reflex/components/radix/themes/components/radio_group.pyi +228 -271
  144. reflex/components/radix/themes/components/scroll_area.py +1 -1
  145. reflex/components/radix/themes/components/scroll_area.pyi +21 -32
  146. reflex/components/radix/themes/components/segmented_control.py +1 -1
  147. reflex/components/radix/themes/components/segmented_control.pyi +90 -113
  148. reflex/components/radix/themes/components/select.py +2 -3
  149. reflex/components/radix/themes/components/select.pyi +374 -471
  150. reflex/components/radix/themes/components/separator.py +1 -2
  151. reflex/components/radix/themes/components/separator.pyi +69 -80
  152. reflex/components/radix/themes/components/skeleton.py +1 -1
  153. reflex/components/radix/themes/components/skeleton.pyi +23 -34
  154. reflex/components/radix/themes/components/slider.py +2 -3
  155. reflex/components/radix/themes/components/slider.pyi +75 -88
  156. reflex/components/radix/themes/components/spinner.py +1 -1
  157. reflex/components/radix/themes/components/spinner.pyi +19 -30
  158. reflex/components/radix/themes/components/switch.py +1 -1
  159. reflex/components/radix/themes/components/switch.pyi +71 -84
  160. reflex/components/radix/themes/components/table.py +1 -1
  161. reflex/components/radix/themes/components/table.pyi +261 -332
  162. reflex/components/radix/themes/components/tabs.py +1 -1
  163. reflex/components/radix/themes/components/tabs.pyi +139 -194
  164. reflex/components/radix/themes/components/text_area.py +1 -1
  165. reflex/components/radix/themes/components/text_area.pyi +96 -111
  166. reflex/components/radix/themes/components/text_field.py +1 -1
  167. reflex/components/radix/themes/components/text_field.pyi +247 -286
  168. reflex/components/radix/themes/components/tooltip.py +1 -1
  169. reflex/components/radix/themes/components/tooltip.pyi +26 -37
  170. reflex/components/radix/themes/layout/__init__.pyi +1 -0
  171. reflex/components/radix/themes/layout/base.py +1 -1
  172. reflex/components/radix/themes/layout/base.pyi +56 -67
  173. reflex/components/radix/themes/layout/box.pyi +34 -45
  174. reflex/components/radix/themes/layout/center.pyi +56 -67
  175. reflex/components/radix/themes/layout/container.py +1 -2
  176. reflex/components/radix/themes/layout/container.pyi +36 -47
  177. reflex/components/radix/themes/layout/flex.py +1 -1
  178. reflex/components/radix/themes/layout/flex.pyi +56 -67
  179. reflex/components/radix/themes/layout/grid.py +1 -1
  180. reflex/components/radix/themes/layout/grid.pyi +64 -75
  181. reflex/components/radix/themes/layout/list.py +5 -6
  182. reflex/components/radix/themes/layout/list.pyi +193 -244
  183. reflex/components/radix/themes/layout/section.py +1 -2
  184. reflex/components/radix/themes/layout/section.pyi +36 -47
  185. reflex/components/radix/themes/layout/spacer.pyi +56 -67
  186. reflex/components/radix/themes/layout/stack.py +1 -1
  187. reflex/components/radix/themes/layout/stack.pyi +128 -159
  188. reflex/components/radix/themes/typography/blockquote.py +1 -1
  189. reflex/components/radix/themes/typography/blockquote.pyi +89 -100
  190. reflex/components/radix/themes/typography/code.py +1 -1
  191. reflex/components/radix/themes/typography/code.pyi +90 -101
  192. reflex/components/radix/themes/typography/heading.py +1 -1
  193. reflex/components/radix/themes/typography/heading.pyi +96 -107
  194. reflex/components/radix/themes/typography/link.py +1 -1
  195. reflex/components/radix/themes/typography/link.pyi +102 -113
  196. reflex/components/radix/themes/typography/text.py +1 -1
  197. reflex/components/radix/themes/typography/text.pyi +501 -572
  198. reflex/components/react_player/audio.pyi +33 -60
  199. reflex/components/react_player/react_player.py +1 -1
  200. reflex/components/react_player/react_player.pyi +33 -60
  201. reflex/components/react_player/video.pyi +33 -60
  202. reflex/components/recharts/cartesian.py +2 -3
  203. reflex/components/recharts/cartesian.pyi +678 -861
  204. reflex/components/recharts/charts.py +4 -5
  205. reflex/components/recharts/charts.pyi +252 -357
  206. reflex/components/recharts/general.py +1 -2
  207. reflex/components/recharts/general.pyi +180 -231
  208. reflex/components/recharts/polar.py +4 -5
  209. reflex/components/recharts/polar.pyi +144 -181
  210. reflex/components/recharts/recharts.pyi +33 -53
  211. reflex/components/sonner/toast.py +16 -17
  212. reflex/components/sonner/toast.pyi +36 -47
  213. reflex/components/suneditor/editor.py +2 -3
  214. reflex/components/suneditor/editor.pyi +55 -78
  215. reflex/components/tags/cond_tag.py +6 -4
  216. reflex/components/tags/iter_tag.py +28 -16
  217. reflex/components/tags/match_tag.py +6 -4
  218. reflex/components/tags/tag.py +40 -23
  219. reflex/event.py +113 -65
  220. reflex/experimental/client_state.py +18 -18
  221. reflex/experimental/hooks.py +16 -16
  222. reflex/experimental/layout.py +5 -5
  223. reflex/experimental/layout.pyi +136 -187
  224. reflex/middleware/hydrate_middleware.py +2 -0
  225. reflex/middleware/middleware.py +3 -3
  226. reflex/state.py +148 -82
  227. reflex/style.py +21 -22
  228. reflex/utils/exceptions.py +16 -0
  229. reflex/utils/format.py +22 -34
  230. reflex/utils/imports.py +16 -73
  231. reflex/utils/prerequisites.py +15 -8
  232. reflex/utils/pyi_generator.py +13 -8
  233. reflex/utils/serializers.py +12 -22
  234. reflex/utils/telemetry.py +2 -1
  235. reflex/utils/types.py +10 -5
  236. reflex/{ivars → vars}/__init__.py +6 -2
  237. reflex/{ivars → vars}/base.py +567 -206
  238. reflex/{ivars → vars}/function.py +15 -19
  239. reflex/{ivars → vars}/number.py +16 -18
  240. reflex/{ivars → vars}/object.py +28 -30
  241. reflex/{ivars → vars}/sequence.py +53 -42
  242. {reflex-0.6.0a1.dist-info → reflex-0.6.0a2.dist-info}/METADATA +2 -2
  243. reflex-0.6.0a2.dist-info/RECORD +382 -0
  244. reflex/.templates/web/components/reflex/chakra_color_mode_provider.js +0 -36
  245. reflex/vars.py +0 -501
  246. reflex-0.6.0a1.dist-info/RECORD +0 -384
  247. {reflex-0.6.0a1.dist-info → reflex-0.6.0a2.dist-info}/LICENSE +0 -0
  248. {reflex-0.6.0a1.dist-info → reflex-0.6.0a2.dist-info}/WHEEL +0 -0
  249. {reflex-0.6.0a1.dist-info → reflex-0.6.0a2.dist-info}/entry_points.txt +0 -0
reflex/state.py CHANGED
@@ -5,6 +5,7 @@ from __future__ import annotations
5
5
  import asyncio
6
6
  import contextlib
7
7
  import copy
8
+ import dataclasses
8
9
  import functools
9
10
  import inspect
10
11
  import os
@@ -34,11 +35,11 @@ import dill
34
35
  from sqlalchemy.orm import DeclarativeBase
35
36
 
36
37
  from reflex.config import get_config
37
- from reflex.ivars.base import (
38
+ from reflex.vars.base import (
39
+ ComputedVar,
38
40
  DynamicRouteVar,
39
- ImmutableComputedVar,
40
- ImmutableVar,
41
- immutable_computed_var,
41
+ Var,
42
+ computed_var,
42
43
  is_computed_var,
43
44
  )
44
45
 
@@ -62,7 +63,10 @@ from reflex.event import (
62
63
  )
63
64
  from reflex.utils import console, format, path_ops, prerequisites, types
64
65
  from reflex.utils.exceptions import (
66
+ ComputedVarShadowsBaseVars,
67
+ ComputedVarShadowsStateVar,
65
68
  DynamicRouteArgShadowsStateVar,
69
+ EventHandlerShadowsBuiltInStateMethod,
66
70
  ImmutableStateError,
67
71
  LockExpiredError,
68
72
  )
@@ -76,20 +80,22 @@ if TYPE_CHECKING:
76
80
 
77
81
 
78
82
  Delta = Dict[str, Any]
79
- var = immutable_computed_var
83
+ var = computed_var
80
84
 
81
85
 
82
86
  # If the state is this large, it's considered a performance issue.
83
87
  TOO_LARGE_SERIALIZED_STATE = 100 * 1024 # 100kb
84
88
 
85
89
 
86
- class HeaderData(Base):
90
+ @dataclasses.dataclass(frozen=True)
91
+ class HeaderData:
87
92
  """An object containing headers data."""
88
93
 
89
94
  host: str = ""
90
95
  origin: str = ""
91
96
  upgrade: str = ""
92
97
  connection: str = ""
98
+ cookie: str = ""
93
99
  pragma: str = ""
94
100
  cache_control: str = ""
95
101
  user_agent: str = ""
@@ -105,13 +111,16 @@ class HeaderData(Base):
105
111
  Args:
106
112
  router_data: the router_data dict.
107
113
  """
108
- super().__init__()
109
114
  if router_data:
110
115
  for k, v in router_data.get(constants.RouteVar.HEADERS, {}).items():
111
- setattr(self, format.to_snake_case(k), v)
116
+ object.__setattr__(self, format.to_snake_case(k), v)
117
+ else:
118
+ for k in dataclasses.fields(self):
119
+ object.__setattr__(self, k.name, "")
112
120
 
113
121
 
114
- class PageData(Base):
122
+ @dataclasses.dataclass(frozen=True)
123
+ class PageData:
115
124
  """An object containing page data."""
116
125
 
117
126
  host: str = "" # repeated with self.headers.origin (remove or keep the duplicate?)
@@ -119,7 +128,7 @@ class PageData(Base):
119
128
  raw_path: str = ""
120
129
  full_path: str = ""
121
130
  full_raw_path: str = ""
122
- params: dict = {}
131
+ params: dict = dataclasses.field(default_factory=dict)
123
132
 
124
133
  def __init__(self, router_data: Optional[dict] = None):
125
134
  """Initalize the PageData object based on router_data.
@@ -127,17 +136,34 @@ class PageData(Base):
127
136
  Args:
128
137
  router_data: the router_data dict.
129
138
  """
130
- super().__init__()
131
139
  if router_data:
132
- self.host = router_data.get(constants.RouteVar.HEADERS, {}).get("origin")
133
- self.path = router_data.get(constants.RouteVar.PATH, "")
134
- self.raw_path = router_data.get(constants.RouteVar.ORIGIN, "")
135
- self.full_path = f"{self.host}{self.path}"
136
- self.full_raw_path = f"{self.host}{self.raw_path}"
137
- self.params = router_data.get(constants.RouteVar.QUERY, {})
140
+ object.__setattr__(
141
+ self,
142
+ "host",
143
+ router_data.get(constants.RouteVar.HEADERS, {}).get("origin", ""),
144
+ )
145
+ object.__setattr__(
146
+ self, "path", router_data.get(constants.RouteVar.PATH, "")
147
+ )
148
+ object.__setattr__(
149
+ self, "raw_path", router_data.get(constants.RouteVar.ORIGIN, "")
150
+ )
151
+ object.__setattr__(self, "full_path", f"{self.host}{self.path}")
152
+ object.__setattr__(self, "full_raw_path", f"{self.host}{self.raw_path}")
153
+ object.__setattr__(
154
+ self, "params", router_data.get(constants.RouteVar.QUERY, {})
155
+ )
156
+ else:
157
+ object.__setattr__(self, "host", "")
158
+ object.__setattr__(self, "path", "")
159
+ object.__setattr__(self, "raw_path", "")
160
+ object.__setattr__(self, "full_path", "")
161
+ object.__setattr__(self, "full_raw_path", "")
162
+ object.__setattr__(self, "params", {})
138
163
 
139
164
 
140
- class SessionData(Base):
165
+ @dataclasses.dataclass(frozen=True, init=False)
166
+ class SessionData:
141
167
  """An object containing session data."""
142
168
 
143
169
  client_token: str = ""
@@ -150,19 +176,24 @@ class SessionData(Base):
150
176
  Args:
151
177
  router_data: the router_data dict.
152
178
  """
153
- super().__init__()
154
179
  if router_data:
155
- self.client_token = router_data.get(constants.RouteVar.CLIENT_TOKEN, "")
156
- self.client_ip = router_data.get(constants.RouteVar.CLIENT_IP, "")
157
- self.session_id = router_data.get(constants.RouteVar.SESSION_ID, "")
180
+ client_token = router_data.get(constants.RouteVar.CLIENT_TOKEN, "")
181
+ client_ip = router_data.get(constants.RouteVar.CLIENT_IP, "")
182
+ session_id = router_data.get(constants.RouteVar.SESSION_ID, "")
183
+ else:
184
+ client_token = client_ip = session_id = ""
185
+ object.__setattr__(self, "client_token", client_token)
186
+ object.__setattr__(self, "client_ip", client_ip)
187
+ object.__setattr__(self, "session_id", session_id)
158
188
 
159
189
 
160
- class RouterData(Base):
190
+ @dataclasses.dataclass(frozen=True, init=False)
191
+ class RouterData:
161
192
  """An object containing RouterData."""
162
193
 
163
- session: SessionData = SessionData()
164
- headers: HeaderData = HeaderData()
165
- page: PageData = PageData()
194
+ session: SessionData = dataclasses.field(default_factory=SessionData)
195
+ headers: HeaderData = dataclasses.field(default_factory=HeaderData)
196
+ page: PageData = dataclasses.field(default_factory=PageData)
166
197
 
167
198
  def __init__(self, router_data: Optional[dict] = None):
168
199
  """Initialize the RouterData object.
@@ -170,10 +201,9 @@ class RouterData(Base):
170
201
  Args:
171
202
  router_data: the router_data dict.
172
203
  """
173
- super().__init__()
174
- self.session = SessionData(router_data)
175
- self.headers = HeaderData(router_data)
176
- self.page = PageData(router_data)
204
+ object.__setattr__(self, "session", SessionData(router_data))
205
+ object.__setattr__(self, "headers", HeaderData(router_data))
206
+ object.__setattr__(self, "page", PageData(router_data))
177
207
 
178
208
 
179
209
  def _no_chain_background_task(
@@ -249,10 +279,11 @@ def _split_substate_key(substate_key: str) -> tuple[str, str]:
249
279
  return token, state_name
250
280
 
251
281
 
282
+ @dataclasses.dataclass(frozen=True, init=False)
252
283
  class EventHandlerSetVar(EventHandler):
253
284
  """A special event handler to wrap setvar functionality."""
254
285
 
255
- state_cls: Type[BaseState]
286
+ state_cls: Type[BaseState] = dataclasses.field(init=False)
256
287
 
257
288
  def __init__(self, state_cls: Type[BaseState]):
258
289
  """Initialize the EventHandlerSetVar.
@@ -263,8 +294,8 @@ class EventHandlerSetVar(EventHandler):
263
294
  super().__init__(
264
295
  fn=type(self).setvar,
265
296
  state_full_name=state_cls.get_full_name(),
266
- state_cls=state_cls, # type: ignore
267
297
  )
298
+ object.__setattr__(self, "state_cls", state_cls)
268
299
 
269
300
  def setvar(self, var_name: str, value: Any):
270
301
  """Set the state variable to the value of the event.
@@ -309,16 +340,16 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
309
340
  """The state of the app."""
310
341
 
311
342
  # A map from the var name to the var.
312
- vars: ClassVar[Dict[str, ImmutableVar]] = {}
343
+ vars: ClassVar[Dict[str, Var]] = {}
313
344
 
314
345
  # The base vars of the class.
315
- base_vars: ClassVar[Dict[str, ImmutableVar]] = {}
346
+ base_vars: ClassVar[Dict[str, Var]] = {}
316
347
 
317
348
  # The computed vars of the class.
318
- computed_vars: ClassVar[Dict[str, ImmutableComputedVar]] = {}
349
+ computed_vars: ClassVar[Dict[str, ComputedVar]] = {}
319
350
 
320
351
  # Vars inherited by the parent state.
321
- inherited_vars: ClassVar[Dict[str, ImmutableVar]] = {}
352
+ inherited_vars: ClassVar[Dict[str, Var]] = {}
322
353
 
323
354
  # Backend base vars that are never sent to the client.
324
355
  backend_vars: ClassVar[Dict[str, Any]] = {}
@@ -428,7 +459,7 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
428
459
  return f"{self.__class__.__name__}({self.dict()})"
429
460
 
430
461
  @classmethod
431
- def _get_computed_vars(cls) -> list[ImmutableComputedVar]:
462
+ def _get_computed_vars(cls) -> list[ComputedVar]:
432
463
  """Helper function to get all computed vars of a instance.
433
464
 
434
465
  Returns:
@@ -525,8 +556,8 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
525
556
 
526
557
  # Set the base and computed vars.
527
558
  cls.base_vars = {
528
- f.name: ImmutableVar(
529
- _var_name=format.format_state_name(cls.get_full_name()) + "." + f.name,
559
+ f.name: Var(
560
+ _js_expr=format.format_state_name(cls.get_full_name()) + "." + f.name,
530
561
  _var_type=f.outer_type_,
531
562
  _var_data=VarData.from_state(cls),
532
563
  ).guess_type()
@@ -534,7 +565,7 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
534
565
  if f.name not in cls.get_skip_vars()
535
566
  }
536
567
  cls.computed_vars = {
537
- v._var_name: v._replace(merge_var_data=VarData.from_state(cls))
568
+ v._js_expr: v._replace(merge_var_data=VarData.from_state(cls))
538
569
  for v in computed_vars
539
570
  }
540
571
  cls.vars = {
@@ -564,8 +595,8 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
564
595
  newcv = value._replace(fget=fget, _var_data=VarData.from_state(cls))
565
596
  # cleanup refs to mixin cls in var_data
566
597
  setattr(cls, name, newcv)
567
- cls.computed_vars[newcv._var_name] = newcv
568
- cls.vars[newcv._var_name] = newcv
598
+ cls.computed_vars[newcv._js_expr] = newcv
599
+ cls.vars[newcv._js_expr] = newcv
569
600
  continue
570
601
  if types.is_backend_base_variable(name, mixin):
571
602
  cls.backend_vars[name] = copy.deepcopy(value)
@@ -705,7 +736,7 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
705
736
  """Check for shadow methods and raise error if any.
706
737
 
707
738
  Raises:
708
- NameError: When an event handler shadows an inbuilt state method.
739
+ EventHandlerShadowsBuiltInStateMethod: When an event handler shadows an inbuilt state method.
709
740
  """
710
741
  overridden_methods = set()
711
742
  state_base_functions = cls._get_base_functions()
@@ -719,7 +750,7 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
719
750
  overridden_methods.add(method.__name__)
720
751
 
721
752
  for method_name in overridden_methods:
722
- raise NameError(
753
+ raise EventHandlerShadowsBuiltInStateMethod(
723
754
  f"The event handler name `{method_name}` shadows a builtin State method; use a different name instead"
724
755
  )
725
756
 
@@ -728,12 +759,12 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
728
759
  """Check for shadow base vars and raise error if any.
729
760
 
730
761
  Raises:
731
- NameError: When a computed var shadows a base var.
762
+ ComputedVarShadowsBaseVars: When a computed var shadows a base var.
732
763
  """
733
764
  for computed_var_ in cls._get_computed_vars():
734
- if computed_var_._var_name in cls.__annotations__:
735
- raise NameError(
736
- f"The computed var name `{computed_var_._var_name}` shadows a base var in {cls.__module__}.{cls.__name__}; use a different name instead"
765
+ if computed_var_._js_expr in cls.__annotations__:
766
+ raise ComputedVarShadowsBaseVars(
767
+ f"The computed var name `{computed_var_._js_expr}` shadows a base var in {cls.__module__}.{cls.__name__}; use a different name instead"
737
768
  )
738
769
 
739
770
  @classmethod
@@ -741,15 +772,15 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
741
772
  """Check for shadow computed vars and raise error if any.
742
773
 
743
774
  Raises:
744
- NameError: When a computed var shadows another.
775
+ ComputedVarShadowsStateVar: When a computed var shadows another.
745
776
  """
746
777
  for name, cv in cls.__dict__.items():
747
778
  if not is_computed_var(cv):
748
779
  continue
749
- name = cv._var_name
780
+ name = cv._js_expr
750
781
  if name in cls.inherited_vars or name in cls.inherited_backend_vars:
751
- raise NameError(
752
- f"The computed var name `{cv._var_name}` shadows a var in {cls.__module__}.{cls.__name__}; use a different name instead"
782
+ raise ComputedVarShadowsStateVar(
783
+ f"The computed var name `{cv._js_expr}` shadows a var in {cls.__module__}.{cls.__name__}; use a different name instead"
753
784
  )
754
785
 
755
786
  @classmethod
@@ -871,7 +902,7 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
871
902
  return getattr(substate, name)
872
903
 
873
904
  @classmethod
874
- def _init_var(cls, prop: ImmutableVar):
905
+ def _init_var(cls, prop: Var):
875
906
  """Initialize a variable.
876
907
 
877
908
  Args:
@@ -887,7 +918,7 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
887
918
  "State vars must be primitive Python types, "
888
919
  "Plotly figures, Pandas dataframes, "
889
920
  "or subclasses of rx.Base. "
890
- f'Found var "{prop._var_name}" with type {prop._var_type}.'
921
+ f'Found var "{prop._js_expr}" with type {prop._var_type}.'
891
922
  )
892
923
  cls._set_var(prop)
893
924
  cls._create_setter(prop)
@@ -914,8 +945,8 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
914
945
  )
915
946
 
916
947
  # create the variable based on name and type
917
- var = ImmutableVar(
918
- _var_name=format.format_state_name(cls.get_full_name()) + "." + name,
948
+ var = Var(
949
+ _js_expr=format.format_state_name(cls.get_full_name()) + "." + name,
919
950
  _var_type=type_,
920
951
  _var_data=VarData.from_state(cls),
921
952
  ).guess_type()
@@ -937,16 +968,14 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
937
968
  cls._init_var_dependency_dicts()
938
969
 
939
970
  @classmethod
940
- def _set_var(cls, prop: ImmutableVar):
971
+ def _set_var(cls, prop: Var):
941
972
  """Set the var as a class member.
942
973
 
943
974
  Args:
944
975
  prop: The var instance to set.
945
976
  """
946
977
  acutal_var_name = (
947
- prop._var_name
948
- if "." not in prop._var_name
949
- else prop._var_name.split(".")[-1]
978
+ prop._js_expr if "." not in prop._js_expr else prop._js_expr.split(".")[-1]
950
979
  )
951
980
  setattr(cls, acutal_var_name, prop)
952
981
 
@@ -968,7 +997,7 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
968
997
  cls.setvar = cls.event_handlers["setvar"] = EventHandlerSetVar(state_cls=cls)
969
998
 
970
999
  @classmethod
971
- def _create_setter(cls, prop: ImmutableVar):
1000
+ def _create_setter(cls, prop: Var):
972
1001
  """Create a setter for the var.
973
1002
 
974
1003
  Args:
@@ -981,17 +1010,17 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
981
1010
  setattr(cls, setter_name, event_handler)
982
1011
 
983
1012
  @classmethod
984
- def _set_default_value(cls, prop: ImmutableVar):
1013
+ def _set_default_value(cls, prop: Var):
985
1014
  """Set the default value for the var.
986
1015
 
987
1016
  Args:
988
1017
  prop: The var to set the default value for.
989
1018
  """
990
1019
  # Get the pydantic field for the var.
991
- if "." in prop._var_name:
992
- field = cls.get_fields()[prop._var_name.split(".")[-1]]
1020
+ if "." in prop._js_expr:
1021
+ field = cls.get_fields()[prop._js_expr.split(".")[-1]]
993
1022
  else:
994
- field = cls.get_fields()[prop._var_name]
1023
+ field = cls.get_fields()[prop._js_expr]
995
1024
  if field.required:
996
1025
  default_value = prop.get_default_value()
997
1026
  if default_value is not None:
@@ -1018,6 +1047,27 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
1018
1047
  if not func[0].startswith("__")
1019
1048
  }
1020
1049
 
1050
+ @classmethod
1051
+ def _update_substate_inherited_vars(cls, vars_to_add: dict[str, Var]):
1052
+ """Update the inherited vars of substates recursively when new vars are added.
1053
+
1054
+ Also updates the var dependency tracking dicts after adding vars.
1055
+
1056
+ Args:
1057
+ vars_to_add: names to Var instances to add to substates
1058
+ """
1059
+ for substate_class in cls.class_subclasses:
1060
+ for name, var in vars_to_add.items():
1061
+ if types.is_backend_base_variable(name, cls):
1062
+ substate_class.backend_vars.setdefault(name, var)
1063
+ substate_class.inherited_backend_vars.setdefault(name, var)
1064
+ else:
1065
+ substate_class.vars.setdefault(name, var)
1066
+ substate_class.inherited_vars.setdefault(name, var)
1067
+ substate_class._update_substate_inherited_vars(vars_to_add)
1068
+ # Reinitialize dependency tracking dicts.
1069
+ cls._init_var_dependency_dicts()
1070
+
1021
1071
  @classmethod
1022
1072
  def setup_dynamic_args(cls, args: dict[str, str]):
1023
1073
  """Set up args for easy access in renderer.
@@ -1034,14 +1084,15 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
1034
1084
  def inner_func(self) -> str:
1035
1085
  return self.router.page.params.get(param, "")
1036
1086
 
1037
- return DynamicRouteVar(fget=inner_func, cache=True)
1087
+ return inner_func
1038
1088
 
1039
1089
  def arglist_factory(param):
1040
1090
  def inner_func(self) -> List[str]:
1041
1091
  return self.router.page.params.get(param, [])
1042
1092
 
1043
- return DynamicRouteVar(fget=inner_func, cache=True)
1093
+ return inner_func
1044
1094
 
1095
+ dynamic_vars = {}
1045
1096
  for param, value in args.items():
1046
1097
  if value == constants.RouteArgType.SINGLE:
1047
1098
  func = argsingle_factory(param)
@@ -1049,16 +1100,18 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
1049
1100
  func = arglist_factory(param)
1050
1101
  else:
1051
1102
  continue
1052
- # to allow passing as a prop, evade python frozen rules (bad practice)
1053
- object.__setattr__(func, "_var_name", param)
1054
- # cls.vars[param] = cls.computed_vars[param] = func._var_set_state(cls) # type: ignore
1055
- cls.vars[param] = cls.computed_vars[param] = func._replace(
1056
- _var_data=VarData.from_state(cls)
1103
+ dynamic_vars[param] = DynamicRouteVar(
1104
+ fget=func,
1105
+ cache=True,
1106
+ _js_expr=param,
1107
+ _var_data=VarData.from_state(cls),
1057
1108
  )
1058
- setattr(cls, param, func)
1109
+ setattr(cls, param, dynamic_vars[param])
1059
1110
 
1060
- # Reinitialize dependency tracking dicts.
1061
- cls._init_var_dependency_dicts()
1111
+ # Update tracking dicts.
1112
+ cls.computed_vars.update(dynamic_vars)
1113
+ cls.vars.update(dynamic_vars)
1114
+ cls._update_substate_inherited_vars(dynamic_vars)
1062
1115
 
1063
1116
  @classmethod
1064
1117
  def _check_overwritten_dynamic_args(cls, args: list[str]):
@@ -1826,8 +1879,13 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
1826
1879
  self.dirty_vars.update(self._always_dirty_computed_vars)
1827
1880
  self._mark_dirty()
1828
1881
 
1882
+ def dictify(value: Any):
1883
+ if dataclasses.is_dataclass(value) and not isinstance(value, type):
1884
+ return dataclasses.asdict(value)
1885
+ return value
1886
+
1829
1887
  base_vars = {
1830
- prop_name: self.get_value(getattr(self, prop_name))
1888
+ prop_name: dictify(self.get_value(getattr(self, prop_name)))
1831
1889
  for prop_name in self.base_vars
1832
1890
  }
1833
1891
  if initial and include_computed:
@@ -1907,9 +1965,6 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
1907
1965
  return state
1908
1966
 
1909
1967
 
1910
- EventHandlerSetVar.update_forward_refs()
1911
-
1912
-
1913
1968
  class State(BaseState):
1914
1969
  """The app Base State."""
1915
1970
 
@@ -2341,18 +2396,29 @@ class StateProxy(wrapt.ObjectProxy):
2341
2396
  self._self_mutable = original_mutable
2342
2397
 
2343
2398
 
2344
- class StateUpdate(Base):
2399
+ @dataclasses.dataclass(
2400
+ frozen=True,
2401
+ )
2402
+ class StateUpdate:
2345
2403
  """A state update sent to the frontend."""
2346
2404
 
2347
2405
  # The state delta.
2348
- delta: Delta = {}
2406
+ delta: Delta = dataclasses.field(default_factory=dict)
2349
2407
 
2350
2408
  # Events to be added to the event queue.
2351
- events: List[Event] = []
2409
+ events: List[Event] = dataclasses.field(default_factory=list)
2352
2410
 
2353
2411
  # Whether this is the final state update for the event.
2354
2412
  final: bool = True
2355
2413
 
2414
+ def json(self) -> str:
2415
+ """Convert the state update to a JSON string.
2416
+
2417
+ Returns:
2418
+ The state update as a JSON string.
2419
+ """
2420
+ return format.json_dumps(dataclasses.asdict(self))
2421
+
2356
2422
 
2357
2423
  class StateManager(Base, ABC):
2358
2424
  """A class to manage many client states."""
reflex/style.py CHANGED
@@ -7,12 +7,12 @@ from typing import Any, Literal, Tuple, Type
7
7
  from reflex import constants
8
8
  from reflex.components.core.breakpoints import Breakpoints, breakpoints_values
9
9
  from reflex.event import EventChain, EventHandler
10
- from reflex.ivars.base import ImmutableCallableVar, ImmutableVar, LiteralVar
11
- from reflex.ivars.function import FunctionVar
12
10
  from reflex.utils import format
13
11
  from reflex.utils.exceptions import ReflexError
14
12
  from reflex.utils.imports import ImportVar
15
- from reflex.vars import Var, VarData
13
+ from reflex.vars import VarData
14
+ from reflex.vars.base import CallableVar, LiteralVar, Var
15
+ from reflex.vars.function import FunctionVar
16
16
 
17
17
  SYSTEM_COLOR_MODE: str = "system"
18
18
  LIGHT_COLOR_MODE: str = "light"
@@ -26,30 +26,30 @@ color_mode_imports = {
26
26
  }
27
27
 
28
28
 
29
- def _color_mode_var(_var_name: str, _var_type: Type = str) -> ImmutableVar:
30
- """Create a Var that destructs the _var_name from ColorModeContext.
29
+ def _color_mode_var(_js_expr: str, _var_type: Type = str) -> Var:
30
+ """Create a Var that destructs the _js_expr from ColorModeContext.
31
31
 
32
32
  Args:
33
- _var_name: The name of the variable to get from ColorModeContext.
33
+ _js_expr: The name of the variable to get from ColorModeContext.
34
34
  _var_type: The type of the Var.
35
35
 
36
36
  Returns:
37
37
  The Var that resolves to the color mode.
38
38
  """
39
- return ImmutableVar(
40
- _var_name=_var_name,
39
+ return Var(
40
+ _js_expr=_js_expr,
41
41
  _var_type=_var_type,
42
42
  _var_data=VarData(
43
43
  imports=color_mode_imports,
44
- hooks={f"const {{ {_var_name} }} = useContext(ColorModeContext)": None},
44
+ hooks={f"const {{ {_js_expr} }} = useContext(ColorModeContext)": None},
45
45
  ),
46
46
  ).guess_type()
47
47
 
48
48
 
49
- @ImmutableCallableVar
49
+ @CallableVar
50
50
  def set_color_mode(
51
51
  new_color_mode: LiteralColorMode | Var[LiteralColorMode] | None = None,
52
- ) -> ImmutableVar[EventChain]:
52
+ ) -> Var[EventChain]:
53
53
  """Create an EventChain Var that sets the color mode to a specific value.
54
54
 
55
55
  Note: `set_color_mode` is not a real event and cannot be triggered from a
@@ -62,16 +62,16 @@ def set_color_mode(
62
62
  The EventChain Var that can be passed to an event trigger.
63
63
  """
64
64
  base_setter = _color_mode_var(
65
- _var_name=constants.ColorMode.SET,
65
+ _js_expr=constants.ColorMode.SET,
66
66
  _var_type=EventChain,
67
67
  )
68
68
  if new_color_mode is None:
69
69
  return base_setter
70
70
 
71
- if not isinstance(new_color_mode, ImmutableVar):
71
+ if not isinstance(new_color_mode, Var):
72
72
  new_color_mode = LiteralVar.create(new_color_mode)
73
73
 
74
- return ImmutableVar(
74
+ return Var(
75
75
  f"() => {str(base_setter)}({str(new_color_mode)})",
76
76
  _var_data=VarData.merge(
77
77
  base_setter._get_all_var_data(), new_color_mode._get_all_var_data()
@@ -80,12 +80,12 @@ def set_color_mode(
80
80
 
81
81
 
82
82
  # Var resolves to the current color mode for the app ("light", "dark" or "system")
83
- color_mode = _color_mode_var(_var_name=constants.ColorMode.NAME)
83
+ color_mode = _color_mode_var(_js_expr=constants.ColorMode.NAME)
84
84
  # Var resolves to the resolved color mode for the app ("light" or "dark")
85
- resolved_color_mode = _color_mode_var(_var_name=constants.ColorMode.RESOLVED_NAME)
85
+ resolved_color_mode = _color_mode_var(_js_expr=constants.ColorMode.RESOLVED_NAME)
86
86
  # Var resolves to a function invocation that toggles the color mode
87
87
  toggle_color_mode = _color_mode_var(
88
- _var_name=constants.ColorMode.TOGGLE,
88
+ _js_expr=constants.ColorMode.TOGGLE,
89
89
  _var_type=EventChain,
90
90
  )
91
91
 
@@ -115,7 +115,7 @@ def media_query(breakpoint_expr: str):
115
115
 
116
116
  def convert_item(
117
117
  style_item: int | str | Var,
118
- ) -> tuple[str | Var, VarData | VarData | None]:
118
+ ) -> tuple[str | Var, VarData | None]:
119
119
  """Format a single value in a style dictionary.
120
120
 
121
121
  Args:
@@ -133,7 +133,7 @@ def convert_item(
133
133
  "Please use a Var or a literal value."
134
134
  )
135
135
 
136
- if isinstance(style_item, ImmutableVar):
136
+ if isinstance(style_item, Var):
137
137
  return style_item, style_item._get_all_var_data()
138
138
 
139
139
  # if isinstance(style_item, str) and REFLEX_VAR_OPENING_TAG not in style_item:
@@ -146,7 +146,7 @@ def convert_item(
146
146
 
147
147
 
148
148
  def convert_list(
149
- responsive_list: list[str | dict | ImmutableVar],
149
+ responsive_list: list[str | dict | Var],
150
150
  ) -> tuple[list[str | dict[str, Var | list | dict]], VarData | None]:
151
151
  """Format a responsive value list.
152
152
 
@@ -189,7 +189,7 @@ def convert(
189
189
 
190
190
  for key, value in style_dict.items():
191
191
  keys = format_style_key(key)
192
- if isinstance(value, ImmutableVar):
192
+ if isinstance(value, Var):
193
193
  return_val = value
194
194
  new_var_data = value._get_all_var_data()
195
195
  update_out_dict(return_val, keys)
@@ -290,7 +290,6 @@ def _format_emotion_style_pseudo_selector(key: str) -> str:
290
290
  """
291
291
  prefix = None
292
292
  if key.startswith("_"):
293
- # Handle pseudo selectors in chakra style format.
294
293
  prefix = "&:"
295
294
  key = key[1:]
296
295
  if key.startswith(":"):
@@ -91,3 +91,19 @@ class EventFnArgMismatch(ReflexError, TypeError):
91
91
 
92
92
  class DynamicRouteArgShadowsStateVar(ReflexError, NameError):
93
93
  """Raised when a dynamic route arg shadows a state var."""
94
+
95
+
96
+ class ComputedVarShadowsStateVar(ReflexError, NameError):
97
+ """Raised when a computed var shadows a state var."""
98
+
99
+
100
+ class ComputedVarShadowsBaseVars(ReflexError, NameError):
101
+ """Raised when a computed var shadows a base var."""
102
+
103
+
104
+ class EventHandlerShadowsBuiltInStateMethod(ReflexError, NameError):
105
+ """Raised when an event handler shadows a built-in state method."""
106
+
107
+
108
+ class GeneratedCodeHasNoFunctionDefs(ReflexError):
109
+ """Raised when refactored code generated with flexgen has no functions defined."""