reflex 0.7.14a6__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.
- reflex/.templates/jinja/app/rxconfig.py.jinja2 +4 -1
- reflex/.templates/jinja/web/package.json.jinja2 +1 -1
- reflex/.templates/jinja/web/pages/_app.js.jinja2 +21 -11
- reflex/.templates/jinja/web/pages/_document.js.jinja2 +1 -1
- reflex/.templates/jinja/web/pages/base_page.js.jinja2 +0 -1
- reflex/.templates/jinja/web/pages/stateful_component.js.jinja2 +4 -0
- reflex/.templates/jinja/web/styles/styles.css.jinja2 +1 -0
- reflex/.templates/jinja/web/utils/context.js.jinja2 +25 -8
- reflex/.templates/web/app/entry.client.js +8 -0
- reflex/.templates/web/app/routes.js +10 -0
- reflex/.templates/web/components/reflex/radix_themes_color_mode_provider.js +12 -37
- reflex/.templates/web/postcss.config.js +1 -1
- reflex/.templates/web/react-router.config.js +6 -0
- reflex/.templates/web/styles/__reflex_style_reset.css +399 -0
- reflex/.templates/web/utils/client_side_routing.js +21 -19
- reflex/.templates/web/utils/react-theme.js +92 -0
- reflex/.templates/web/utils/state.js +251 -100
- reflex/.templates/web/vite-plugin-safari-cachebust.js +160 -0
- reflex/.templates/web/vite.config.js +39 -0
- reflex/__init__.py +1 -6
- reflex/__init__.pyi +327 -192
- reflex/app.py +86 -135
- reflex/base.py +1 -87
- reflex/compiler/compiler.py +70 -19
- reflex/compiler/templates.py +3 -3
- reflex/compiler/utils.py +91 -33
- reflex/components/__init__.py +0 -2
- reflex/components/__init__.pyi +34 -18
- reflex/components/base/__init__.py +1 -5
- reflex/components/base/__init__.pyi +30 -21
- reflex/components/base/app_wrap.pyi +7 -7
- reflex/components/base/body.pyi +7 -7
- reflex/components/base/document.py +18 -14
- reflex/components/base/document.pyi +88 -38
- reflex/components/base/error_boundary.pyi +7 -7
- reflex/components/base/fragment.pyi +7 -7
- reflex/components/base/link.pyi +12 -12
- reflex/components/base/meta.py +4 -15
- reflex/components/base/meta.pyi +31 -31
- reflex/components/base/script.py +60 -58
- reflex/components/base/script.pyi +248 -34
- reflex/components/base/strict_mode.pyi +7 -7
- reflex/components/component.py +146 -217
- reflex/components/core/__init__.py +1 -0
- reflex/components/core/__init__.pyi +77 -37
- reflex/components/core/auto_scroll.pyi +7 -7
- reflex/components/core/banner.pyi +33 -33
- reflex/components/core/client_side_routing.py +7 -6
- reflex/components/core/client_side_routing.pyi +8 -59
- reflex/components/core/clipboard.pyi +7 -7
- reflex/components/core/debounce.py +1 -0
- reflex/components/core/debounce.pyi +7 -7
- reflex/components/core/foreach.py +5 -4
- reflex/components/core/helmet.py +14 -0
- reflex/components/{next/base.pyi → core/helmet.pyi} +12 -10
- reflex/components/core/html.pyi +7 -7
- reflex/components/core/match.py +3 -3
- reflex/components/core/sticky.pyi +21 -20
- reflex/components/core/upload.py +4 -2
- reflex/components/core/upload.pyi +26 -25
- reflex/components/datadisplay/__init__.pyi +13 -7
- reflex/components/datadisplay/code.py +14 -79
- reflex/components/datadisplay/code.pyi +11 -13
- reflex/components/datadisplay/dataeditor.pyi +38 -15
- reflex/components/datadisplay/shiki_code_block.py +5 -3
- reflex/components/datadisplay/shiki_code_block.pyi +16 -15
- reflex/components/dynamic.py +5 -5
- reflex/components/el/__init__.pyi +506 -246
- reflex/components/el/element.pyi +7 -7
- reflex/components/el/elements/__init__.pyi +504 -245
- reflex/components/el/elements/base.pyi +7 -7
- reflex/components/el/elements/forms.pyi +146 -101
- reflex/components/el/elements/inline.pyi +142 -142
- reflex/components/el/elements/media.pyi +131 -130
- reflex/components/el/elements/metadata.pyi +32 -32
- reflex/components/el/elements/other.pyi +37 -37
- reflex/components/el/elements/scripts.pyi +17 -17
- reflex/components/el/elements/sectioning.pyi +77 -77
- reflex/components/el/elements/tables.pyi +52 -52
- reflex/components/el/elements/typography.pyi +77 -77
- reflex/components/field.py +175 -0
- reflex/components/gridjs/datatable.py +2 -2
- reflex/components/gridjs/datatable.pyi +14 -14
- reflex/components/lucide/icon.py +6 -2
- reflex/components/lucide/icon.pyi +19 -17
- reflex/components/markdown/markdown.py +5 -3
- reflex/components/markdown/markdown.pyi +7 -7
- reflex/components/moment/moment.py +1 -1
- reflex/components/moment/moment.pyi +7 -7
- reflex/components/plotly/plotly.py +12 -6
- reflex/components/plotly/plotly.pyi +50 -49
- reflex/components/props.py +376 -27
- reflex/components/radix/__init__.pyi +123 -65
- reflex/components/radix/primitives/__init__.pyi +6 -4
- reflex/components/radix/primitives/accordion.py +8 -1
- reflex/components/radix/primitives/accordion.pyi +37 -37
- reflex/components/radix/primitives/base.pyi +12 -12
- reflex/components/radix/primitives/drawer.pyi +56 -55
- reflex/components/radix/primitives/form.pyi +63 -53
- reflex/components/radix/primitives/progress.pyi +26 -25
- reflex/components/radix/primitives/slider.pyi +27 -27
- reflex/components/radix/themes/__init__.pyi +5 -6
- reflex/components/radix/themes/base.py +3 -3
- reflex/components/radix/themes/base.pyi +42 -42
- reflex/components/radix/themes/color_mode.py +5 -6
- reflex/components/radix/themes/color_mode.pyi +17 -17
- reflex/components/radix/themes/components/__init__.pyi +75 -38
- reflex/components/radix/themes/components/alert_dialog.pyi +37 -37
- reflex/components/radix/themes/components/aspect_ratio.pyi +7 -7
- reflex/components/radix/themes/components/avatar.pyi +7 -7
- reflex/components/radix/themes/components/badge.pyi +7 -7
- reflex/components/radix/themes/components/button.pyi +7 -7
- reflex/components/radix/themes/components/callout.pyi +26 -25
- reflex/components/radix/themes/components/card.pyi +7 -7
- reflex/components/radix/themes/components/checkbox.pyi +16 -15
- reflex/components/radix/themes/components/checkbox_cards.pyi +12 -12
- reflex/components/radix/themes/components/checkbox_group.pyi +12 -12
- reflex/components/radix/themes/components/context_menu.pyi +67 -67
- reflex/components/radix/themes/components/data_list.pyi +22 -22
- reflex/components/radix/themes/components/dialog.pyi +36 -35
- reflex/components/radix/themes/components/dropdown_menu.pyi +42 -42
- reflex/components/radix/themes/components/hover_card.pyi +21 -20
- reflex/components/radix/themes/components/icon_button.pyi +7 -7
- reflex/components/radix/themes/components/inset.pyi +7 -7
- reflex/components/radix/themes/components/popover.pyi +22 -22
- reflex/components/radix/themes/components/progress.pyi +7 -7
- reflex/components/radix/themes/components/radio.pyi +7 -7
- reflex/components/radix/themes/components/radio_cards.pyi +12 -12
- reflex/components/radix/themes/components/radio_group.pyi +21 -20
- reflex/components/radix/themes/components/scroll_area.pyi +7 -7
- reflex/components/radix/themes/components/segmented_control.pyi +12 -12
- reflex/components/radix/themes/components/select.pyi +46 -45
- reflex/components/radix/themes/components/separator.pyi +7 -7
- reflex/components/radix/themes/components/skeleton.pyi +7 -7
- reflex/components/radix/themes/components/slider.pyi +17 -9
- reflex/components/radix/themes/components/spinner.pyi +7 -7
- reflex/components/radix/themes/components/switch.pyi +7 -7
- reflex/components/radix/themes/components/table.pyi +37 -37
- reflex/components/radix/themes/components/tabs.pyi +26 -25
- reflex/components/radix/themes/components/text_area.pyi +15 -9
- reflex/components/radix/themes/components/text_field.pyi +32 -19
- reflex/components/radix/themes/components/tooltip.pyi +7 -7
- reflex/components/radix/themes/layout/__init__.pyi +27 -14
- reflex/components/radix/themes/layout/base.pyi +7 -7
- reflex/components/radix/themes/layout/box.pyi +7 -7
- reflex/components/radix/themes/layout/center.pyi +7 -7
- reflex/components/radix/themes/layout/container.pyi +7 -7
- reflex/components/radix/themes/layout/flex.pyi +7 -7
- reflex/components/radix/themes/layout/grid.pyi +7 -7
- reflex/components/radix/themes/layout/list.pyi +26 -25
- reflex/components/radix/themes/layout/section.pyi +7 -7
- reflex/components/radix/themes/layout/spacer.pyi +7 -7
- reflex/components/radix/themes/layout/stack.pyi +17 -17
- reflex/components/radix/themes/typography/__init__.pyi +7 -5
- reflex/components/radix/themes/typography/blockquote.pyi +7 -7
- reflex/components/radix/themes/typography/code.pyi +7 -7
- reflex/components/radix/themes/typography/heading.pyi +7 -7
- reflex/components/radix/themes/typography/link.py +46 -11
- reflex/components/radix/themes/typography/link.pyi +312 -9
- reflex/components/radix/themes/typography/text.pyi +36 -35
- reflex/components/react_player/audio.pyi +10 -8
- reflex/components/react_player/react_player.pyi +7 -7
- reflex/components/react_player/video.pyi +10 -8
- reflex/components/recharts/__init__.pyi +208 -100
- reflex/components/recharts/cartesian.py +10 -8
- reflex/components/recharts/cartesian.pyi +90 -94
- reflex/components/recharts/charts.py +4 -2
- reflex/components/recharts/charts.pyi +49 -49
- reflex/components/recharts/general.pyi +31 -31
- reflex/components/recharts/polar.py +8 -4
- reflex/components/recharts/polar.pyi +23 -23
- reflex/components/recharts/recharts.py +2 -2
- reflex/components/recharts/recharts.pyi +12 -12
- reflex/components/sonner/toast.py +3 -3
- reflex/components/sonner/toast.pyi +9 -9
- reflex/config.py +10 -113
- reflex/constants/__init__.py +2 -2
- reflex/constants/base.py +28 -11
- reflex/constants/compiler.py +12 -3
- reflex/constants/event.py +1 -0
- reflex/constants/installer.py +26 -20
- reflex/constants/route.py +27 -8
- reflex/constants/state.py +2 -0
- reflex/custom_components/custom_components.py +0 -14
- reflex/environment.py +77 -5
- reflex/event.py +178 -81
- reflex/experimental/__init__.py +0 -30
- reflex/istate/__init__.py +69 -0
- reflex/istate/manager.py +1 -0
- reflex/istate/proxy.py +5 -3
- reflex/page.py +0 -27
- reflex/plugins/__init__.py +3 -2
- reflex/plugins/base.py +5 -1
- reflex/plugins/shared_tailwind.py +215 -0
- reflex/plugins/sitemap.py +206 -0
- reflex/plugins/tailwind_v3.py +15 -108
- reflex/plugins/tailwind_v4.py +18 -110
- reflex/reflex.py +1 -0
- reflex/route.py +157 -75
- reflex/state.py +171 -155
- reflex/testing.py +86 -16
- reflex/utils/build.py +38 -82
- reflex/utils/exec.py +83 -175
- reflex/utils/export.py +2 -2
- reflex/utils/format.py +1 -5
- reflex/utils/imports.py +5 -16
- reflex/utils/misc.py +67 -0
- reflex/utils/prerequisites.py +66 -68
- reflex/utils/processes.py +24 -47
- reflex/utils/pyi_generator.py +44 -49
- reflex/utils/serializers.py +14 -1
- reflex/utils/telemetry.py +0 -15
- reflex/utils/types.py +197 -62
- reflex/vars/__init__.py +2 -0
- reflex/vars/base.py +367 -134
- {reflex-0.7.14a6.dist-info → reflex-0.8.0.dist-info}/METADATA +15 -8
- reflex-0.8.0.dist-info/RECORD +403 -0
- reflex/.templates/web/next.config.js +0 -7
- reflex/components/base/head.py +0 -20
- reflex/components/base/head.pyi +0 -116
- reflex/components/next/__init__.py +0 -10
- reflex/components/next/base.py +0 -7
- reflex/components/next/image.py +0 -117
- reflex/components/next/image.pyi +0 -94
- reflex/components/next/link.py +0 -20
- reflex/components/next/link.pyi +0 -67
- reflex/components/next/video.py +0 -38
- reflex/components/next/video.pyi +0 -68
- reflex/components/suneditor/__init__.py +0 -5
- reflex/components/suneditor/editor.py +0 -269
- reflex/components/suneditor/editor.pyi +0 -199
- reflex/experimental/layout.py +0 -254
- reflex/experimental/layout.pyi +0 -814
- reflex-0.7.14a6.dist-info/RECORD +0 -408
- {reflex-0.7.14a6.dist-info → reflex-0.8.0.dist-info}/WHEEL +0 -0
- {reflex-0.7.14a6.dist-info → reflex-0.8.0.dist-info}/entry_points.txt +0 -0
- {reflex-0.7.14a6.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
|
-
|
|
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
|
|
259
|
-
"""
|
|
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
|
-
|
|
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 =
|
|
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,
|
|
289
|
-
result_var_type=
|
|
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(
|
|
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
|
|
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
|
|
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
|
-
|
|
552
|
-
for f in cls.get_fields().
|
|
553
|
-
if
|
|
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
|
-
|
|
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.
|
|
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[
|
|
587
|
-
cls.vars[
|
|
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 =
|
|
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
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
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
|
|
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())
|
|
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,
|
|
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 =
|
|
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()[
|
|
1134
|
-
|
|
1135
|
-
|
|
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
|
|
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
|
-
|
|
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
|
|
1374
|
-
|
|
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
|
-
|
|
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
|
-
|
|
2062
|
-
|
|
2063
|
-
|
|
2064
|
-
|
|
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(): {
|
|
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 =
|
|
2151
|
-
state
|
|
2152
|
-
if state
|
|
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
|
|
2155
|
-
state
|
|
2162
|
+
state.pop("router", None)
|
|
2163
|
+
state.pop("router_data", None)
|
|
2156
2164
|
# Never serialize parent_state or substates.
|
|
2157
|
-
state
|
|
2158
|
-
state
|
|
2159
|
-
state
|
|
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
|
|
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["
|
|
2174
|
-
state["
|
|
2175
|
-
|
|
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,
|
|
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((
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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."
|