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
@@ -9,6 +9,9 @@ import dis
9
9
  import functools
10
10
  import inspect
11
11
  import json
12
+ import random
13
+ import re
14
+ import string
12
15
  import sys
13
16
  from types import CodeType, FunctionType
14
17
  from typing import (
@@ -17,6 +20,7 @@ from typing import (
17
20
  Callable,
18
21
  Dict,
19
22
  Generic,
23
+ Iterable,
20
24
  List,
21
25
  Literal,
22
26
  NoReturn,
@@ -43,15 +47,14 @@ from reflex.utils.exceptions import (
43
47
  VarValueError,
44
48
  )
45
49
  from reflex.utils.format import format_state_name
46
- from reflex.utils.types import GenericType, Self, get_origin
47
- from reflex.vars import (
48
- REPLACED_NAMES,
49
- Var,
50
- VarData,
51
- _decode_var_immutable,
52
- _extract_var_data,
53
- _global_vars,
50
+ from reflex.utils.imports import (
51
+ ImmutableParsedImportDict,
52
+ ImportDict,
53
+ ImportVar,
54
+ ParsedImportDict,
55
+ parse_imports,
54
56
  )
57
+ from reflex.utils.types import GenericType, Self, get_origin
55
58
 
56
59
  if TYPE_CHECKING:
57
60
  from reflex.state import BaseState
@@ -67,19 +70,18 @@ if TYPE_CHECKING:
67
70
  from .sequence import ArrayVar, StringVar, ToArrayOperation, ToStringOperation
68
71
 
69
72
 
70
- VAR_TYPE = TypeVar("VAR_TYPE")
73
+ VAR_TYPE = TypeVar("VAR_TYPE", covariant=True)
71
74
 
72
75
 
73
76
  @dataclasses.dataclass(
74
77
  eq=False,
75
78
  frozen=True,
76
- **{"slots": True} if sys.version_info >= (3, 10) else {},
77
79
  )
78
- class ImmutableVar(Var, Generic[VAR_TYPE]):
80
+ class Var(Generic[VAR_TYPE]):
79
81
  """Base class for immutable vars."""
80
82
 
81
83
  # The name of the var.
82
- _var_name: str = dataclasses.field()
84
+ _js_expr: str = dataclasses.field()
83
85
 
84
86
  # The type of the var.
85
87
  _var_type: types.GenericType = dataclasses.field(default=Any)
@@ -93,7 +95,7 @@ class ImmutableVar(Var, Generic[VAR_TYPE]):
93
95
  Returns:
94
96
  The name of the var.
95
97
  """
96
- return self._var_name
98
+ return self._js_expr
97
99
 
98
100
  @property
99
101
  def _var_is_local(self) -> bool:
@@ -104,6 +106,16 @@ class ImmutableVar(Var, Generic[VAR_TYPE]):
104
106
  """
105
107
  return False
106
108
 
109
+ @property
110
+ @deprecated("Use `_js_expr` instead.")
111
+ def _var_name(self) -> str:
112
+ """The name of the var.
113
+
114
+ Returns:
115
+ The name of the var.
116
+ """
117
+ return self._js_expr
118
+
107
119
  @property
108
120
  def _var_is_string(self) -> bool:
109
121
  """Whether the var is a string literal.
@@ -116,11 +128,11 @@ class ImmutableVar(Var, Generic[VAR_TYPE]):
116
128
  def __post_init__(self):
117
129
  """Post-initialize the var."""
118
130
  # Decode any inline Var markup and apply it to the instance
119
- _var_data, _var_name = _decode_var_immutable(self._var_name)
131
+ _var_data, _js_expr = _decode_var_immutable(self._js_expr)
120
132
 
121
- if _var_data or _var_name != self._var_name:
133
+ if _var_data or _js_expr != self._js_expr:
122
134
  self.__init__(
123
- _var_name=_var_name,
135
+ _js_expr=_js_expr,
124
136
  _var_type=self._var_type,
125
137
  _var_data=VarData.merge(self._var_data, _var_data),
126
138
  )
@@ -131,7 +143,7 @@ class ImmutableVar(Var, Generic[VAR_TYPE]):
131
143
  Returns:
132
144
  The hash of the var.
133
145
  """
134
- return hash((self._var_name, self._var_type, self._var_data))
146
+ return hash((self._js_expr, self._var_type, self._var_data))
135
147
 
136
148
  def _get_all_var_data(self) -> VarData | None:
137
149
  """Get all VarData associated with the Var.
@@ -141,7 +153,7 @@ class ImmutableVar(Var, Generic[VAR_TYPE]):
141
153
  """
142
154
  return self._var_data
143
155
 
144
- def equals(self, other: ImmutableVar) -> bool:
156
+ def equals(self, other: Var) -> bool:
145
157
  """Check if two vars are equal.
146
158
 
147
159
  Args:
@@ -151,7 +163,7 @@ class ImmutableVar(Var, Generic[VAR_TYPE]):
151
163
  Whether the vars are equal.
152
164
  """
153
165
  return (
154
- self._var_name == other._var_name
166
+ self._js_expr == other._js_expr
155
167
  and self._var_type == other._var_type
156
168
  and self._get_all_var_data() == other._get_all_var_data()
157
169
  )
@@ -164,24 +176,20 @@ class ImmutableVar(Var, Generic[VAR_TYPE]):
164
176
  **kwargs: Var fields to update.
165
177
 
166
178
  Returns:
167
- A new ImmutableVar with the updated fields overwriting the corresponding fields in this Var.
179
+ A new Var with the updated fields overwriting the corresponding fields in this Var.
168
180
 
169
181
  Raises:
170
182
  TypeError: If _var_is_local, _var_is_string, or _var_full_name_needs_state_prefix is not None.
171
183
  """
172
184
  if kwargs.get("_var_is_local", False) is not False:
173
- raise TypeError(
174
- "The _var_is_local argument is not supported for ImmutableVar."
175
- )
185
+ raise TypeError("The _var_is_local argument is not supported for Var.")
176
186
 
177
187
  if kwargs.get("_var_is_string", False) is not False:
178
- raise TypeError(
179
- "The _var_is_string argument is not supported for ImmutableVar."
180
- )
188
+ raise TypeError("The _var_is_string argument is not supported for Var.")
181
189
 
182
190
  if kwargs.get("_var_full_name_needs_state_prefix", False) is not False:
183
191
  raise TypeError(
184
- "The _var_full_name_needs_state_prefix argument is not supported for ImmutableVar."
192
+ "The _var_full_name_needs_state_prefix argument is not supported for Var."
185
193
  )
186
194
 
187
195
  return dataclasses.replace(
@@ -199,7 +207,7 @@ class ImmutableVar(Var, Generic[VAR_TYPE]):
199
207
  _var_is_local: bool | None = None,
200
208
  _var_is_string: bool | None = None,
201
209
  _var_data: VarData | None = None,
202
- ) -> ImmutableVar | None:
210
+ ) -> Var:
203
211
  """Create a var from a value.
204
212
 
205
213
  Args:
@@ -210,80 +218,57 @@ class ImmutableVar(Var, Generic[VAR_TYPE]):
210
218
 
211
219
  Returns:
212
220
  The var.
213
-
214
- Raises:
215
- VarTypeError: If the value is JSON-unserializable.
216
- TypeError: If _var_is_local or _var_is_string is not None.
217
221
  """
218
222
  if _var_is_local is not None:
219
- raise TypeError(
220
- "The _var_is_local argument is not supported for ImmutableVar."
223
+ console.deprecate(
224
+ feature_name="_var_is_local",
225
+ reason="The _var_is_local argument is not supported for Var."
226
+ "If you want to create a Var from a raw Javascript expression, use the constructor directly",
227
+ deprecation_version="0.6.0",
228
+ removal_version="0.7.0",
221
229
  )
222
-
223
230
  if _var_is_string is not None:
224
- raise TypeError(
225
- "The _var_is_string argument is not supported for ImmutableVar."
231
+ console.deprecate(
232
+ feature_name="_var_is_string",
233
+ reason="The _var_is_string argument is not supported for Var."
234
+ "If you want to create a Var from a raw Javascript expression, use the constructor directly",
235
+ deprecation_version="0.6.0",
236
+ removal_version="0.7.0",
226
237
  )
227
238
 
228
- from reflex.utils import format
229
-
230
- # Check for none values.
231
- if value is None:
232
- return None
233
-
234
239
  # If the value is already a var, do nothing.
235
- if isinstance(value, ImmutableVar):
240
+ if isinstance(value, Var):
236
241
  return value
237
242
 
238
243
  # Try to pull the imports and hooks from contained values.
239
244
  if not isinstance(value, str):
240
- _var_data = VarData.merge(*_extract_var_data(value), _var_data)
245
+ return LiteralVar.create(value)
241
246
 
242
- # Try to serialize the value.
243
- type_ = type(value)
244
- if type_ in types.JSONType:
245
- name = value
246
- else:
247
- name, _serialized_type = serializers.serialize(value, get_type=True)
248
- if name is None:
249
- raise VarTypeError(
250
- f"No JSON serializer found for var {value} of type {type_}."
247
+ if _var_is_string is False or _var_is_local is True:
248
+ return cls(
249
+ _js_expr=value,
250
+ _var_data=_var_data,
251
251
  )
252
- name = name if isinstance(name, str) else format.json_dumps(name)
253
252
 
254
- return cls(
255
- _var_name=name,
256
- _var_type=type_,
257
- _var_data=_var_data,
258
- )
253
+ return LiteralVar.create(value, _var_data=_var_data)
259
254
 
260
255
  @classmethod
256
+ @deprecated("Use `.create()` instead.")
261
257
  def create_safe(
262
258
  cls,
263
- value: Any,
264
- _var_is_local: bool | None = None,
265
- _var_is_string: bool | None = None,
266
- _var_data: VarData | None = None,
267
- ) -> ImmutableVar:
268
- """Create a var from a value, asserting that it is not None.
259
+ *args: Any,
260
+ **kwargs: Any,
261
+ ) -> Var:
262
+ """Create a var from a value.
269
263
 
270
264
  Args:
271
- value: The value to create the var from.
272
- _var_is_local: Whether the var is local. Deprecated.
273
- _var_is_string: Whether the var is a string literal. Deprecated.
274
- _var_data: Additional hooks and imports associated with the Var.
265
+ *args: The arguments to create the var from.
266
+ **kwargs: The keyword arguments to create the var from.
275
267
 
276
268
  Returns:
277
269
  The var.
278
270
  """
279
- var = cls.create(
280
- value,
281
- _var_is_local=_var_is_local,
282
- _var_is_string=_var_is_string,
283
- _var_data=_var_data,
284
- )
285
- assert var is not None
286
- return var
271
+ return cls.create(*args, **kwargs)
287
272
 
288
273
  def __format__(self, format_spec: str) -> str:
289
274
  """Format the var into a Javascript equivalent to an f-string.
@@ -299,7 +284,7 @@ class ImmutableVar(Var, Generic[VAR_TYPE]):
299
284
  _global_vars[hashed_var] = self
300
285
 
301
286
  # Encode the _var_data into the formatted output for tracking purposes.
302
- return f"{constants.REFLEX_VAR_OPENING_TAG}{hashed_var}{constants.REFLEX_VAR_CLOSING_TAG}{self._var_name}"
287
+ return f"{constants.REFLEX_VAR_OPENING_TAG}{hashed_var}{constants.REFLEX_VAR_CLOSING_TAG}{self._js_expr}"
303
288
 
304
289
  @overload
305
290
  def to(self, output: Type[StringVar]) -> ToStringOperation: ...
@@ -343,7 +328,7 @@ class ImmutableVar(Var, Generic[VAR_TYPE]):
343
328
  self,
344
329
  output: Type[OUTPUT] | types.GenericType,
345
330
  var_type: types.GenericType | None = None,
346
- ) -> ImmutableVar:
331
+ ) -> Var:
347
332
  """Convert the var to a different type.
348
333
 
349
334
  Args:
@@ -387,6 +372,12 @@ class ImmutableVar(Var, Generic[VAR_TYPE]):
387
372
  return self.to(BooleanVar, output)
388
373
  if fixed_output_type is None:
389
374
  return ToNoneOperation.create(self)
375
+ if issubclass(fixed_output_type, Base):
376
+ return self.to(ObjectVar, output)
377
+ if dataclasses.is_dataclass(fixed_output_type) and not issubclass(
378
+ fixed_output_type, Var
379
+ ):
380
+ return self.to(ObjectVar, output)
390
381
 
391
382
  if issubclass(output, BooleanVar):
392
383
  return ToBooleanVarOperation.create(self)
@@ -421,6 +412,9 @@ class ImmutableVar(Var, Generic[VAR_TYPE]):
421
412
  if issubclass(output, (ObjectVar, Base)):
422
413
  return ToObjectOperation.create(self, var_type or dict)
423
414
 
415
+ if dataclasses.is_dataclass(output):
416
+ return ToObjectOperation.create(self, var_type or dict)
417
+
424
418
  if issubclass(output, FunctionVar):
425
419
  # if fixed_type is not None and not issubclass(fixed_type, Callable):
426
420
  # raise TypeError(
@@ -447,11 +441,11 @@ class ImmutableVar(Var, Generic[VAR_TYPE]):
447
441
 
448
442
  return self
449
443
 
450
- def guess_type(self) -> ImmutableVar:
444
+ def guess_type(self) -> Var:
451
445
  """Guesses the type of the variable based on its `_var_type` attribute.
452
446
 
453
447
  Returns:
454
- ImmutableVar: The guessed type of the variable.
448
+ Var: The guessed type of the variable.
455
449
 
456
450
  Raises:
457
451
  TypeError: If the type is not supported for guessing.
@@ -479,7 +473,11 @@ class ImmutableVar(Var, Generic[VAR_TYPE]):
479
473
  ):
480
474
  return self.to(NumberVar, self._var_type)
481
475
 
482
- if all(inspect.isclass(t) and issubclass(t, Base) for t in inner_types):
476
+ if all(
477
+ inspect.isclass(t)
478
+ and (issubclass(t, Base) or dataclasses.is_dataclass(t))
479
+ for t in inner_types
480
+ ):
483
481
  return self.to(ObjectVar, self._var_type)
484
482
 
485
483
  return self
@@ -499,6 +497,8 @@ class ImmutableVar(Var, Generic[VAR_TYPE]):
499
497
  return self.to(StringVar, self._var_type)
500
498
  if issubclass(fixed_type, Base):
501
499
  return self.to(ObjectVar, self._var_type)
500
+ if dataclasses.is_dataclass(fixed_type):
501
+ return self.to(ObjectVar, self._var_type)
502
502
  return self
503
503
 
504
504
  def get_default_value(self) -> Any:
@@ -553,7 +553,7 @@ class ImmutableVar(Var, Generic[VAR_TYPE]):
553
553
  Returns:
554
554
  The name of the setter function.
555
555
  """
556
- var_name_parts = self._var_name.split(".")
556
+ var_name_parts = self._js_expr.split(".")
557
557
  setter = constants.SETTER_PREFIX + var_name_parts[-1]
558
558
  var_data = self._get_all_var_data()
559
559
  if var_data is None:
@@ -568,7 +568,7 @@ class ImmutableVar(Var, Generic[VAR_TYPE]):
568
568
  Returns:
569
569
  A function that that creates a setter for the var.
570
570
  """
571
- actual_name = self._var_name.split(".")[-1]
571
+ actual_name = self._js_expr.split(".")[-1]
572
572
 
573
573
  def setter(state: BaseState, value: Any):
574
574
  """Get the setter for the var.
@@ -583,7 +583,7 @@ class ImmutableVar(Var, Generic[VAR_TYPE]):
583
583
  setattr(state, actual_name, value)
584
584
  except ValueError:
585
585
  console.debug(
586
- f"{type(state).__name__}.{self._var_name}: Failed conversion of {value} to '{self._var_type.__name__}'. Value not set.",
586
+ f"{type(state).__name__}.{self._js_expr}: Failed conversion of {value} to '{self._var_type.__name__}'. Value not set.",
587
587
  )
588
588
  else:
589
589
  setattr(state, actual_name, value)
@@ -613,11 +613,11 @@ class ImmutableVar(Var, Generic[VAR_TYPE]):
613
613
  _var_data=VarData.merge(VarData.from_state(state), self._var_data),
614
614
  ).guess_type()
615
615
 
616
- def __eq__(self, other: ImmutableVar | Any) -> BooleanVar:
616
+ def __eq__(self, other: Var | Any) -> BooleanVar:
617
617
  """Check if the current variable is equal to the given variable.
618
618
 
619
619
  Args:
620
- other (ImmutableVar | Any): The variable to compare with.
620
+ other (Var | Any): The variable to compare with.
621
621
 
622
622
  Returns:
623
623
  BooleanVar: A BooleanVar object representing the result of the equality check.
@@ -626,11 +626,11 @@ class ImmutableVar(Var, Generic[VAR_TYPE]):
626
626
 
627
627
  return equal_operation(self, other)
628
628
 
629
- def __ne__(self, other: ImmutableVar | Any) -> BooleanVar:
629
+ def __ne__(self, other: Var | Any) -> BooleanVar:
630
630
  """Check if the current object is not equal to the given object.
631
631
 
632
632
  Parameters:
633
- other (ImmutableVar | Any): The object to compare with.
633
+ other (Var | Any): The object to compare with.
634
634
 
635
635
  Returns:
636
636
  BooleanVar: A BooleanVar object representing the result of the comparison.
@@ -649,7 +649,7 @@ class ImmutableVar(Var, Generic[VAR_TYPE]):
649
649
 
650
650
  return boolify(self)
651
651
 
652
- def __and__(self, other: ImmutableVar | Any) -> ImmutableVar:
652
+ def __and__(self, other: Var | Any) -> Var:
653
653
  """Perform a logical AND operation on the current instance and another variable.
654
654
 
655
655
  Args:
@@ -660,7 +660,7 @@ class ImmutableVar(Var, Generic[VAR_TYPE]):
660
660
  """
661
661
  return and_operation(self, other)
662
662
 
663
- def __rand__(self, other: ImmutableVar | Any) -> ImmutableVar:
663
+ def __rand__(self, other: Var | Any) -> Var:
664
664
  """Perform a logical AND operation on the current instance and another variable.
665
665
 
666
666
  Args:
@@ -671,7 +671,7 @@ class ImmutableVar(Var, Generic[VAR_TYPE]):
671
671
  """
672
672
  return and_operation(other, self)
673
673
 
674
- def __or__(self, other: ImmutableVar | Any) -> ImmutableVar:
674
+ def __or__(self, other: Var | Any) -> Var:
675
675
  """Perform a logical OR operation on the current instance and another variable.
676
676
 
677
677
  Args:
@@ -682,7 +682,7 @@ class ImmutableVar(Var, Generic[VAR_TYPE]):
682
682
  """
683
683
  return or_operation(self, other)
684
684
 
685
- def __ror__(self, other: ImmutableVar | Any) -> ImmutableVar:
685
+ def __ror__(self, other: Var | Any) -> Var:
686
686
  """Perform a logical OR operation on the current instance and another variable.
687
687
 
688
688
  Args:
@@ -712,7 +712,7 @@ class ImmutableVar(Var, Generic[VAR_TYPE]):
712
712
 
713
713
  return JSON_STRINGIFY.call(self).to(StringVar)
714
714
 
715
- def as_ref(self) -> ImmutableVar:
715
+ def as_ref(self) -> Var:
716
716
  """Get a reference to the var.
717
717
 
718
718
  Returns:
@@ -720,14 +720,14 @@ class ImmutableVar(Var, Generic[VAR_TYPE]):
720
720
  """
721
721
  from .object import ObjectVar
722
722
 
723
- refs = ImmutableVar(
724
- _var_name="refs",
723
+ refs = Var(
724
+ _js_expr="refs",
725
725
  _var_data=VarData(
726
726
  imports={
727
727
  f"/{constants.Dirs.STATE_PATH}": [imports.ImportVar(tag="refs")]
728
728
  }
729
729
  ),
730
- ).to(ObjectVar)
730
+ ).to(ObjectVar, Dict[str, str])
731
731
  return refs[LiteralVar.create(str(self))]
732
732
 
733
733
  @deprecated("Use `.js_type()` instead.")
@@ -813,7 +813,8 @@ class ImmutableVar(Var, Generic[VAR_TYPE]):
813
813
  TypeError: If the var type is Any.
814
814
  """
815
815
  if name.startswith("_"):
816
- return super(ImmutableVar, self).__getattribute__(name)
816
+ return self.__getattribute__(name)
817
+
817
818
  if self._var_type is Any:
818
819
  raise TypeError(
819
820
  f"You must provide an annotation for the state var `{str(self)}`. Annotation cannot be `{self._var_type}`."
@@ -857,26 +858,85 @@ class ImmutableVar(Var, Generic[VAR_TYPE]):
857
858
  var_data = self._get_all_var_data()
858
859
  return var_data.state if var_data else ""
859
860
 
861
+ @overload
862
+ @classmethod
863
+ def range(cls, stop: int | NumberVar, /) -> ArrayVar[List[int]]: ...
864
+
865
+ @overload
866
+ @classmethod
867
+ def range(
868
+ cls,
869
+ start: int | NumberVar,
870
+ end: int | NumberVar,
871
+ step: int | NumberVar = 1,
872
+ /,
873
+ ) -> ArrayVar[List[int]]: ...
860
874
 
861
- OUTPUT = TypeVar("OUTPUT", bound=ImmutableVar)
875
+ @classmethod
876
+ def range(
877
+ cls,
878
+ first_endpoint: int | NumberVar,
879
+ second_endpoint: int | NumberVar | None = None,
880
+ step: int | NumberVar | None = None,
881
+ ) -> ArrayVar[List[int]]:
882
+ """Create a range of numbers.
862
883
 
884
+ Args:
885
+ first_endpoint: The end of the range if second_endpoint is not provided, otherwise the start of the range.
886
+ second_endpoint: The end of the range.
887
+ step: The step of the range.
863
888
 
864
- def _encode_var(value: ImmutableVar) -> str:
865
- """Encode the state name into a formatted var.
889
+ Returns:
890
+ The range of numbers.
891
+ """
892
+ from .sequence import ArrayVar
866
893
 
867
- Args:
868
- value: The value to encode the state name into.
894
+ return ArrayVar.range(first_endpoint, second_endpoint, step)
869
895
 
870
- Returns:
871
- The encoded var.
872
- """
873
- return f"{value}"
896
+ def __bool__(self) -> bool:
897
+ """Raise exception if using Var in a boolean context.
898
+
899
+ Raises:
900
+ VarTypeError: when attempting to bool-ify the Var.
901
+ """
902
+ raise VarTypeError(
903
+ f"Cannot convert Var {str(self)!r} to bool for use with `if`, `and`, `or`, and `not`. "
904
+ "Instead use `rx.cond` and bitwise operators `&` (and), `|` (or), `~` (invert)."
905
+ )
906
+
907
+ def __iter__(self) -> Any:
908
+ """Raise exception if using Var in an iterable context.
909
+
910
+ Raises:
911
+ VarTypeError: when attempting to iterate over the Var.
912
+ """
913
+ raise VarTypeError(
914
+ f"Cannot iterate over Var {str(self)!r}. Instead use `rx.foreach`."
915
+ )
916
+
917
+ def __contains__(self, _: Any) -> Var:
918
+ """Override the 'in' operator to alert the user that it is not supported.
919
+
920
+ Raises:
921
+ VarTypeError: the operation is not supported
922
+ """
923
+ raise VarTypeError(
924
+ "'in' operator not supported for Var types, use Var.contains() instead."
925
+ )
926
+
927
+ def json(self) -> str:
928
+ """Serialize the var to a JSON string.
929
+
930
+ Raises:
931
+ NotImplementedError: If the method is not implemented.
932
+ """
933
+ raise NotImplementedError("Var subclasses must implement the json method.")
874
934
 
875
935
 
876
- serializers.serializer(_encode_var)
936
+ OUTPUT = TypeVar("OUTPUT", bound=Var)
877
937
 
878
938
 
879
- class LiteralVar(ImmutableVar):
939
+ class LiteralVar(Var):
880
940
  """Base class for immutable literal vars."""
881
941
 
882
942
  @classmethod
@@ -884,7 +944,7 @@ class LiteralVar(ImmutableVar):
884
944
  cls,
885
945
  value: Any,
886
946
  _var_data: VarData | None = None,
887
- ) -> ImmutableVar:
947
+ ) -> Var:
888
948
  """Create a var from a value.
889
949
 
890
950
  Args:
@@ -901,7 +961,7 @@ class LiteralVar(ImmutableVar):
901
961
  from .object import LiteralObjectVar
902
962
  from .sequence import LiteralArrayVar, LiteralStringVar
903
963
 
904
- if isinstance(value, ImmutableVar):
964
+ if isinstance(value, Var):
905
965
  if _var_data is None:
906
966
  return value
907
967
  return value._replace(merge_var_data=_var_data)
@@ -924,7 +984,7 @@ class LiteralVar(ImmutableVar):
924
984
  if value is None:
925
985
  return LiteralNoneVar.create(_var_data=_var_data)
926
986
 
927
- from reflex.event import EventChain, EventSpec
987
+ from reflex.event import EventChain, EventHandler, EventSpec
928
988
  from reflex.utils.format import get_event_handler_parts
929
989
 
930
990
  from .function import ArgsFunctionOperation, FunctionStringVar
@@ -948,14 +1008,12 @@ class LiteralVar(ImmutableVar):
948
1008
  sig = inspect.signature(value.args_spec) # type: ignore
949
1009
  if sig.parameters:
950
1010
  arg_def = tuple((f"_{p}" for p in sig.parameters))
951
- arg_def_expr = LiteralVar.create(
952
- [ImmutableVar.create_safe(arg) for arg in arg_def]
953
- )
1011
+ arg_def_expr = LiteralVar.create([Var(_js_expr=arg) for arg in arg_def])
954
1012
  else:
955
1013
  # add a default argument for addEvents if none were specified in value.args_spec
956
1014
  # used to trigger the preventDefault() on the event.
957
1015
  arg_def = ("...args",)
958
- arg_def_expr = ImmutableVar.create_safe("args")
1016
+ arg_def_expr = Var(_js_expr="args")
959
1017
 
960
1018
  return ArgsFunctionOperation.create(
961
1019
  arg_def,
@@ -968,9 +1026,20 @@ class LiteralVar(ImmutableVar):
968
1026
  ),
969
1027
  )
970
1028
 
1029
+ if isinstance(value, EventHandler):
1030
+ return Var(_js_expr=".".join(filter(None, get_event_handler_parts(value))))
1031
+
971
1032
  if isinstance(value, Base):
1033
+ # get the fields of the pydantic class
1034
+ fields = value.__fields__.keys()
1035
+ one_level_dict = {field: getattr(value, field) for field in fields}
1036
+
972
1037
  return LiteralObjectVar.create(
973
- {k: (None if callable(v) else v) for k, v in value.dict().items()},
1038
+ {
1039
+ field: value
1040
+ for field, value in one_level_dict.items()
1041
+ if not callable(value)
1042
+ },
974
1043
  _var_type=type(value),
975
1044
  _var_data=_var_data,
976
1045
  )
@@ -983,8 +1052,22 @@ class LiteralVar(ImmutableVar):
983
1052
  _var_type=type(value),
984
1053
  _var_data=_var_data,
985
1054
  )
1055
+ if isinstance(serialized_value, str):
1056
+ return LiteralStringVar.create(
1057
+ serialized_value, _var_type=type(value), _var_data=_var_data
1058
+ )
986
1059
  return LiteralVar.create(serialized_value, _var_data=_var_data)
987
1060
 
1061
+ if dataclasses.is_dataclass(value) and not isinstance(value, type):
1062
+ return LiteralObjectVar.create(
1063
+ {
1064
+ k: (None if callable(v) else v)
1065
+ for k, v in dataclasses.asdict(value).items()
1066
+ },
1067
+ _var_type=type(value),
1068
+ _var_data=_var_data,
1069
+ )
1070
+
988
1071
  raise TypeError(
989
1072
  f"Unsupported type {type(value)} for LiteralVar. Tried to create a LiteralVar from {value}."
990
1073
  )
@@ -1003,6 +1086,19 @@ class LiteralVar(ImmutableVar):
1003
1086
  )
1004
1087
 
1005
1088
 
1089
+ @serializers.serializer
1090
+ def serialize_literal(value: LiteralVar):
1091
+ """Serialize a Literal type.
1092
+
1093
+ Args:
1094
+ value: The Literal to serialize.
1095
+
1096
+ Returns:
1097
+ The serialized Literal.
1098
+ """
1099
+ return serializers.serialize(value._var_value)
1100
+
1101
+
1006
1102
  P = ParamSpec("P")
1007
1103
  T = TypeVar("T")
1008
1104
 
@@ -1011,7 +1107,7 @@ T = TypeVar("T")
1011
1107
  @overload
1012
1108
  def var_operation(
1013
1109
  func: Callable[P, CustomVarOperationReturn[NoReturn]],
1014
- ) -> Callable[P, ImmutableVar]: ...
1110
+ ) -> Callable[P, Var]: ...
1015
1111
 
1016
1112
 
1017
1113
  @overload
@@ -1055,7 +1151,7 @@ def var_operation(
1055
1151
 
1056
1152
  def var_operation(
1057
1153
  func: Callable[P, CustomVarOperationReturn[T]],
1058
- ) -> Callable[P, ImmutableVar[T]]:
1154
+ ) -> Callable[P, Var[T]]:
1059
1155
  """Decorator for creating a var operation.
1060
1156
 
1061
1157
  Example:
@@ -1073,18 +1169,14 @@ def var_operation(
1073
1169
  """
1074
1170
 
1075
1171
  @functools.wraps(func)
1076
- def wrapper(*args: P.args, **kwargs: P.kwargs) -> ImmutableVar[T]:
1172
+ def wrapper(*args: P.args, **kwargs: P.kwargs) -> Var[T]:
1077
1173
  func_args = list(inspect.signature(func).parameters)
1078
1174
  args_vars = {
1079
- func_args[i]: (
1080
- LiteralVar.create(arg) if not isinstance(arg, ImmutableVar) else arg
1081
- )
1175
+ func_args[i]: (LiteralVar.create(arg) if not isinstance(arg, Var) else arg)
1082
1176
  for i, arg in enumerate(args)
1083
1177
  }
1084
1178
  kwargs_vars = {
1085
- key: LiteralVar.create(value)
1086
- if not isinstance(value, ImmutableVar)
1087
- else value
1179
+ key: LiteralVar.create(value) if not isinstance(value, Var) else value
1088
1180
  for key, value in kwargs.items()
1089
1181
  }
1090
1182
 
@@ -1133,7 +1225,7 @@ def figure_out_type(value: Any) -> types.GenericType:
1133
1225
  unionize(*(figure_out_type(k) for k in value)),
1134
1226
  unionize(*(figure_out_type(v) for v in value.values())),
1135
1227
  ]
1136
- if isinstance(value, ImmutableVar):
1228
+ if isinstance(value, Var):
1137
1229
  return value._var_type
1138
1230
  return type(value)
1139
1231
 
@@ -1156,7 +1248,7 @@ class CachedVarOperation:
1156
1248
 
1157
1249
  def __post_init__(self):
1158
1250
  """Post-initialize the CachedVarOperation."""
1159
- object.__delattr__(self, "_var_name")
1251
+ object.__delattr__(self, "_js_expr")
1160
1252
 
1161
1253
  def __getattr__(self, name: str) -> Any:
1162
1254
  """Get an attribute of the var.
@@ -1167,7 +1259,7 @@ class CachedVarOperation:
1167
1259
  Returns:
1168
1260
  The attribute.
1169
1261
  """
1170
- if name == "_var_name":
1262
+ if name == "_js_expr":
1171
1263
  return self._cached_var_name
1172
1264
 
1173
1265
  parent_classes = inspect.getmro(self.__class__)
@@ -1194,9 +1286,7 @@ class CachedVarOperation:
1194
1286
  return VarData.merge(
1195
1287
  *map(
1196
1288
  lambda value: (
1197
- value._get_all_var_data()
1198
- if isinstance(value, ImmutableVar)
1199
- else None
1289
+ value._get_all_var_data() if isinstance(value, Var) else None
1200
1290
  ),
1201
1291
  map(
1202
1292
  lambda field: getattr(self, field.name),
@@ -1218,13 +1308,13 @@ class CachedVarOperation:
1218
1308
  *[
1219
1309
  getattr(self, field.name)
1220
1310
  for field in dataclasses.fields(self) # type: ignore
1221
- if field.name not in ["_var_name", "_var_data", "_var_type"]
1311
+ if field.name not in ["_js_expr", "_var_data", "_var_type"]
1222
1312
  ],
1223
1313
  )
1224
1314
  )
1225
1315
 
1226
1316
 
1227
- def and_operation(a: ImmutableVar | Any, b: ImmutableVar | Any) -> ImmutableVar:
1317
+ def and_operation(a: Var | Any, b: Var | Any) -> Var:
1228
1318
  """Perform a logical AND operation on two variables.
1229
1319
 
1230
1320
  Args:
@@ -1238,7 +1328,7 @@ def and_operation(a: ImmutableVar | Any, b: ImmutableVar | Any) -> ImmutableVar:
1238
1328
 
1239
1329
 
1240
1330
  @var_operation
1241
- def _and_operation(a: ImmutableVar, b: ImmutableVar):
1331
+ def _and_operation(a: Var, b: Var):
1242
1332
  """Perform a logical AND operation on two variables.
1243
1333
 
1244
1334
  Args:
@@ -1254,7 +1344,7 @@ def _and_operation(a: ImmutableVar, b: ImmutableVar):
1254
1344
  )
1255
1345
 
1256
1346
 
1257
- def or_operation(a: ImmutableVar | Any, b: ImmutableVar | Any) -> ImmutableVar:
1347
+ def or_operation(a: Var | Any, b: Var | Any) -> Var:
1258
1348
  """Perform a logical OR operation on two variables.
1259
1349
 
1260
1350
  Args:
@@ -1268,7 +1358,7 @@ def or_operation(a: ImmutableVar | Any, b: ImmutableVar | Any) -> ImmutableVar:
1268
1358
 
1269
1359
 
1270
1360
  @var_operation
1271
- def _or_operation(a: ImmutableVar, b: ImmutableVar):
1361
+ def _or_operation(a: Var, b: Var):
1272
1362
  """Perform a logical OR operation on two variables.
1273
1363
 
1274
1364
  Args:
@@ -1289,36 +1379,36 @@ def _or_operation(a: ImmutableVar, b: ImmutableVar):
1289
1379
  frozen=True,
1290
1380
  **{"slots": True} if sys.version_info >= (3, 10) else {},
1291
1381
  )
1292
- class ImmutableCallableVar(ImmutableVar):
1382
+ class CallableVar(Var):
1293
1383
  """Decorate a Var-returning function to act as both a Var and a function.
1294
1384
 
1295
1385
  This is used as a compatibility shim for replacing Var objects in the
1296
1386
  API with functions that return a family of Var.
1297
1387
  """
1298
1388
 
1299
- fn: Callable[..., ImmutableVar] = dataclasses.field(
1300
- default_factory=lambda: lambda: ImmutableVar(_var_name="undefined")
1389
+ fn: Callable[..., Var] = dataclasses.field(
1390
+ default_factory=lambda: lambda: Var(_js_expr="undefined")
1301
1391
  )
1302
- original_var: ImmutableVar = dataclasses.field(
1303
- default_factory=lambda: ImmutableVar(_var_name="undefined")
1392
+ original_var: Var = dataclasses.field(
1393
+ default_factory=lambda: Var(_js_expr="undefined")
1304
1394
  )
1305
1395
 
1306
- def __init__(self, fn: Callable[..., ImmutableVar]):
1396
+ def __init__(self, fn: Callable[..., Var]):
1307
1397
  """Initialize a CallableVar.
1308
1398
 
1309
1399
  Args:
1310
1400
  fn: The function to decorate (must return Var)
1311
1401
  """
1312
1402
  original_var = fn()
1313
- super(ImmutableCallableVar, self).__init__(
1314
- _var_name=original_var._var_name,
1403
+ super(CallableVar, self).__init__(
1404
+ _js_expr=original_var._js_expr,
1315
1405
  _var_type=original_var._var_type,
1316
1406
  _var_data=VarData.merge(original_var._get_all_var_data()),
1317
1407
  )
1318
1408
  object.__setattr__(self, "fn", fn)
1319
1409
  object.__setattr__(self, "original_var", original_var)
1320
1410
 
1321
- def __call__(self, *args, **kwargs) -> ImmutableVar:
1411
+ def __call__(self, *args, **kwargs) -> Var:
1322
1412
  """Call the decorated function.
1323
1413
 
1324
1414
  Args:
@@ -1347,13 +1437,13 @@ DICT_VAL = TypeVar("DICT_VAL")
1347
1437
  LIST_INSIDE = TypeVar("LIST_INSIDE")
1348
1438
 
1349
1439
 
1350
- class FakeComputedVarBaseClass(Var, property):
1440
+ class FakeComputedVarBaseClass(property):
1351
1441
  """A fake base class for ComputedVar to avoid inheriting from property."""
1352
1442
 
1353
1443
  __pydantic_run_validation__ = False
1354
1444
 
1355
1445
 
1356
- def is_computed_var(obj: Any) -> TypeGuard[ImmutableComputedVar]:
1446
+ def is_computed_var(obj: Any) -> TypeGuard[ComputedVar]:
1357
1447
  """Check if the object is a ComputedVar.
1358
1448
 
1359
1449
  Args:
@@ -1370,7 +1460,7 @@ def is_computed_var(obj: Any) -> TypeGuard[ImmutableComputedVar]:
1370
1460
  frozen=True,
1371
1461
  **{"slots": True} if sys.version_info >= (3, 10) else {},
1372
1462
  )
1373
- class ImmutableComputedVar(ImmutableVar[RETURN_TYPE]):
1463
+ class ComputedVar(Var[RETURN_TYPE]):
1374
1464
  """A field with computed getters."""
1375
1465
 
1376
1466
  # Whether to track dependencies and cache computed values
@@ -1400,7 +1490,7 @@ class ImmutableComputedVar(ImmutableVar[RETURN_TYPE]):
1400
1490
  fget: Callable[[BASE_STATE], RETURN_TYPE],
1401
1491
  initial_value: RETURN_TYPE | types.Unset = types.Unset(),
1402
1492
  cache: bool = False,
1403
- deps: Optional[List[Union[str, ImmutableVar]]] = None,
1493
+ deps: Optional[List[Union[str, Var]]] = None,
1404
1494
  auto_deps: bool = True,
1405
1495
  interval: Optional[Union[int, datetime.timedelta]] = None,
1406
1496
  backend: bool | None = None,
@@ -1424,12 +1514,12 @@ class ImmutableComputedVar(ImmutableVar[RETURN_TYPE]):
1424
1514
  hints = get_type_hints(fget)
1425
1515
  hint = hints.get("return", Any)
1426
1516
 
1427
- kwargs["_var_name"] = kwargs.pop("_var_name", fget.__name__)
1517
+ kwargs["_js_expr"] = kwargs.pop("_js_expr", fget.__name__)
1428
1518
  kwargs["_var_type"] = kwargs.pop("_var_type", hint)
1429
1519
 
1430
- ImmutableVar.__init__(
1520
+ Var.__init__(
1431
1521
  self,
1432
- _var_name=kwargs.pop("_var_name"),
1522
+ _js_expr=kwargs.pop("_js_expr"),
1433
1523
  _var_type=kwargs.pop("_var_type"),
1434
1524
  _var_data=kwargs.pop("_var_data", None),
1435
1525
  )
@@ -1450,7 +1540,7 @@ class ImmutableComputedVar(ImmutableVar[RETURN_TYPE]):
1450
1540
  deps = []
1451
1541
  else:
1452
1542
  for dep in deps:
1453
- if isinstance(dep, ImmutableVar):
1543
+ if isinstance(dep, Var):
1454
1544
  continue
1455
1545
  if isinstance(dep, str) and dep != "":
1456
1546
  continue
@@ -1460,7 +1550,7 @@ class ImmutableComputedVar(ImmutableVar[RETURN_TYPE]):
1460
1550
  object.__setattr__(
1461
1551
  self,
1462
1552
  "_static_deps",
1463
- {dep._var_name if isinstance(dep, ImmutableVar) else dep for dep in deps},
1553
+ {dep._js_expr if isinstance(dep, Var) else dep for dep in deps},
1464
1554
  )
1465
1555
  object.__setattr__(self, "_auto_deps", auto_deps)
1466
1556
 
@@ -1488,7 +1578,7 @@ class ImmutableComputedVar(ImmutableVar[RETURN_TYPE]):
1488
1578
  auto_deps=kwargs.pop("auto_deps", self._auto_deps),
1489
1579
  interval=kwargs.pop("interval", self._update_interval),
1490
1580
  backend=kwargs.pop("backend", self._backend),
1491
- _var_name=kwargs.pop("_var_name", self._var_name),
1581
+ _js_expr=kwargs.pop("_js_expr", self._js_expr),
1492
1582
  _var_type=kwargs.pop("_var_type", self._var_type),
1493
1583
  _var_data=kwargs.pop(
1494
1584
  "_var_data", VarData.merge(self._var_data, merge_var_data)
@@ -1508,7 +1598,7 @@ class ImmutableComputedVar(ImmutableVar[RETURN_TYPE]):
1508
1598
  Returns:
1509
1599
  An attribute name.
1510
1600
  """
1511
- return f"__cached_{self._var_name}"
1601
+ return f"__cached_{self._js_expr}"
1512
1602
 
1513
1603
  @property
1514
1604
  def _last_updated_attr(self) -> str:
@@ -1517,7 +1607,7 @@ class ImmutableComputedVar(ImmutableVar[RETURN_TYPE]):
1517
1607
  Returns:
1518
1608
  An attribute name.
1519
1609
  """
1520
- return f"__last_updated_{self._var_name}"
1610
+ return f"__last_updated_{self._js_expr}"
1521
1611
 
1522
1612
  def needs_update(self, instance: BaseState) -> bool:
1523
1613
  """Check if the computed var needs to be updated.
@@ -1537,50 +1627,48 @@ class ImmutableComputedVar(ImmutableVar[RETURN_TYPE]):
1537
1627
 
1538
1628
  @overload
1539
1629
  def __get__(
1540
- self: ImmutableComputedVar[int] | ImmutableComputedVar[float],
1630
+ self: ComputedVar[int] | ComputedVar[float],
1541
1631
  instance: None,
1542
1632
  owner: Type,
1543
1633
  ) -> NumberVar: ...
1544
1634
 
1545
1635
  @overload
1546
1636
  def __get__(
1547
- self: ImmutableComputedVar[str],
1637
+ self: ComputedVar[str],
1548
1638
  instance: None,
1549
1639
  owner: Type,
1550
1640
  ) -> StringVar: ...
1551
1641
 
1552
1642
  @overload
1553
1643
  def __get__(
1554
- self: ImmutableComputedVar[dict[DICT_KEY, DICT_VAL]],
1644
+ self: ComputedVar[dict[DICT_KEY, DICT_VAL]],
1555
1645
  instance: None,
1556
1646
  owner: Type,
1557
1647
  ) -> ObjectVar[dict[DICT_KEY, DICT_VAL]]: ...
1558
1648
 
1559
1649
  @overload
1560
1650
  def __get__(
1561
- self: ImmutableComputedVar[list[LIST_INSIDE]],
1651
+ self: ComputedVar[list[LIST_INSIDE]],
1562
1652
  instance: None,
1563
1653
  owner: Type,
1564
1654
  ) -> ArrayVar[list[LIST_INSIDE]]: ...
1565
1655
 
1566
1656
  @overload
1567
1657
  def __get__(
1568
- self: ImmutableComputedVar[set[LIST_INSIDE]],
1658
+ self: ComputedVar[set[LIST_INSIDE]],
1569
1659
  instance: None,
1570
1660
  owner: Type,
1571
1661
  ) -> ArrayVar[set[LIST_INSIDE]]: ...
1572
1662
 
1573
1663
  @overload
1574
1664
  def __get__(
1575
- self: ImmutableComputedVar[tuple[LIST_INSIDE, ...]],
1665
+ self: ComputedVar[tuple[LIST_INSIDE, ...]],
1576
1666
  instance: None,
1577
1667
  owner: Type,
1578
1668
  ) -> ArrayVar[tuple[LIST_INSIDE, ...]]: ...
1579
1669
 
1580
1670
  @overload
1581
- def __get__(
1582
- self, instance: None, owner: Type
1583
- ) -> ImmutableComputedVar[RETURN_TYPE]: ...
1671
+ def __get__(self, instance: None, owner: Type) -> ComputedVar[RETURN_TYPE]: ...
1584
1672
 
1585
1673
  @overload
1586
1674
  def __get__(self, instance: BaseState, owner: Type) -> RETURN_TYPE: ...
@@ -1599,13 +1687,13 @@ class ImmutableComputedVar(ImmutableVar[RETURN_TYPE]):
1599
1687
  """
1600
1688
  if instance is None:
1601
1689
  state_where_defined = owner
1602
- while self.fget.__name__ in state_where_defined.inherited_vars:
1690
+ while self._js_expr in state_where_defined.inherited_vars:
1603
1691
  state_where_defined = state_where_defined.get_parent_state()
1604
1692
 
1605
1693
  return self._replace(
1606
- _var_name=format_state_name(state_where_defined.get_full_name())
1694
+ _js_expr=format_state_name(state_where_defined.get_full_name())
1607
1695
  + "."
1608
- + self._var_name,
1696
+ + self._js_expr,
1609
1697
  merge_var_data=VarData.from_state(state_where_defined),
1610
1698
  ).guess_type()
1611
1699
 
@@ -1705,7 +1793,7 @@ class ImmutableComputedVar(ImmutableVar[RETURN_TYPE]):
1705
1793
  )
1706
1794
  # recurse into property fget functions
1707
1795
  elif isinstance(ref_obj, property) and not isinstance(
1708
- ref_obj, ImmutableComputedVar
1796
+ ref_obj, ComputedVar
1709
1797
  ):
1710
1798
  d.update(
1711
1799
  self._deps(
@@ -1773,7 +1861,7 @@ class ImmutableComputedVar(ImmutableVar[RETURN_TYPE]):
1773
1861
  return self._fget
1774
1862
 
1775
1863
 
1776
- class DynamicRouteVar(ImmutableComputedVar[Union[str, List[str]]]):
1864
+ class DynamicRouteVar(ComputedVar[Union[str, List[str]]]):
1777
1865
  """A ComputedVar that represents a dynamic route."""
1778
1866
 
1779
1867
  pass
@@ -1784,45 +1872,41 @@ if TYPE_CHECKING:
1784
1872
 
1785
1873
 
1786
1874
  @overload
1787
- def immutable_computed_var(
1875
+ def computed_var(
1788
1876
  fget: None = None,
1789
1877
  initial_value: Any | types.Unset = types.Unset(),
1790
1878
  cache: bool = False,
1791
- deps: Optional[List[Union[str, ImmutableVar]]] = None,
1879
+ deps: Optional[List[Union[str, Var]]] = None,
1792
1880
  auto_deps: bool = True,
1793
1881
  interval: Optional[Union[datetime.timedelta, int]] = None,
1794
1882
  backend: bool | None = None,
1795
1883
  **kwargs,
1796
- ) -> Callable[
1797
- [Callable[[BASE_STATE], RETURN_TYPE]], ImmutableComputedVar[RETURN_TYPE]
1798
- ]: ...
1884
+ ) -> Callable[[Callable[[BASE_STATE], RETURN_TYPE]], ComputedVar[RETURN_TYPE]]: ...
1799
1885
 
1800
1886
 
1801
1887
  @overload
1802
- def immutable_computed_var(
1888
+ def computed_var(
1803
1889
  fget: Callable[[BASE_STATE], RETURN_TYPE],
1804
1890
  initial_value: RETURN_TYPE | types.Unset = types.Unset(),
1805
1891
  cache: bool = False,
1806
- deps: Optional[List[Union[str, ImmutableVar]]] = None,
1892
+ deps: Optional[List[Union[str, Var]]] = None,
1807
1893
  auto_deps: bool = True,
1808
1894
  interval: Optional[Union[datetime.timedelta, int]] = None,
1809
1895
  backend: bool | None = None,
1810
1896
  **kwargs,
1811
- ) -> ImmutableComputedVar[RETURN_TYPE]: ...
1897
+ ) -> ComputedVar[RETURN_TYPE]: ...
1812
1898
 
1813
1899
 
1814
- def immutable_computed_var(
1900
+ def computed_var(
1815
1901
  fget: Callable[[BASE_STATE], Any] | None = None,
1816
1902
  initial_value: Any | types.Unset = types.Unset(),
1817
1903
  cache: bool = False,
1818
- deps: Optional[List[Union[str, ImmutableVar]]] = None,
1904
+ deps: Optional[List[Union[str, Var]]] = None,
1819
1905
  auto_deps: bool = True,
1820
1906
  interval: Optional[Union[datetime.timedelta, int]] = None,
1821
1907
  backend: bool | None = None,
1822
1908
  **kwargs,
1823
- ) -> (
1824
- ImmutableComputedVar | Callable[[Callable[[BASE_STATE], Any]], ImmutableComputedVar]
1825
- ):
1909
+ ) -> ComputedVar | Callable[[Callable[[BASE_STATE], Any]], ComputedVar]:
1826
1910
  """A ComputedVar decorator with or without kwargs.
1827
1911
 
1828
1912
  Args:
@@ -1849,10 +1933,10 @@ def immutable_computed_var(
1849
1933
  raise VarDependencyError("Cannot track dependencies without caching.")
1850
1934
 
1851
1935
  if fget is not None:
1852
- return ImmutableComputedVar(fget, cache=cache)
1936
+ return ComputedVar(fget, cache=cache)
1853
1937
 
1854
- def wrapper(fget: Callable[[BASE_STATE], Any]) -> ImmutableComputedVar:
1855
- return ImmutableComputedVar(
1938
+ def wrapper(fget: Callable[[BASE_STATE], Any]) -> ComputedVar:
1939
+ return ComputedVar(
1856
1940
  fget,
1857
1941
  initial_value=initial_value,
1858
1942
  cache=cache,
@@ -1869,7 +1953,7 @@ def immutable_computed_var(
1869
1953
  RETURN = TypeVar("RETURN")
1870
1954
 
1871
1955
 
1872
- class CustomVarOperationReturn(ImmutableVar[RETURN]):
1956
+ class CustomVarOperationReturn(Var[RETURN]):
1873
1957
  """Base class for custom var operations."""
1874
1958
 
1875
1959
  @classmethod
@@ -1890,7 +1974,7 @@ class CustomVarOperationReturn(ImmutableVar[RETURN]):
1890
1974
  The CustomVarOperation.
1891
1975
  """
1892
1976
  return CustomVarOperationReturn(
1893
- _var_name=js_expression,
1977
+ _js_expr=js_expression,
1894
1978
  _var_type=_var_type or Any,
1895
1979
  _var_data=_var_data,
1896
1980
  )
@@ -1917,12 +2001,10 @@ def var_operation_return(
1917
2001
  frozen=True,
1918
2002
  **{"slots": True} if sys.version_info >= (3, 10) else {},
1919
2003
  )
1920
- class CustomVarOperation(CachedVarOperation, ImmutableVar[T]):
2004
+ class CustomVarOperation(CachedVarOperation, Var[T]):
1921
2005
  """Base class for custom var operations."""
1922
2006
 
1923
- _args: Tuple[Tuple[str, ImmutableVar], ...] = dataclasses.field(
1924
- default_factory=tuple
1925
- )
2007
+ _args: Tuple[Tuple[str, Var], ...] = dataclasses.field(default_factory=tuple)
1926
2008
 
1927
2009
  _return: CustomVarOperationReturn[T] = dataclasses.field(
1928
2010
  default_factory=lambda: CustomVarOperationReturn.create("")
@@ -1956,7 +2038,7 @@ class CustomVarOperation(CachedVarOperation, ImmutableVar[T]):
1956
2038
  @classmethod
1957
2039
  def create(
1958
2040
  cls,
1959
- args: Tuple[Tuple[str, ImmutableVar], ...],
2041
+ args: Tuple[Tuple[str, Var], ...],
1960
2042
  return_var: CustomVarOperationReturn[T],
1961
2043
  _var_data: VarData | None = None,
1962
2044
  ) -> CustomVarOperation[T]:
@@ -1971,7 +2053,7 @@ class CustomVarOperation(CachedVarOperation, ImmutableVar[T]):
1971
2053
  The CustomVarOperation.
1972
2054
  """
1973
2055
  return CustomVarOperation(
1974
- _var_name="",
2056
+ _js_expr="",
1975
2057
  _var_type=return_var._var_type,
1976
2058
  _var_data=_var_data,
1977
2059
  _args=args,
@@ -1979,7 +2061,7 @@ class CustomVarOperation(CachedVarOperation, ImmutableVar[T]):
1979
2061
  )
1980
2062
 
1981
2063
 
1982
- class NoneVar(ImmutableVar[None]):
2064
+ class NoneVar(Var[None]):
1983
2065
  """A var representing None."""
1984
2066
 
1985
2067
 
@@ -2008,7 +2090,7 @@ class LiteralNoneVar(LiteralVar, NoneVar):
2008
2090
  The var.
2009
2091
  """
2010
2092
  return LiteralNoneVar(
2011
- _var_name="null",
2093
+ _js_expr="null",
2012
2094
  _var_type=None,
2013
2095
  _var_data=_var_data,
2014
2096
  )
@@ -2051,7 +2133,7 @@ class ToNoneOperation(CachedVarOperation, NoneVar):
2051
2133
  The ToNoneOperation.
2052
2134
  """
2053
2135
  return ToNoneOperation(
2054
- _var_name="",
2136
+ _js_expr="",
2055
2137
  _var_type=None,
2056
2138
  _var_data=_var_data,
2057
2139
  _original_var=var,
@@ -2063,7 +2145,7 @@ class ToNoneOperation(CachedVarOperation, NoneVar):
2063
2145
  frozen=True,
2064
2146
  **{"slots": True} if sys.version_info >= (3, 10) else {},
2065
2147
  )
2066
- class StateOperation(CachedVarOperation, ImmutableVar):
2148
+ class StateOperation(CachedVarOperation, Var):
2067
2149
  """A var operation that accesses a field on an object."""
2068
2150
 
2069
2151
  _state_name: str = dataclasses.field(default="")
@@ -2087,7 +2169,7 @@ class StateOperation(CachedVarOperation, ImmutableVar):
2087
2169
  Returns:
2088
2170
  The attribute.
2089
2171
  """
2090
- if name == "_var_name":
2172
+ if name == "_js_expr":
2091
2173
  return self._cached_var_name
2092
2174
 
2093
2175
  return getattr(self._field, name)
@@ -2096,7 +2178,7 @@ class StateOperation(CachedVarOperation, ImmutableVar):
2096
2178
  def create(
2097
2179
  cls,
2098
2180
  state_name: str,
2099
- field: ImmutableVar,
2181
+ field: Var,
2100
2182
  _var_data: VarData | None = None,
2101
2183
  ) -> StateOperation:
2102
2184
  """Create a DotOperation.
@@ -2110,7 +2192,7 @@ class StateOperation(CachedVarOperation, ImmutableVar):
2110
2192
  The DotOperation.
2111
2193
  """
2112
2194
  return StateOperation(
2113
- _var_name="",
2195
+ _js_expr="",
2114
2196
  _var_type=field._var_type,
2115
2197
  _var_data=_var_data,
2116
2198
  _state_name=state_name,
@@ -2134,7 +2216,7 @@ class ToOperation:
2134
2216
 
2135
2217
  def __post_init__(self):
2136
2218
  """Post initialization."""
2137
- object.__delattr__(self, "_var_name")
2219
+ object.__delattr__(self, "_js_expr")
2138
2220
 
2139
2221
  def __hash__(self) -> int:
2140
2222
  """Calculate the hash value of the object.
@@ -2173,8 +2255,287 @@ class ToOperation:
2173
2255
  The ToOperation.
2174
2256
  """
2175
2257
  return cls(
2176
- _var_name="", # type: ignore
2258
+ _js_expr="", # type: ignore
2177
2259
  _var_data=_var_data, # type: ignore
2178
2260
  _var_type=_var_type or cls._default_var_type, # type: ignore
2179
2261
  _original=value, # type: ignore
2180
2262
  )
2263
+
2264
+
2265
+ def get_uuid_string_var() -> Var:
2266
+ """Return a Var that generates a single memoized UUID via .web/utils/state.js.
2267
+
2268
+ useMemo with an empty dependency array ensures that the generated UUID is
2269
+ consistent across re-renders of the component.
2270
+
2271
+ Returns:
2272
+ A Var that generates a UUID at runtime.
2273
+ """
2274
+ from reflex.utils.imports import ImportVar
2275
+ from reflex.vars import Var
2276
+
2277
+ unique_uuid_var = get_unique_variable_name()
2278
+ unique_uuid_var_data = VarData(
2279
+ imports={
2280
+ f"/{constants.Dirs.STATE_PATH}": {ImportVar(tag="generateUUID")}, # type: ignore
2281
+ "react": "useMemo",
2282
+ },
2283
+ hooks={f"const {unique_uuid_var} = useMemo(generateUUID, [])": None},
2284
+ )
2285
+
2286
+ return Var(
2287
+ _js_expr=unique_uuid_var,
2288
+ _var_type=str,
2289
+ _var_data=unique_uuid_var_data,
2290
+ )
2291
+
2292
+
2293
+ # Set of unique variable names.
2294
+ USED_VARIABLES = set()
2295
+
2296
+
2297
+ def get_unique_variable_name() -> str:
2298
+ """Get a unique variable name.
2299
+
2300
+ Returns:
2301
+ The unique variable name.
2302
+ """
2303
+ name = "".join([random.choice(string.ascii_lowercase) for _ in range(8)])
2304
+ if name not in USED_VARIABLES:
2305
+ USED_VARIABLES.add(name)
2306
+ return name
2307
+ return get_unique_variable_name()
2308
+
2309
+
2310
+ @dataclasses.dataclass(
2311
+ eq=True,
2312
+ frozen=True,
2313
+ )
2314
+ class VarData:
2315
+ """Metadata associated with a x."""
2316
+
2317
+ # The name of the enclosing state.
2318
+ state: str = dataclasses.field(default="")
2319
+
2320
+ # Imports needed to render this var
2321
+ imports: ImmutableParsedImportDict = dataclasses.field(default_factory=tuple)
2322
+
2323
+ # Hooks that need to be present in the component to render this var
2324
+ hooks: Tuple[str, ...] = dataclasses.field(default_factory=tuple)
2325
+
2326
+ def __init__(
2327
+ self,
2328
+ state: str = "",
2329
+ imports: ImportDict | ParsedImportDict | None = None,
2330
+ hooks: dict[str, None] | None = None,
2331
+ ):
2332
+ """Initialize the var data.
2333
+
2334
+ Args:
2335
+ state: The name of the enclosing state.
2336
+ imports: Imports needed to render this var.
2337
+ hooks: Hooks that need to be present in the component to render this var.
2338
+ """
2339
+ immutable_imports: ImmutableParsedImportDict = tuple(
2340
+ sorted(
2341
+ ((k, tuple(sorted(v))) for k, v in parse_imports(imports or {}).items())
2342
+ )
2343
+ )
2344
+ object.__setattr__(self, "state", state)
2345
+ object.__setattr__(self, "imports", immutable_imports)
2346
+ object.__setattr__(self, "hooks", tuple(hooks or {}))
2347
+
2348
+ def old_school_imports(self) -> ImportDict:
2349
+ """Return the imports as a mutable dict.
2350
+
2351
+ Returns:
2352
+ The imports as a mutable dict.
2353
+ """
2354
+ return dict((k, list(v)) for k, v in self.imports)
2355
+
2356
+ @classmethod
2357
+ def merge(cls, *others: VarData | None) -> VarData | None:
2358
+ """Merge multiple var data objects.
2359
+
2360
+ Args:
2361
+ *others: The var data objects to merge.
2362
+
2363
+ Returns:
2364
+ The merged var data object.
2365
+ """
2366
+ state = ""
2367
+ _imports = {}
2368
+ hooks = {}
2369
+ for var_data in others:
2370
+ if var_data is None:
2371
+ continue
2372
+ state = state or var_data.state
2373
+ _imports = imports.merge_imports(_imports, var_data.imports)
2374
+ hooks.update(
2375
+ var_data.hooks
2376
+ if isinstance(var_data.hooks, dict)
2377
+ else {k: None for k in var_data.hooks}
2378
+ )
2379
+
2380
+ if state or _imports or hooks:
2381
+ return VarData(
2382
+ state=state,
2383
+ imports=_imports,
2384
+ hooks=hooks,
2385
+ )
2386
+ return None
2387
+
2388
+ def __bool__(self) -> bool:
2389
+ """Check if the var data is non-empty.
2390
+
2391
+ Returns:
2392
+ True if any field is set to a non-default value.
2393
+ """
2394
+ return bool(self.state or self.imports or self.hooks)
2395
+
2396
+ def __eq__(self, other: Any) -> bool:
2397
+ """Check if two var data objects are equal.
2398
+
2399
+ Args:
2400
+ other: The other var data object to compare.
2401
+
2402
+ Returns:
2403
+ True if all fields are equal and collapsed imports are equal.
2404
+ """
2405
+ if not isinstance(other, VarData):
2406
+ return False
2407
+
2408
+ # Don't compare interpolations - that's added in by the decoder, and
2409
+ # not part of the vardata itself.
2410
+ return (
2411
+ self.state == other.state
2412
+ and self.hooks
2413
+ == (
2414
+ other.hooks if isinstance(other, VarData) else tuple(other.hooks.keys())
2415
+ )
2416
+ and imports.collapse_imports(self.imports)
2417
+ == imports.collapse_imports(other.imports)
2418
+ )
2419
+
2420
+ @classmethod
2421
+ def from_state(cls, state: Type[BaseState] | str) -> VarData:
2422
+ """Set the state of the var.
2423
+
2424
+ Args:
2425
+ state: The state to set or the full name of the state.
2426
+
2427
+ Returns:
2428
+ The var with the set state.
2429
+ """
2430
+ from reflex.utils import format
2431
+
2432
+ state_name = state if isinstance(state, str) else state.get_full_name()
2433
+ new_var_data = VarData(
2434
+ state=state_name,
2435
+ hooks={
2436
+ "const {0} = useContext(StateContexts.{0})".format(
2437
+ format.format_state_name(state_name)
2438
+ ): None
2439
+ },
2440
+ imports={
2441
+ f"/{constants.Dirs.CONTEXTS_PATH}": [ImportVar(tag="StateContexts")],
2442
+ "react": [ImportVar(tag="useContext")],
2443
+ },
2444
+ )
2445
+ return new_var_data
2446
+
2447
+
2448
+ def _decode_var_immutable(value: str) -> tuple[VarData | None, str]:
2449
+ """Decode the state name from a formatted var.
2450
+
2451
+ Args:
2452
+ value: The value to extract the state name from.
2453
+
2454
+ Returns:
2455
+ The extracted state name and the value without the state name.
2456
+ """
2457
+ var_datas = []
2458
+ if isinstance(value, str):
2459
+ # fast path if there is no encoded VarData
2460
+ if constants.REFLEX_VAR_OPENING_TAG not in value:
2461
+ return None, value
2462
+
2463
+ offset = 0
2464
+
2465
+ # Find all tags.
2466
+ while m := _decode_var_pattern.search(value):
2467
+ start, end = m.span()
2468
+ value = value[:start] + value[end:]
2469
+
2470
+ serialized_data = m.group(1)
2471
+
2472
+ if serialized_data.isnumeric() or (
2473
+ serialized_data[0] == "-" and serialized_data[1:].isnumeric()
2474
+ ):
2475
+ # This is a global immutable var.
2476
+ var = _global_vars[int(serialized_data)]
2477
+ var_data = var._get_all_var_data()
2478
+
2479
+ if var_data is not None:
2480
+ var_datas.append(var_data)
2481
+ offset += end - start
2482
+
2483
+ return VarData.merge(*var_datas) if var_datas else None, value
2484
+
2485
+
2486
+ # Compile regex for finding reflex var tags.
2487
+ _decode_var_pattern_re = (
2488
+ rf"{constants.REFLEX_VAR_OPENING_TAG}(.*?){constants.REFLEX_VAR_CLOSING_TAG}"
2489
+ )
2490
+ _decode_var_pattern = re.compile(_decode_var_pattern_re, flags=re.DOTALL)
2491
+
2492
+ # Defined global immutable vars.
2493
+ _global_vars: Dict[int, Var] = {}
2494
+
2495
+
2496
+ def _extract_var_data(value: Iterable) -> list[VarData | None]:
2497
+ """Extract the var imports and hooks from an iterable containing a Var.
2498
+
2499
+ Args:
2500
+ value: The iterable to extract the VarData from
2501
+
2502
+ Returns:
2503
+ The extracted VarDatas.
2504
+ """
2505
+ from reflex.style import Style
2506
+ from reflex.vars import Var
2507
+
2508
+ var_datas = []
2509
+ with contextlib.suppress(TypeError):
2510
+ for sub in value:
2511
+ if isinstance(sub, Var):
2512
+ var_datas.append(sub._var_data)
2513
+ elif not isinstance(sub, str):
2514
+ # Recurse into dict values.
2515
+ if hasattr(sub, "values") and callable(sub.values):
2516
+ var_datas.extend(_extract_var_data(sub.values()))
2517
+ # Recurse into iterable values (or dict keys).
2518
+ var_datas.extend(_extract_var_data(sub))
2519
+
2520
+ # Style objects should already have _var_data.
2521
+ if isinstance(value, Style):
2522
+ var_datas.append(value._var_data)
2523
+ else:
2524
+ # Recurse when value is a dict itself.
2525
+ values = getattr(value, "values", None)
2526
+ if callable(values):
2527
+ var_datas.extend(_extract_var_data(values()))
2528
+ return var_datas
2529
+
2530
+
2531
+ # These names were changed in reflex 0.3.0
2532
+ REPLACED_NAMES = {
2533
+ "full_name": "_var_full_name",
2534
+ "name": "_js_expr",
2535
+ "state": "_var_data.state",
2536
+ "type_": "_var_type",
2537
+ "is_local": "_var_is_local",
2538
+ "is_string": "_var_is_string",
2539
+ "set_state": "_var_set_state",
2540
+ "deps": "_deps",
2541
+ }