reflex 0.7.14a5__py3-none-any.whl → 0.8.0__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 (236) hide show
  1. reflex/.templates/jinja/app/rxconfig.py.jinja2 +4 -1
  2. reflex/.templates/jinja/web/package.json.jinja2 +1 -1
  3. reflex/.templates/jinja/web/pages/_app.js.jinja2 +21 -11
  4. reflex/.templates/jinja/web/pages/_document.js.jinja2 +1 -1
  5. reflex/.templates/jinja/web/pages/base_page.js.jinja2 +0 -1
  6. reflex/.templates/jinja/web/pages/stateful_component.js.jinja2 +4 -0
  7. reflex/.templates/jinja/web/styles/styles.css.jinja2 +1 -0
  8. reflex/.templates/jinja/web/utils/context.js.jinja2 +25 -8
  9. reflex/.templates/web/app/entry.client.js +8 -0
  10. reflex/.templates/web/app/routes.js +10 -0
  11. reflex/.templates/web/components/reflex/radix_themes_color_mode_provider.js +12 -37
  12. reflex/.templates/web/postcss.config.js +1 -1
  13. reflex/.templates/web/react-router.config.js +6 -0
  14. reflex/.templates/web/styles/__reflex_style_reset.css +399 -0
  15. reflex/.templates/web/utils/client_side_routing.js +21 -19
  16. reflex/.templates/web/utils/react-theme.js +92 -0
  17. reflex/.templates/web/utils/state.js +251 -100
  18. reflex/.templates/web/vite-plugin-safari-cachebust.js +160 -0
  19. reflex/.templates/web/vite.config.js +39 -0
  20. reflex/__init__.py +1 -6
  21. reflex/__init__.pyi +327 -192
  22. reflex/app.py +103 -152
  23. reflex/base.py +1 -87
  24. reflex/compiler/compiler.py +70 -19
  25. reflex/compiler/templates.py +3 -3
  26. reflex/compiler/utils.py +91 -33
  27. reflex/components/__init__.py +0 -2
  28. reflex/components/__init__.pyi +34 -18
  29. reflex/components/base/__init__.py +1 -5
  30. reflex/components/base/__init__.pyi +30 -21
  31. reflex/components/base/app_wrap.pyi +7 -7
  32. reflex/components/base/body.pyi +7 -7
  33. reflex/components/base/document.py +18 -14
  34. reflex/components/base/document.pyi +88 -38
  35. reflex/components/base/error_boundary.pyi +7 -7
  36. reflex/components/base/fragment.pyi +7 -7
  37. reflex/components/base/link.pyi +12 -12
  38. reflex/components/base/meta.py +4 -15
  39. reflex/components/base/meta.pyi +31 -31
  40. reflex/components/base/script.py +60 -58
  41. reflex/components/base/script.pyi +248 -34
  42. reflex/components/base/strict_mode.pyi +7 -7
  43. reflex/components/component.py +146 -217
  44. reflex/components/core/__init__.py +1 -0
  45. reflex/components/core/__init__.pyi +77 -37
  46. reflex/components/core/auto_scroll.pyi +7 -7
  47. reflex/components/core/banner.pyi +33 -33
  48. reflex/components/core/client_side_routing.py +7 -6
  49. reflex/components/core/client_side_routing.pyi +8 -59
  50. reflex/components/core/clipboard.pyi +7 -7
  51. reflex/components/core/debounce.py +1 -0
  52. reflex/components/core/debounce.pyi +7 -7
  53. reflex/components/core/foreach.py +5 -4
  54. reflex/components/core/helmet.py +14 -0
  55. reflex/components/{next/base.pyi → core/helmet.pyi} +12 -10
  56. reflex/components/core/html.pyi +7 -7
  57. reflex/components/core/match.py +3 -3
  58. reflex/components/core/sticky.pyi +21 -20
  59. reflex/components/core/upload.py +4 -2
  60. reflex/components/core/upload.pyi +26 -25
  61. reflex/components/datadisplay/__init__.pyi +13 -7
  62. reflex/components/datadisplay/code.py +14 -79
  63. reflex/components/datadisplay/code.pyi +11 -13
  64. reflex/components/datadisplay/dataeditor.pyi +38 -15
  65. reflex/components/datadisplay/shiki_code_block.py +5 -3
  66. reflex/components/datadisplay/shiki_code_block.pyi +16 -15
  67. reflex/components/dynamic.py +5 -5
  68. reflex/components/el/__init__.pyi +506 -246
  69. reflex/components/el/element.pyi +7 -7
  70. reflex/components/el/elements/__init__.pyi +504 -245
  71. reflex/components/el/elements/base.pyi +7 -7
  72. reflex/components/el/elements/forms.pyi +146 -101
  73. reflex/components/el/elements/inline.pyi +142 -142
  74. reflex/components/el/elements/media.pyi +131 -130
  75. reflex/components/el/elements/metadata.pyi +32 -32
  76. reflex/components/el/elements/other.pyi +37 -37
  77. reflex/components/el/elements/scripts.pyi +17 -17
  78. reflex/components/el/elements/sectioning.pyi +77 -77
  79. reflex/components/el/elements/tables.pyi +52 -52
  80. reflex/components/el/elements/typography.pyi +77 -77
  81. reflex/components/field.py +175 -0
  82. reflex/components/gridjs/datatable.py +2 -2
  83. reflex/components/gridjs/datatable.pyi +14 -14
  84. reflex/components/lucide/icon.py +6 -2
  85. reflex/components/lucide/icon.pyi +19 -17
  86. reflex/components/markdown/markdown.py +5 -3
  87. reflex/components/markdown/markdown.pyi +7 -7
  88. reflex/components/moment/moment.py +1 -1
  89. reflex/components/moment/moment.pyi +7 -7
  90. reflex/components/plotly/plotly.py +12 -6
  91. reflex/components/plotly/plotly.pyi +50 -49
  92. reflex/components/props.py +376 -27
  93. reflex/components/radix/__init__.pyi +123 -65
  94. reflex/components/radix/primitives/__init__.pyi +6 -4
  95. reflex/components/radix/primitives/accordion.py +8 -1
  96. reflex/components/radix/primitives/accordion.pyi +37 -37
  97. reflex/components/radix/primitives/base.pyi +12 -12
  98. reflex/components/radix/primitives/drawer.pyi +56 -55
  99. reflex/components/radix/primitives/form.pyi +63 -53
  100. reflex/components/radix/primitives/progress.pyi +26 -25
  101. reflex/components/radix/primitives/slider.pyi +27 -27
  102. reflex/components/radix/themes/__init__.pyi +5 -6
  103. reflex/components/radix/themes/base.py +3 -3
  104. reflex/components/radix/themes/base.pyi +42 -42
  105. reflex/components/radix/themes/color_mode.py +5 -6
  106. reflex/components/radix/themes/color_mode.pyi +17 -17
  107. reflex/components/radix/themes/components/__init__.pyi +75 -38
  108. reflex/components/radix/themes/components/alert_dialog.pyi +37 -37
  109. reflex/components/radix/themes/components/aspect_ratio.pyi +7 -7
  110. reflex/components/radix/themes/components/avatar.pyi +7 -7
  111. reflex/components/radix/themes/components/badge.pyi +7 -7
  112. reflex/components/radix/themes/components/button.pyi +7 -7
  113. reflex/components/radix/themes/components/callout.pyi +26 -25
  114. reflex/components/radix/themes/components/card.pyi +7 -7
  115. reflex/components/radix/themes/components/checkbox.pyi +16 -15
  116. reflex/components/radix/themes/components/checkbox_cards.pyi +12 -12
  117. reflex/components/radix/themes/components/checkbox_group.pyi +12 -12
  118. reflex/components/radix/themes/components/context_menu.pyi +67 -67
  119. reflex/components/radix/themes/components/data_list.pyi +22 -22
  120. reflex/components/radix/themes/components/dialog.pyi +36 -35
  121. reflex/components/radix/themes/components/dropdown_menu.pyi +42 -42
  122. reflex/components/radix/themes/components/hover_card.pyi +21 -20
  123. reflex/components/radix/themes/components/icon_button.pyi +7 -7
  124. reflex/components/radix/themes/components/inset.pyi +7 -7
  125. reflex/components/radix/themes/components/popover.pyi +22 -22
  126. reflex/components/radix/themes/components/progress.pyi +7 -7
  127. reflex/components/radix/themes/components/radio.pyi +7 -7
  128. reflex/components/radix/themes/components/radio_cards.pyi +12 -12
  129. reflex/components/radix/themes/components/radio_group.pyi +21 -20
  130. reflex/components/radix/themes/components/scroll_area.pyi +7 -7
  131. reflex/components/radix/themes/components/segmented_control.pyi +12 -12
  132. reflex/components/radix/themes/components/select.pyi +46 -45
  133. reflex/components/radix/themes/components/separator.pyi +7 -7
  134. reflex/components/radix/themes/components/skeleton.pyi +7 -7
  135. reflex/components/radix/themes/components/slider.pyi +17 -9
  136. reflex/components/radix/themes/components/spinner.pyi +7 -7
  137. reflex/components/radix/themes/components/switch.pyi +7 -7
  138. reflex/components/radix/themes/components/table.pyi +37 -37
  139. reflex/components/radix/themes/components/tabs.pyi +26 -25
  140. reflex/components/radix/themes/components/text_area.pyi +15 -9
  141. reflex/components/radix/themes/components/text_field.pyi +32 -19
  142. reflex/components/radix/themes/components/tooltip.pyi +7 -7
  143. reflex/components/radix/themes/layout/__init__.pyi +27 -14
  144. reflex/components/radix/themes/layout/base.pyi +7 -7
  145. reflex/components/radix/themes/layout/box.pyi +7 -7
  146. reflex/components/radix/themes/layout/center.pyi +7 -7
  147. reflex/components/radix/themes/layout/container.pyi +7 -7
  148. reflex/components/radix/themes/layout/flex.pyi +7 -7
  149. reflex/components/radix/themes/layout/grid.pyi +7 -7
  150. reflex/components/radix/themes/layout/list.pyi +26 -25
  151. reflex/components/radix/themes/layout/section.pyi +7 -7
  152. reflex/components/radix/themes/layout/spacer.pyi +7 -7
  153. reflex/components/radix/themes/layout/stack.pyi +17 -17
  154. reflex/components/radix/themes/typography/__init__.pyi +7 -5
  155. reflex/components/radix/themes/typography/blockquote.pyi +7 -7
  156. reflex/components/radix/themes/typography/code.pyi +7 -7
  157. reflex/components/radix/themes/typography/heading.pyi +7 -7
  158. reflex/components/radix/themes/typography/link.py +46 -11
  159. reflex/components/radix/themes/typography/link.pyi +312 -9
  160. reflex/components/radix/themes/typography/text.pyi +36 -35
  161. reflex/components/react_player/audio.pyi +10 -8
  162. reflex/components/react_player/react_player.pyi +7 -7
  163. reflex/components/react_player/video.pyi +10 -8
  164. reflex/components/recharts/__init__.pyi +208 -100
  165. reflex/components/recharts/cartesian.py +10 -8
  166. reflex/components/recharts/cartesian.pyi +90 -94
  167. reflex/components/recharts/charts.py +4 -2
  168. reflex/components/recharts/charts.pyi +49 -49
  169. reflex/components/recharts/general.pyi +31 -31
  170. reflex/components/recharts/polar.py +8 -4
  171. reflex/components/recharts/polar.pyi +23 -23
  172. reflex/components/recharts/recharts.py +2 -2
  173. reflex/components/recharts/recharts.pyi +12 -12
  174. reflex/components/sonner/toast.py +3 -3
  175. reflex/components/sonner/toast.pyi +9 -9
  176. reflex/config.py +10 -113
  177. reflex/constants/__init__.py +2 -2
  178. reflex/constants/base.py +28 -11
  179. reflex/constants/compiler.py +12 -3
  180. reflex/constants/event.py +1 -0
  181. reflex/constants/installer.py +26 -20
  182. reflex/constants/route.py +27 -8
  183. reflex/constants/state.py +2 -0
  184. reflex/custom_components/custom_components.py +0 -14
  185. reflex/environment.py +77 -5
  186. reflex/event.py +178 -81
  187. reflex/experimental/__init__.py +0 -30
  188. reflex/istate/__init__.py +69 -0
  189. reflex/istate/manager.py +1 -0
  190. reflex/istate/proxy.py +5 -3
  191. reflex/page.py +0 -27
  192. reflex/plugins/__init__.py +3 -2
  193. reflex/plugins/base.py +5 -1
  194. reflex/plugins/shared_tailwind.py +215 -0
  195. reflex/plugins/sitemap.py +206 -0
  196. reflex/plugins/tailwind_v3.py +15 -108
  197. reflex/plugins/tailwind_v4.py +18 -110
  198. reflex/reflex.py +1 -0
  199. reflex/route.py +157 -75
  200. reflex/state.py +171 -155
  201. reflex/testing.py +86 -16
  202. reflex/utils/build.py +38 -82
  203. reflex/utils/exec.py +83 -175
  204. reflex/utils/export.py +2 -2
  205. reflex/utils/format.py +1 -5
  206. reflex/utils/imports.py +5 -16
  207. reflex/utils/misc.py +67 -0
  208. reflex/utils/prerequisites.py +66 -68
  209. reflex/utils/processes.py +24 -47
  210. reflex/utils/pyi_generator.py +44 -49
  211. reflex/utils/serializers.py +14 -1
  212. reflex/utils/telemetry.py +0 -15
  213. reflex/utils/types.py +197 -62
  214. reflex/vars/__init__.py +2 -0
  215. reflex/vars/base.py +367 -134
  216. {reflex-0.7.14a5.dist-info → reflex-0.8.0.dist-info}/METADATA +15 -8
  217. reflex-0.8.0.dist-info/RECORD +403 -0
  218. reflex/.templates/web/next.config.js +0 -7
  219. reflex/components/base/head.py +0 -20
  220. reflex/components/base/head.pyi +0 -116
  221. reflex/components/next/__init__.py +0 -10
  222. reflex/components/next/base.py +0 -7
  223. reflex/components/next/image.py +0 -117
  224. reflex/components/next/image.pyi +0 -94
  225. reflex/components/next/link.py +0 -20
  226. reflex/components/next/link.pyi +0 -67
  227. reflex/components/next/video.py +0 -38
  228. reflex/components/next/video.pyi +0 -68
  229. reflex/components/suneditor/__init__.py +0 -5
  230. reflex/components/suneditor/editor.py +0 -269
  231. reflex/components/suneditor/editor.pyi +0 -199
  232. reflex/experimental/layout.py +0 -254
  233. reflex-0.7.14a5.dist-info/RECORD +0 -407
  234. {reflex-0.7.14a5.dist-info → reflex-0.8.0.dist-info}/WHEEL +0 -0
  235. {reflex-0.7.14a5.dist-info → reflex-0.8.0.dist-info}/entry_points.txt +0 -0
  236. {reflex-0.7.14a5.dist-info → reflex-0.8.0.dist-info}/licenses/LICENSE +0 -0
reflex/state.py CHANGED
@@ -13,20 +13,10 @@ import pickle
13
13
  import sys
14
14
  import typing
15
15
  import warnings
16
- from abc import ABC
17
16
  from collections.abc import AsyncIterator, Callable, Sequence
18
17
  from hashlib import md5
19
18
  from types import FunctionType
20
- from typing import (
21
- TYPE_CHECKING,
22
- Any,
23
- BinaryIO,
24
- ClassVar,
25
- TypeVar,
26
- cast,
27
- get_args,
28
- get_type_hints,
29
- )
19
+ from typing import TYPE_CHECKING, Any, BinaryIO, ClassVar, TypeVar, cast, get_type_hints
30
20
 
31
21
  import pydantic.v1 as pydantic
32
22
  from pydantic import BaseModel as BaseModelV2
@@ -38,6 +28,7 @@ from typing_extensions import Self
38
28
  import reflex.istate.dynamic
39
29
  from reflex import constants, event
40
30
  from reflex.base import Base
31
+ from reflex.constants.state import FIELD_MARKER
41
32
  from reflex.environment import PerformanceMode, environment
42
33
  from reflex.event import (
43
34
  BACKGROUND_TASK_MARKER,
@@ -46,6 +37,7 @@ from reflex.event import (
46
37
  EventSpec,
47
38
  fix_events,
48
39
  )
40
+ from reflex.istate import HANDLED_PICKLE_ERRORS, debug_failed_pickles
49
41
  from reflex.istate.data import RouterData
50
42
  from reflex.istate.proxy import ImmutableMutableProxy as ImmutableMutableProxy
51
43
  from reflex.istate.proxy import MutableProxy, StateProxy
@@ -68,21 +60,15 @@ from reflex.utils.exceptions import (
68
60
  )
69
61
  from reflex.utils.exceptions import ImmutableStateError as ImmutableStateError
70
62
  from reflex.utils.exec import is_testing_env
71
- from reflex.utils.types import (
72
- _isinstance,
73
- get_origin,
74
- is_union,
75
- true_type_for_pydantic_field,
76
- value_inside_optional,
77
- )
78
- from reflex.vars import VarData
63
+ from reflex.utils.types import _isinstance, is_union, value_inside_optional
64
+ from reflex.vars import Field, VarData, field
79
65
  from reflex.vars.base import (
80
66
  ComputedVar,
81
67
  DynamicRouteVar,
68
+ EvenMoreBasicBaseState,
82
69
  Var,
83
70
  computed_var,
84
71
  dispatch,
85
- get_unique_variable_name,
86
72
  is_computed_var,
87
73
  )
88
74
 
@@ -100,14 +86,6 @@ if environment.REFLEX_PERF_MODE.get() != PerformanceMode.OFF:
100
86
  # Only warn about each state class size once.
101
87
  _WARNED_ABOUT_STATE_SIZE: set[str] = set()
102
88
 
103
- # Errors caught during pickling of state
104
- HANDLED_PICKLE_ERRORS = (
105
- pickle.PicklingError,
106
- AttributeError,
107
- IndexError,
108
- TypeError,
109
- ValueError,
110
- )
111
89
 
112
90
  # For BaseState.get_var_value
113
91
  VAR_TYPE = TypeVar("VAR_TYPE")
@@ -205,6 +183,21 @@ class EventHandlerSetVar(EventHandler):
205
183
  )
206
184
  object.__setattr__(self, "state_cls", state_cls)
207
185
 
186
+ def __hash__(self):
187
+ """Get the hash of the event handler.
188
+
189
+ Returns:
190
+ The hash of the event handler.
191
+ """
192
+ return hash(
193
+ (
194
+ tuple(self.event_actions.items()),
195
+ self.fn,
196
+ self.state_full_name,
197
+ self.state_cls,
198
+ )
199
+ )
200
+
208
201
  def setvar(self, var_name: str, value: Any):
209
202
  """Set the state variable to the value of the event.
210
203
 
@@ -255,38 +248,25 @@ if TYPE_CHECKING:
255
248
  from pydantic.v1.fields import ModelField
256
249
 
257
250
 
258
- def _unwrap_field_type(type_: types.GenericType) -> type:
259
- """Unwrap rx.Field type annotations.
260
-
261
- Args:
262
- type_: The type to unwrap.
263
-
264
- Returns:
265
- The unwrapped type.
266
- """
267
- from reflex.vars import Field
268
-
269
- if get_origin(type_) is Field:
270
- return get_args(type_)[0]
271
- return type_
272
-
273
-
274
- def get_var_for_field(cls: type[BaseState], f: ModelField):
275
- """Get a Var instance for a Pydantic field.
251
+ def get_var_for_field(cls: type[BaseState], name: str, f: Field) -> Var:
252
+ """Get a Var instance for a state field.
276
253
 
277
254
  Args:
278
255
  cls: The state class.
279
- f: The Pydantic field.
256
+ name: The name of the field.
257
+ f: The Field instance.
280
258
 
281
259
  Returns:
282
260
  The Var instance.
283
261
  """
284
- field_name = format.format_state_name(cls.get_full_name()) + "." + f.name
262
+ field_name = (
263
+ format.format_state_name(cls.get_full_name()) + "." + name + FIELD_MARKER
264
+ )
285
265
 
286
266
  return dispatch(
287
267
  field_name=field_name,
288
- var_data=VarData.from_state(cls, f.name),
289
- result_var_type=_unwrap_field_type(true_type_for_pydantic_field(f)),
268
+ var_data=VarData.from_state(cls, name),
269
+ result_var_type=f.outer_type_,
290
270
  )
291
271
 
292
272
 
@@ -312,7 +292,7 @@ async def _resolve_delta(delta: Delta) -> Delta:
312
292
  all_base_state_classes: dict[str, None] = {}
313
293
 
314
294
 
315
- class BaseState(Base, ABC, extra=pydantic.Extra.allow):
295
+ class BaseState(EvenMoreBasicBaseState):
316
296
  """The state of the app."""
317
297
 
318
298
  # A map from the var name to the var.
@@ -352,31 +332,34 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
352
332
  _potentially_dirty_states: ClassVar[set[str]] = set()
353
333
 
354
334
  # The parent state.
355
- parent_state: BaseState | None = None
335
+ parent_state: BaseState | None = field(default=None, is_var=False)
356
336
 
357
337
  # The substates of the state.
358
- substates: builtins.dict[str, BaseState] = {}
338
+ substates: builtins.dict[str, BaseState] = field(
339
+ default_factory=builtins.dict, is_var=False
340
+ )
359
341
 
360
342
  # The set of dirty vars.
361
- dirty_vars: set[str] = set()
343
+ dirty_vars: set[str] = field(default_factory=set, is_var=False)
362
344
 
363
345
  # The set of dirty substates.
364
- dirty_substates: set[str] = set()
346
+ dirty_substates: set[str] = field(default_factory=set, is_var=False)
365
347
 
366
348
  # The routing path that triggered the state
367
- router_data: builtins.dict[str, Any] = {}
349
+ router_data: builtins.dict[str, Any] = field(
350
+ default_factory=builtins.dict, is_var=False
351
+ )
368
352
 
369
353
  # Per-instance copy of backend base variable values
370
- _backend_vars: builtins.dict[str, Any] = {}
354
+ _backend_vars: builtins.dict[str, Any] = field(
355
+ default_factory=builtins.dict, is_var=False
356
+ )
371
357
 
372
358
  # The router data for the current page
373
- router: RouterData = RouterData()
359
+ router: Field[RouterData] = field(default_factory=RouterData)
374
360
 
375
361
  # Whether the state has ever been touched since instantiation.
376
- _was_touched: bool = False
377
-
378
- # Whether this state class is a mixin and should not be instantiated.
379
- _mixin: ClassVar[bool] = False
362
+ _was_touched: bool = field(default=False, is_var=False)
380
363
 
381
364
  # A special event handler for setting base vars.
382
365
  setvar: ClassVar[EventHandler]
@@ -409,13 +392,11 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
409
392
  "See https://reflex.dev/docs/state/ for further information."
410
393
  )
411
394
  raise ReflexRuntimeError(msg)
412
- if type(self)._mixin:
395
+ if self._mixin:
413
396
  msg = f"{type(self).__name__} is a state mixin and cannot be instantiated directly."
414
397
  raise ReflexRuntimeError(msg)
415
398
  kwargs["parent_state"] = parent_state
416
- super().__init__()
417
- for name, value in kwargs.items():
418
- setattr(self, name, value)
399
+ super().__init__(**kwargs)
419
400
 
420
401
  # Setup the substates (for memory state manager only).
421
402
  if init_substates:
@@ -437,14 +418,14 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
437
418
  return f"{type(self).__name__}({self.dict()})"
438
419
 
439
420
  @classmethod
440
- def _get_computed_vars(cls) -> list[ComputedVar]:
421
+ def _get_computed_vars(cls) -> list[tuple[str, ComputedVar]]:
441
422
  """Helper function to get all computed vars of a instance.
442
423
 
443
424
  Returns:
444
425
  A list of computed vars.
445
426
  """
446
427
  return [
447
- v
428
+ (name, v)
448
429
  for mixin in [*cls._mixins(), cls]
449
430
  for name, v in mixin.__dict__.items()
450
431
  if is_computed_var(v) and name not in cls.inherited_vars
@@ -481,8 +462,7 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
481
462
 
482
463
  super().__init_subclass__(**kwargs)
483
464
 
484
- cls._mixin = mixin
485
- if mixin:
465
+ if cls._mixin:
486
466
  return
487
467
 
488
468
  # Handle locally-defined states for pickling.
@@ -548,13 +528,13 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
548
528
 
549
529
  # Set the base and computed vars.
550
530
  cls.base_vars = {
551
- f.name: get_var_for_field(cls, f)
552
- for f in cls.get_fields().values()
553
- if f.name not in cls.get_skip_vars()
531
+ name: get_var_for_field(cls, name, f)
532
+ for name, f in cls.get_fields().items()
533
+ if name not in cls.get_skip_vars() and f.is_var and not name.startswith("_")
554
534
  }
555
535
  cls.computed_vars = {
556
- v._js_expr: v._replace(merge_var_data=VarData.from_state(cls))
557
- for v in computed_vars
536
+ name: v._replace(merge_var_data=VarData.from_state(cls))
537
+ for name, v in computed_vars
558
538
  }
559
539
  cls.vars = {
560
540
  **cls.inherited_vars,
@@ -564,8 +544,8 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
564
544
  cls.event_handlers = {}
565
545
 
566
546
  # Setup the base vars at the class level.
567
- for prop in cls.base_vars.values():
568
- cls._init_var(prop)
547
+ for name, prop in cls.base_vars.items():
548
+ cls._init_var(name, prop)
569
549
 
570
550
  # Set up the event handlers.
571
551
  events = {
@@ -583,8 +563,8 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
583
563
  newcv = value._replace(fget=fget, _var_data=VarData.from_state(cls))
584
564
  # cleanup refs to mixin cls in var_data
585
565
  setattr(cls, name, newcv)
586
- cls.computed_vars[newcv._js_expr] = newcv
587
- cls.vars[newcv._js_expr] = newcv
566
+ cls.computed_vars[name] = newcv
567
+ cls.vars[name] = newcv
588
568
  continue
589
569
  if types.is_backend_base_variable(name, mixin_cls):
590
570
  cls.backend_vars[name] = copy.deepcopy(value)
@@ -687,9 +667,16 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
687
667
 
688
668
  of_type = of_type or Component
689
669
 
690
- unique_var_name = get_unique_variable_name()
670
+ unique_var_name = (
671
+ ("dynamic_" + f.__module__ + "_" + f.__qualname__)
672
+ .replace("<", "")
673
+ .replace(">", "")
674
+ .replace(".", "_")
675
+ )
676
+
677
+ while unique_var_name in cls.vars:
678
+ unique_var_name += "_"
691
679
 
692
- @computed_var(_js_expr=unique_var_name, return_type=of_type)
693
680
  def computed_var_func(state: Self):
694
681
  result = f(state)
695
682
 
@@ -701,10 +688,16 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
701
688
 
702
689
  return result
703
690
 
704
- setattr(cls, unique_var_name, computed_var_func)
705
- cls.computed_vars[unique_var_name] = computed_var_func
706
- cls.vars[unique_var_name] = computed_var_func
707
- cls._update_substate_inherited_vars({unique_var_name: computed_var_func})
691
+ computed_var_func.__name__ = unique_var_name
692
+
693
+ computed_var_func_arg = computed_var(return_type=of_type, cache=False)(
694
+ computed_var_func
695
+ )
696
+
697
+ setattr(cls, unique_var_name, computed_var_func_arg)
698
+ cls.computed_vars[unique_var_name] = computed_var_func_arg
699
+ cls.vars[unique_var_name] = computed_var_func_arg
700
+ cls._update_substate_inherited_vars({unique_var_name: computed_var_func_arg})
708
701
  cls._always_dirty_computed_vars.add(unique_var_name)
709
702
 
710
703
  return getattr(cls, unique_var_name)
@@ -842,8 +835,8 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
842
835
  Raises:
843
836
  ComputedVarShadowsBaseVarsError: When a computed var shadows a base var.
844
837
  """
845
- for computed_var_ in cls._get_computed_vars():
846
- if computed_var_._js_expr in cls.__annotations__:
838
+ for name, computed_var_ in cls._get_computed_vars():
839
+ if name in cls.__annotations__:
847
840
  msg = f"The computed var name `{computed_var_._js_expr}` shadows a base var in {cls.__module__}.{cls.__name__}; use a different name instead"
848
841
  raise ComputedVarShadowsBaseVarsError(msg)
849
842
 
@@ -898,7 +891,7 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
898
891
  if issubclass(base, BaseState) and base is not BaseState and not base._mixin
899
892
  ]
900
893
  if len(parent_states) >= 2:
901
- msg = f"Only one parent state is allowed {parent_states}."
894
+ msg = f"Only one parent state of is allowed. Found {parent_states} parents of {cls}."
902
895
  raise ValueError(msg)
903
896
  # The first non-mixin state in the mro is our parent.
904
897
  for base in cls.mro()[1:]:
@@ -1016,10 +1009,11 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
1016
1009
  )
1017
1010
 
1018
1011
  @classmethod
1019
- def _init_var(cls, prop: Var):
1012
+ def _init_var(cls, name: str, prop: Var):
1020
1013
  """Initialize a variable.
1021
1014
 
1022
1015
  Args:
1016
+ name: The name of the variable
1023
1017
  prop: The variable to initialize
1024
1018
 
1025
1019
  Raises:
@@ -1036,10 +1030,10 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
1036
1030
  f'Found var "{prop._js_expr}" with type {prop._var_type}.'
1037
1031
  )
1038
1032
  raise VarTypeError(msg)
1039
- cls._set_var(prop)
1033
+ cls._set_var(name, prop)
1040
1034
  if cls.is_user_defined() and get_config().state_auto_setters:
1041
- cls._create_setter(prop)
1042
- cls._set_default_value(prop)
1035
+ cls._create_setter(name, prop)
1036
+ cls._set_default_value(name, prop)
1043
1037
 
1044
1038
  @classmethod
1045
1039
  def add_var(cls, name: str, type_: Any, default_value: Any = None):
@@ -1062,15 +1056,18 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
1062
1056
 
1063
1057
  # create the variable based on name and type
1064
1058
  var = Var(
1065
- _js_expr=format.format_state_name(cls.get_full_name()) + "." + name,
1059
+ _js_expr=format.format_state_name(cls.get_full_name())
1060
+ + "."
1061
+ + name
1062
+ + FIELD_MARKER,
1066
1063
  _var_type=type_,
1067
1064
  _var_data=VarData.from_state(cls, name),
1068
1065
  ).guess_type()
1069
1066
 
1070
1067
  # add the pydantic field dynamically (must be done before _init_var)
1071
- cls.add_field(var, default_value)
1068
+ cls.add_field(name, var, default_value)
1072
1069
 
1073
- cls._init_var(var)
1070
+ cls._init_var(name, var)
1074
1071
 
1075
1072
  # update the internal dicts so the new variable is correctly handled
1076
1073
  cls.base_vars.update({name: var})
@@ -1084,13 +1081,14 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
1084
1081
  cls._init_var_dependency_dicts()
1085
1082
 
1086
1083
  @classmethod
1087
- def _set_var(cls, prop: Var):
1084
+ def _set_var(cls, name: str, prop: Var):
1088
1085
  """Set the var as a class member.
1089
1086
 
1090
1087
  Args:
1088
+ name: The name of the var.
1091
1089
  prop: The var instance to set.
1092
1090
  """
1093
- setattr(cls, prop._var_field_name, prop)
1091
+ setattr(cls, name, prop)
1094
1092
 
1095
1093
  @classmethod
1096
1094
  def _create_event_handler(cls, fn: Any):
@@ -1110,38 +1108,31 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
1110
1108
  cls.setvar = cls.event_handlers["setvar"] = EventHandlerSetVar(state_cls=cls)
1111
1109
 
1112
1110
  @classmethod
1113
- def _create_setter(cls, prop: Var):
1111
+ def _create_setter(cls, name: str, prop: Var):
1114
1112
  """Create a setter for the var.
1115
1113
 
1116
1114
  Args:
1115
+ name: The name of the var.
1117
1116
  prop: The var to create a setter for.
1118
1117
  """
1119
- setter_name = prop._get_setter_name(include_state=False)
1118
+ setter_name = Var._get_setter_name_for_name(name)
1120
1119
  if setter_name not in cls.__dict__:
1121
- event_handler = cls._create_event_handler(prop._get_setter())
1120
+ event_handler = cls._create_event_handler(prop._get_setter(name))
1122
1121
  cls.event_handlers[setter_name] = event_handler
1123
1122
  setattr(cls, setter_name, event_handler)
1124
1123
 
1125
1124
  @classmethod
1126
- def _set_default_value(cls, prop: Var):
1125
+ def _set_default_value(cls, name: str, prop: Var):
1127
1126
  """Set the default value for the var.
1128
1127
 
1129
1128
  Args:
1129
+ name: The name of the var.
1130
1130
  prop: The var to set the default value for.
1131
1131
  """
1132
1132
  # Get the pydantic field for the var.
1133
- field = cls.get_fields()[prop._var_field_name]
1134
- if field.required:
1135
- default_value = prop._get_default_value()
1136
- if default_value is not None:
1137
- field.required = False
1138
- field.default = default_value
1139
- if (
1140
- not field.required
1141
- and field.default is None
1142
- and field.default_factory is None
1143
- and not types.is_optional(prop._var_type)
1144
- ):
1133
+ field = cls.get_fields()[name]
1134
+
1135
+ if field.default is None and not types.is_optional(prop._var_type):
1145
1136
  # Ensure frontend uses null coalescing when accessing.
1146
1137
  object.__setattr__(prop, "_var_type", prop._var_type | None)
1147
1138
 
@@ -1160,7 +1151,7 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
1160
1151
  return getattr(cls, name)
1161
1152
  except AttributeError:
1162
1153
  try:
1163
- return Var("", _var_type=annotation_value)._get_default_value()
1154
+ return types.get_default_value_for_type(annotation_value)
1164
1155
  except TypeError:
1165
1156
  pass
1166
1157
  return None
@@ -1215,12 +1206,16 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
1215
1206
  def inner_func(self: BaseState) -> str:
1216
1207
  return self.router.page.params.get(param, "")
1217
1208
 
1209
+ inner_func.__name__ = param
1210
+
1218
1211
  return inner_func
1219
1212
 
1220
1213
  def arglist_factory(param: str):
1221
1214
  def inner_func(self: BaseState) -> list[str]:
1222
1215
  return self.router.page.params.get(param, [])
1223
1216
 
1217
+ inner_func.__name__ = param
1218
+
1224
1219
  return inner_func
1225
1220
 
1226
1221
  dynamic_vars = {}
@@ -1235,8 +1230,7 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
1235
1230
  fget=func,
1236
1231
  auto_deps=False,
1237
1232
  deps=["router"],
1238
- _js_expr=param,
1239
- _var_data=VarData.from_state(cls),
1233
+ _var_data=VarData.from_state(cls, param),
1240
1234
  )
1241
1235
  setattr(cls, param, dynamic_vars[param])
1242
1236
 
@@ -1276,10 +1270,6 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
1276
1270
  Returns:
1277
1271
  The value of the var.
1278
1272
  """
1279
- # If the state hasn't been initialized yet, return the default value.
1280
- if not super().__getattribute__("__dict__"):
1281
- return super().__getattribute__(name)
1282
-
1283
1273
  # Fast path for dunder
1284
1274
  if name.startswith("__"):
1285
1275
  return super().__getattribute__(name)
@@ -1306,7 +1296,7 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
1306
1296
  fn.__qualname__ = handler.fn.__qualname__
1307
1297
  return fn
1308
1298
 
1309
- backend_vars = super().__getattribute__("_backend_vars")
1299
+ backend_vars = super().__getattribute__("_backend_vars") or {}
1310
1300
  if name in backend_vars:
1311
1301
  value = backend_vars[name]
1312
1302
  else:
@@ -1370,9 +1360,8 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
1370
1360
 
1371
1361
  fields = self.get_fields()
1372
1362
 
1373
- if name in fields:
1374
- field = fields[name]
1375
- field_type = _unwrap_field_type(true_type_for_pydantic_field(field))
1363
+ if (field := fields.get(name)) is not None and field.is_var:
1364
+ field_type = field.outer_type_
1376
1365
  if not _isinstance(value, field_type, nested=1, treat_var_as_type=False):
1377
1366
  console.error(
1378
1367
  f"Expected field '{type(self).__name__}.{name}' to receive type '{escape(str(field_type))}',"
@@ -1380,7 +1369,7 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
1380
1369
  )
1381
1370
 
1382
1371
  # Set the attribute.
1383
- super().__setattr__(name, value)
1372
+ object.__setattr__(self, name, value)
1384
1373
 
1385
1374
  # Add the var to the dirty list.
1386
1375
  if name in self.base_vars:
@@ -1969,7 +1958,7 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
1969
1958
  )
1970
1959
 
1971
1960
  subdelta: dict[str, Any] = {
1972
- prop: self.get_value(prop)
1961
+ prop + FIELD_MARKER: self.get_value(prop)
1973
1962
  for prop in delta_vars
1974
1963
  if not types.is_backend_base_variable(prop, type(self))
1975
1964
  }
@@ -2057,11 +2046,28 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
2057
2046
 
2058
2047
  Returns:
2059
2048
  The value of the field.
2049
+
2050
+ Raises:
2051
+ TypeError: If the key is not a string or MutableProxy.
2060
2052
  """
2061
- value = super().get_value(key)
2062
- if isinstance(value, MutableProxy):
2063
- return value.__wrapped__
2064
- return value
2053
+ if isinstance(key, MutableProxy):
2054
+ # Legacy behavior from v0.7.14: handle non-string keys with deprecation warning
2055
+ from reflex.utils import console
2056
+
2057
+ console.deprecate(
2058
+ feature_name="Non-string keys in get_value",
2059
+ reason="Passing non-string keys to get_value is deprecated and will no longer be supported",
2060
+ deprecation_version="0.8.0",
2061
+ removal_version="0.9.0",
2062
+ )
2063
+
2064
+ return key.__wrapped__
2065
+
2066
+ if isinstance(key, str):
2067
+ return getattr(self, key)
2068
+
2069
+ msg = f"Invalid key type: {type(key)}. Expected str."
2070
+ raise TypeError(msg)
2065
2071
 
2066
2072
  def dict(
2067
2073
  self, include_computed: bool = True, initial: bool = False, **kwargs
@@ -2104,7 +2110,9 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
2104
2110
  computed_vars = {}
2105
2111
  variables = {**base_vars, **computed_vars}
2106
2112
  d = {
2107
- self.get_full_name(): {k: variables[k] for k in sorted(variables)},
2113
+ self.get_full_name(): {
2114
+ k + FIELD_MARKER: variables[k] for k in sorted(variables)
2115
+ },
2108
2116
  }
2109
2117
  for substate_d in [
2110
2118
  v.dict(include_computed=include_computed, initial=initial, **kwargs)
@@ -2147,19 +2155,19 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
2147
2155
  Returns:
2148
2156
  The state dict for serialization.
2149
2157
  """
2150
- state = super().__getstate__()
2151
- state["__dict__"] = state["__dict__"].copy()
2152
- if state["__dict__"].get("parent_state") is not None:
2158
+ state = self.__dict__
2159
+ state = state.copy()
2160
+ if state.get("parent_state") is not None:
2153
2161
  # Do not serialize router data in substates (only the root state).
2154
- state["__dict__"].pop("router", None)
2155
- state["__dict__"].pop("router_data", None)
2162
+ state.pop("router", None)
2163
+ state.pop("router_data", None)
2156
2164
  # Never serialize parent_state or substates.
2157
- state["__dict__"].pop("parent_state", None)
2158
- state["__dict__"].pop("substates", None)
2159
- state["__dict__"].pop("_was_touched", None)
2165
+ state.pop("parent_state", None)
2166
+ state.pop("substates", None)
2167
+ state.pop("_was_touched", None)
2160
2168
  # Remove all inherited vars.
2161
2169
  for inherited_var_name in self.inherited_vars:
2162
- state["__dict__"].pop(inherited_var_name, None)
2170
+ state.pop(inherited_var_name, None)
2163
2171
  return state
2164
2172
 
2165
2173
  def __setstate__(self, state: dict[str, Any]):
@@ -2170,9 +2178,10 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
2170
2178
  Args:
2171
2179
  state: The state dict for deserialization.
2172
2180
  """
2173
- state["__dict__"]["parent_state"] = None
2174
- state["__dict__"]["substates"] = {}
2175
- super().__setstate__(state)
2181
+ state["parent_state"] = None
2182
+ state["substates"] = {}
2183
+ for key, value in state.items():
2184
+ object.__setattr__(self, key, value)
2176
2185
 
2177
2186
  def _check_state_size(
2178
2187
  self,
@@ -2213,17 +2222,11 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
2213
2222
 
2214
2223
  def _field_tuple(
2215
2224
  field_name: str,
2216
- ) -> tuple[str, str, Any, bool | None, Any]:
2225
+ ) -> tuple[str, Any, Any]:
2217
2226
  model_field = cls.__fields__[field_name]
2218
2227
  return (
2219
2228
  field_name,
2220
- model_field.name,
2221
2229
  _serialize_type(model_field.type_),
2222
- (
2223
- model_field.required
2224
- if isinstance(model_field.required, bool)
2225
- else None
2226
- ),
2227
2230
  (model_field.default if is_serializable(model_field.default) else None),
2228
2231
  )
2229
2232
 
@@ -2241,11 +2244,16 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
2241
2244
 
2242
2245
  Raises:
2243
2246
  StateSerializationError: If the state cannot be serialized.
2247
+
2248
+ # noqa: DAR401: e
2249
+ # noqa: DAR402: StateSerializationError
2244
2250
  """
2245
2251
  payload = b""
2246
2252
  error = ""
2253
+ self_schema = self._to_schema()
2254
+ pickle_function = pickle.dumps
2247
2255
  try:
2248
- payload = pickle.dumps((self._to_schema(), self))
2256
+ payload = pickle.dumps((self_schema, self))
2249
2257
  except HANDLED_PICKLE_ERRORS as og_pickle_error:
2250
2258
  error = (
2251
2259
  f"Failed to serialize state {self.get_full_name()} due to unpicklable object. "
@@ -2254,7 +2262,8 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
2254
2262
  try:
2255
2263
  import dill
2256
2264
 
2257
- payload = dill.dumps((self._to_schema(), self))
2265
+ pickle_function = dill.dumps
2266
+ payload = dill.dumps((self_schema, self))
2258
2267
  except ImportError:
2259
2268
  error += (
2260
2269
  f"Pickle error: {og_pickle_error}. "
@@ -2262,13 +2271,19 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
2262
2271
  )
2263
2272
  except HANDLED_PICKLE_ERRORS as ex:
2264
2273
  error += f"Dill was also unable to pickle the state: {ex}"
2265
- console.warn(error)
2266
2274
 
2267
2275
  if environment.REFLEX_PERF_MODE.get() != PerformanceMode.OFF:
2268
2276
  self._check_state_size(len(payload))
2269
2277
 
2270
2278
  if not payload:
2271
- raise StateSerializationError(error)
2279
+ e = StateSerializationError(error)
2280
+ if sys.version_info >= (3, 11):
2281
+ try:
2282
+ debug_failed_pickles(self, pickle_function)
2283
+ except HANDLED_PICKLE_ERRORS as ex:
2284
+ for note in ex.__notes__:
2285
+ e.add_note(note)
2286
+ raise e
2272
2287
 
2273
2288
  return payload
2274
2289
 
@@ -2430,6 +2445,7 @@ class UpdateVarsInternalState(State):
2430
2445
  """
2431
2446
  for var, value in vars.items():
2432
2447
  state_name, _, var_name = var.rpartition(".")
2448
+ var_name = var_name.removesuffix(FIELD_MARKER)
2433
2449
  var_state_cls = State.get_class_substate(state_name)
2434
2450
  if var_state_cls._is_client_storage(var_name):
2435
2451
  var_state = await self.get_state(var_state_cls)
@@ -2518,7 +2534,7 @@ class ComponentState(State, mixin=True):
2518
2534
  Raises:
2519
2535
  ReflexRuntimeError: If the ComponentState is initialized directly.
2520
2536
  """
2521
- if type(self)._mixin:
2537
+ if self._mixin:
2522
2538
  raise ReflexRuntimeError(
2523
2539
  f"{ComponentState.__name__} {type(self).__name__} is not meant to be initialized directly. "
2524
2540
  + "Use the `create` method to create a new instance and access the state via the `State` attribute."