reflex 0.6.0a1__py3-none-any.whl → 0.6.0a3__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/custom_components/pyproject.toml.jinja2 +2 -2
- reflex/.templates/jinja/web/pages/_app.js.jinja2 +1 -1
- reflex/.templates/jinja/web/pages/utils.js.jinja2 +2 -2
- reflex/__init__.py +8 -2
- reflex/__init__.pyi +2 -1
- reflex/app.py +10 -4
- reflex/base.py +1 -1
- reflex/compiler/compiler.py +2 -2
- reflex/compiler/utils.py +3 -3
- reflex/components/base/app_wrap.py +2 -2
- reflex/components/base/app_wrap.pyi +17 -27
- reflex/components/base/bare.py +4 -5
- reflex/components/base/body.pyi +17 -27
- reflex/components/base/document.pyi +81 -131
- reflex/components/base/error_boundary.py +6 -7
- reflex/components/base/error_boundary.pyi +20 -33
- reflex/components/base/fragment.pyi +17 -27
- reflex/components/base/head.pyi +33 -53
- reflex/components/base/link.py +1 -1
- reflex/components/base/link.pyi +33 -54
- reflex/components/base/meta.pyi +65 -105
- reflex/components/base/script.py +1 -2
- reflex/components/base/script.pyi +21 -38
- reflex/components/component.py +45 -47
- reflex/components/core/banner.py +23 -27
- reflex/components/core/banner.pyi +134 -171
- reflex/components/core/breakpoints.py +3 -1
- reflex/components/core/client_side_routing.py +2 -3
- reflex/components/core/client_side_routing.pyi +33 -54
- reflex/components/core/clipboard.py +2 -1
- reflex/components/core/clipboard.pyi +20 -33
- reflex/components/core/cond.py +5 -5
- reflex/components/core/debounce.py +5 -5
- reflex/components/core/debounce.pyi +20 -33
- reflex/components/core/foreach.py +3 -4
- reflex/components/core/html.py +1 -1
- reflex/components/core/html.pyi +35 -46
- reflex/components/core/match.py +17 -17
- reflex/components/core/upload.py +17 -23
- reflex/components/core/upload.pyi +78 -124
- reflex/components/datadisplay/code.py +9 -10
- reflex/components/datadisplay/code.pyi +302 -412
- reflex/components/datadisplay/dataeditor.py +8 -10
- reflex/components/datadisplay/dataeditor.pyi +40 -53
- reflex/components/el/element.pyi +17 -27
- reflex/components/el/elements/base.py +1 -1
- reflex/components/el/elements/base.pyi +34 -45
- reflex/components/el/elements/forms.py +16 -16
- reflex/components/el/elements/forms.pyi +554 -707
- reflex/components/el/elements/inline.py +1 -1
- reflex/components/el/elements/inline.pyi +937 -1218
- reflex/components/el/elements/media.py +1 -1
- reflex/components/el/elements/media.pyi +786 -997
- reflex/components/el/elements/metadata.py +3 -6
- reflex/components/el/elements/metadata.pyi +181 -242
- reflex/components/el/elements/other.py +1 -1
- reflex/components/el/elements/other.pyi +235 -306
- reflex/components/el/elements/scripts.py +1 -1
- reflex/components/el/elements/scripts.pyi +109 -140
- reflex/components/el/elements/sectioning.py +0 -2
- reflex/components/el/elements/sectioning.pyi +496 -647
- reflex/components/el/elements/tables.py +1 -1
- reflex/components/el/elements/tables.pyi +351 -452
- reflex/components/el/elements/typography.py +1 -1
- reflex/components/el/elements/typography.pyi +506 -657
- reflex/components/gridjs/datatable.py +6 -9
- reflex/components/gridjs/datatable.pyi +35 -56
- reflex/components/lucide/icon.py +1 -1
- reflex/components/lucide/icon.pyi +33 -54
- reflex/components/markdown/markdown.py +26 -31
- reflex/components/markdown/markdown.pyi +27 -37
- reflex/components/moment/moment.py +13 -12
- reflex/components/moment/moment.pyi +23 -35
- reflex/components/next/base.pyi +17 -27
- reflex/components/next/image.py +1 -1
- reflex/components/next/image.pyi +22 -37
- reflex/components/next/link.py +1 -1
- reflex/components/next/link.pyi +17 -28
- reflex/components/next/video.py +1 -1
- reflex/components/next/video.pyi +17 -28
- reflex/components/plotly/plotly.py +12 -13
- reflex/components/plotly/plotly.pyi +39 -54
- reflex/components/props.py +1 -1
- reflex/components/radix/__init__.pyi +1 -0
- reflex/components/radix/primitives/__init__.pyi +1 -0
- reflex/components/radix/primitives/accordion.py +4 -4
- reflex/components/radix/primitives/accordion.pyi +424 -495
- reflex/components/radix/primitives/base.py +1 -1
- reflex/components/radix/primitives/base.pyi +33 -54
- reflex/components/radix/primitives/drawer.py +1 -1
- reflex/components/radix/primitives/drawer.pyi +172 -273
- reflex/components/radix/primitives/form.py +1 -1
- reflex/components/radix/primitives/form.pyi +257 -364
- reflex/components/radix/primitives/progress.py +1 -1
- reflex/components/radix/primitives/progress.pyi +231 -282
- reflex/components/radix/primitives/slider.py +1 -1
- reflex/components/radix/primitives/slider.pyi +87 -138
- reflex/components/radix/themes/base.py +3 -24
- reflex/components/radix/themes/base.pyi +178 -250
- reflex/components/radix/themes/color_mode.py +5 -5
- reflex/components/radix/themes/color_mode.pyi +187 -220
- reflex/components/radix/themes/components/alert_dialog.py +1 -1
- reflex/components/radix/themes/components/alert_dialog.pyi +136 -207
- reflex/components/radix/themes/components/aspect_ratio.py +1 -1
- reflex/components/radix/themes/components/aspect_ratio.pyi +17 -28
- reflex/components/radix/themes/components/avatar.py +1 -1
- reflex/components/radix/themes/components/avatar.pyi +70 -81
- reflex/components/radix/themes/components/badge.py +1 -1
- reflex/components/radix/themes/components/badge.pyi +88 -99
- reflex/components/radix/themes/components/button.py +1 -1
- reflex/components/radix/themes/components/button.pyi +98 -109
- reflex/components/radix/themes/components/callout.py +1 -1
- reflex/components/radix/themes/components/callout.pyi +322 -373
- reflex/components/radix/themes/components/card.py +1 -1
- reflex/components/radix/themes/components/card.pyi +38 -49
- reflex/components/radix/themes/components/checkbox.py +1 -2
- reflex/components/radix/themes/components/checkbox.pyi +208 -245
- reflex/components/radix/themes/components/checkbox_cards.py +1 -1
- reflex/components/radix/themes/components/checkbox_cards.pyi +94 -115
- reflex/components/radix/themes/components/checkbox_group.py +1 -1
- reflex/components/radix/themes/components/checkbox_group.pyi +86 -107
- reflex/components/radix/themes/components/context_menu.py +1 -1
- reflex/components/radix/themes/components/context_menu.pyi +238 -319
- reflex/components/radix/themes/components/data_list.py +1 -1
- reflex/components/radix/themes/components/data_list.pyi +130 -171
- reflex/components/radix/themes/components/dialog.py +1 -1
- reflex/components/radix/themes/components/dialog.pyi +139 -210
- reflex/components/radix/themes/components/dropdown_menu.py +1 -1
- reflex/components/radix/themes/components/dropdown_menu.pyi +249 -332
- reflex/components/radix/themes/components/hover_card.py +1 -1
- reflex/components/radix/themes/components/hover_card.pyi +90 -131
- reflex/components/radix/themes/components/icon_button.py +2 -3
- reflex/components/radix/themes/components/icon_button.pyi +98 -109
- reflex/components/radix/themes/components/inset.py +1 -1
- reflex/components/radix/themes/components/inset.pyi +47 -58
- reflex/components/radix/themes/components/popover.py +1 -1
- reflex/components/radix/themes/components/popover.pyi +95 -136
- reflex/components/radix/themes/components/progress.py +1 -1
- reflex/components/radix/themes/components/progress.pyi +71 -82
- reflex/components/radix/themes/components/radio.py +1 -1
- reflex/components/radix/themes/components/radio.pyi +69 -80
- reflex/components/radix/themes/components/radio_cards.py +1 -1
- reflex/components/radix/themes/components/radio_cards.pyi +98 -119
- reflex/components/radix/themes/components/radio_group.py +8 -11
- reflex/components/radix/themes/components/radio_group.pyi +228 -271
- reflex/components/radix/themes/components/scroll_area.py +1 -1
- reflex/components/radix/themes/components/scroll_area.pyi +21 -32
- reflex/components/radix/themes/components/segmented_control.py +1 -1
- reflex/components/radix/themes/components/segmented_control.pyi +90 -113
- reflex/components/radix/themes/components/select.py +2 -3
- reflex/components/radix/themes/components/select.pyi +374 -471
- reflex/components/radix/themes/components/separator.py +1 -2
- reflex/components/radix/themes/components/separator.pyi +69 -80
- reflex/components/radix/themes/components/skeleton.py +1 -1
- reflex/components/radix/themes/components/skeleton.pyi +23 -34
- reflex/components/radix/themes/components/slider.py +2 -3
- reflex/components/radix/themes/components/slider.pyi +75 -88
- reflex/components/radix/themes/components/spinner.py +1 -1
- reflex/components/radix/themes/components/spinner.pyi +19 -30
- reflex/components/radix/themes/components/switch.py +1 -1
- reflex/components/radix/themes/components/switch.pyi +71 -84
- reflex/components/radix/themes/components/table.py +1 -1
- reflex/components/radix/themes/components/table.pyi +261 -332
- reflex/components/radix/themes/components/tabs.py +1 -1
- reflex/components/radix/themes/components/tabs.pyi +139 -194
- reflex/components/radix/themes/components/text_area.py +1 -1
- reflex/components/radix/themes/components/text_area.pyi +96 -111
- reflex/components/radix/themes/components/text_field.py +1 -1
- reflex/components/radix/themes/components/text_field.pyi +247 -286
- reflex/components/radix/themes/components/tooltip.py +1 -1
- reflex/components/radix/themes/components/tooltip.pyi +26 -37
- reflex/components/radix/themes/layout/__init__.pyi +1 -0
- reflex/components/radix/themes/layout/base.py +1 -1
- reflex/components/radix/themes/layout/base.pyi +56 -67
- reflex/components/radix/themes/layout/box.pyi +34 -45
- reflex/components/radix/themes/layout/center.pyi +56 -67
- reflex/components/radix/themes/layout/container.py +1 -2
- reflex/components/radix/themes/layout/container.pyi +36 -47
- reflex/components/radix/themes/layout/flex.py +1 -1
- reflex/components/radix/themes/layout/flex.pyi +56 -67
- reflex/components/radix/themes/layout/grid.py +1 -1
- reflex/components/radix/themes/layout/grid.pyi +64 -75
- reflex/components/radix/themes/layout/list.py +5 -6
- reflex/components/radix/themes/layout/list.pyi +193 -244
- reflex/components/radix/themes/layout/section.py +1 -2
- reflex/components/radix/themes/layout/section.pyi +36 -47
- reflex/components/radix/themes/layout/spacer.pyi +56 -67
- reflex/components/radix/themes/layout/stack.py +1 -1
- reflex/components/radix/themes/layout/stack.pyi +128 -159
- reflex/components/radix/themes/typography/blockquote.py +1 -1
- reflex/components/radix/themes/typography/blockquote.pyi +89 -100
- reflex/components/radix/themes/typography/code.py +1 -1
- reflex/components/radix/themes/typography/code.pyi +90 -101
- reflex/components/radix/themes/typography/heading.py +1 -1
- reflex/components/radix/themes/typography/heading.pyi +96 -107
- reflex/components/radix/themes/typography/link.py +1 -1
- reflex/components/radix/themes/typography/link.pyi +102 -113
- reflex/components/radix/themes/typography/text.py +1 -1
- reflex/components/radix/themes/typography/text.pyi +501 -572
- reflex/components/react_player/audio.pyi +33 -60
- reflex/components/react_player/react_player.py +1 -1
- reflex/components/react_player/react_player.pyi +33 -60
- reflex/components/react_player/video.pyi +33 -60
- reflex/components/recharts/cartesian.py +2 -3
- reflex/components/recharts/cartesian.pyi +678 -861
- reflex/components/recharts/charts.py +4 -5
- reflex/components/recharts/charts.pyi +252 -357
- reflex/components/recharts/general.py +1 -2
- reflex/components/recharts/general.pyi +180 -231
- reflex/components/recharts/polar.py +4 -5
- reflex/components/recharts/polar.pyi +144 -181
- reflex/components/recharts/recharts.pyi +33 -53
- reflex/components/sonner/toast.py +16 -17
- reflex/components/sonner/toast.pyi +36 -47
- reflex/components/suneditor/editor.py +2 -3
- reflex/components/suneditor/editor.pyi +55 -78
- reflex/components/tags/cond_tag.py +6 -4
- reflex/components/tags/iter_tag.py +28 -16
- reflex/components/tags/match_tag.py +6 -4
- reflex/components/tags/tag.py +40 -23
- reflex/custom_components/custom_components.py +3 -1
- reflex/event.py +115 -67
- reflex/experimental/client_state.py +18 -18
- reflex/experimental/hooks.py +16 -16
- reflex/experimental/layout.py +5 -5
- reflex/experimental/layout.pyi +136 -187
- reflex/middleware/hydrate_middleware.py +2 -0
- reflex/middleware/middleware.py +3 -3
- reflex/state.py +149 -82
- reflex/style.py +21 -22
- reflex/utils/exceptions.py +20 -0
- reflex/utils/format.py +54 -34
- reflex/utils/imports.py +16 -73
- reflex/utils/prerequisites.py +15 -8
- reflex/utils/pyi_generator.py +13 -8
- reflex/utils/serializers.py +12 -22
- reflex/utils/telemetry.py +3 -2
- reflex/utils/types.py +11 -6
- reflex/{ivars → vars}/__init__.py +6 -2
- reflex/{ivars → vars}/base.py +599 -216
- reflex/{ivars → vars}/function.py +15 -19
- reflex/{ivars → vars}/number.py +41 -20
- reflex/{ivars → vars}/object.py +28 -30
- reflex/{ivars → vars}/sequence.py +53 -42
- {reflex-0.6.0a1.dist-info → reflex-0.6.0a3.dist-info}/METADATA +4 -6
- reflex-0.6.0a3.dist-info/RECORD +382 -0
- reflex/.templates/web/components/reflex/chakra_color_mode_provider.js +0 -36
- reflex/vars.py +0 -501
- reflex-0.6.0a1.dist-info/RECORD +0 -384
- {reflex-0.6.0a1.dist-info → reflex-0.6.0a3.dist-info}/LICENSE +0 -0
- {reflex-0.6.0a1.dist-info → reflex-0.6.0a3.dist-info}/WHEEL +0 -0
- {reflex-0.6.0a1.dist-info → reflex-0.6.0a3.dist-info}/entry_points.txt +0 -0
reflex/{ivars → vars}/base.py
RENAMED
|
@@ -9,7 +9,11 @@ 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
|
|
16
|
+
import warnings
|
|
13
17
|
from types import CodeType, FunctionType
|
|
14
18
|
from typing import (
|
|
15
19
|
TYPE_CHECKING,
|
|
@@ -17,6 +21,7 @@ from typing import (
|
|
|
17
21
|
Callable,
|
|
18
22
|
Dict,
|
|
19
23
|
Generic,
|
|
24
|
+
Iterable,
|
|
20
25
|
List,
|
|
21
26
|
Literal,
|
|
22
27
|
NoReturn,
|
|
@@ -43,15 +48,14 @@ from reflex.utils.exceptions import (
|
|
|
43
48
|
VarValueError,
|
|
44
49
|
)
|
|
45
50
|
from reflex.utils.format import format_state_name
|
|
46
|
-
from reflex.utils.
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
_extract_var_data,
|
|
53
|
-
_global_vars,
|
|
51
|
+
from reflex.utils.imports import (
|
|
52
|
+
ImmutableParsedImportDict,
|
|
53
|
+
ImportDict,
|
|
54
|
+
ImportVar,
|
|
55
|
+
ParsedImportDict,
|
|
56
|
+
parse_imports,
|
|
54
57
|
)
|
|
58
|
+
from reflex.utils.types import GenericType, Self, get_origin
|
|
55
59
|
|
|
56
60
|
if TYPE_CHECKING:
|
|
57
61
|
from reflex.state import BaseState
|
|
@@ -67,19 +71,20 @@ if TYPE_CHECKING:
|
|
|
67
71
|
from .sequence import ArrayVar, StringVar, ToArrayOperation, ToStringOperation
|
|
68
72
|
|
|
69
73
|
|
|
70
|
-
VAR_TYPE = TypeVar("VAR_TYPE")
|
|
74
|
+
VAR_TYPE = TypeVar("VAR_TYPE", covariant=True)
|
|
75
|
+
|
|
76
|
+
warnings.filterwarnings("ignore", message="fields may not start with an underscore")
|
|
71
77
|
|
|
72
78
|
|
|
73
79
|
@dataclasses.dataclass(
|
|
74
80
|
eq=False,
|
|
75
81
|
frozen=True,
|
|
76
|
-
**{"slots": True} if sys.version_info >= (3, 10) else {},
|
|
77
82
|
)
|
|
78
|
-
class
|
|
83
|
+
class Var(Generic[VAR_TYPE]):
|
|
79
84
|
"""Base class for immutable vars."""
|
|
80
85
|
|
|
81
86
|
# The name of the var.
|
|
82
|
-
|
|
87
|
+
_js_expr: str = dataclasses.field()
|
|
83
88
|
|
|
84
89
|
# The type of the var.
|
|
85
90
|
_var_type: types.GenericType = dataclasses.field(default=Any)
|
|
@@ -93,7 +98,7 @@ class ImmutableVar(Var, Generic[VAR_TYPE]):
|
|
|
93
98
|
Returns:
|
|
94
99
|
The name of the var.
|
|
95
100
|
"""
|
|
96
|
-
return self.
|
|
101
|
+
return self._js_expr
|
|
97
102
|
|
|
98
103
|
@property
|
|
99
104
|
def _var_is_local(self) -> bool:
|
|
@@ -104,6 +109,26 @@ class ImmutableVar(Var, Generic[VAR_TYPE]):
|
|
|
104
109
|
"""
|
|
105
110
|
return False
|
|
106
111
|
|
|
112
|
+
@property
|
|
113
|
+
@deprecated("Use `_js_expr` instead.")
|
|
114
|
+
def _var_name(self) -> str:
|
|
115
|
+
"""The name of the var.
|
|
116
|
+
|
|
117
|
+
Returns:
|
|
118
|
+
The name of the var.
|
|
119
|
+
"""
|
|
120
|
+
return self._js_expr
|
|
121
|
+
|
|
122
|
+
@property
|
|
123
|
+
@deprecated("Use `_js_expr` instead.")
|
|
124
|
+
def _var_name_unwrapped(self) -> str:
|
|
125
|
+
"""The name of the var without extra curly braces.
|
|
126
|
+
|
|
127
|
+
Returns:
|
|
128
|
+
The name of the var.
|
|
129
|
+
"""
|
|
130
|
+
return self._js_expr
|
|
131
|
+
|
|
107
132
|
@property
|
|
108
133
|
def _var_is_string(self) -> bool:
|
|
109
134
|
"""Whether the var is a string literal.
|
|
@@ -116,11 +141,11 @@ class ImmutableVar(Var, Generic[VAR_TYPE]):
|
|
|
116
141
|
def __post_init__(self):
|
|
117
142
|
"""Post-initialize the var."""
|
|
118
143
|
# Decode any inline Var markup and apply it to the instance
|
|
119
|
-
_var_data,
|
|
144
|
+
_var_data, _js_expr = _decode_var_immutable(self._js_expr)
|
|
120
145
|
|
|
121
|
-
if _var_data or
|
|
146
|
+
if _var_data or _js_expr != self._js_expr:
|
|
122
147
|
self.__init__(
|
|
123
|
-
|
|
148
|
+
_js_expr=_js_expr,
|
|
124
149
|
_var_type=self._var_type,
|
|
125
150
|
_var_data=VarData.merge(self._var_data, _var_data),
|
|
126
151
|
)
|
|
@@ -131,7 +156,7 @@ class ImmutableVar(Var, Generic[VAR_TYPE]):
|
|
|
131
156
|
Returns:
|
|
132
157
|
The hash of the var.
|
|
133
158
|
"""
|
|
134
|
-
return hash((self.
|
|
159
|
+
return hash((self._js_expr, self._var_type, self._var_data))
|
|
135
160
|
|
|
136
161
|
def _get_all_var_data(self) -> VarData | None:
|
|
137
162
|
"""Get all VarData associated with the Var.
|
|
@@ -141,7 +166,7 @@ class ImmutableVar(Var, Generic[VAR_TYPE]):
|
|
|
141
166
|
"""
|
|
142
167
|
return self._var_data
|
|
143
168
|
|
|
144
|
-
def equals(self, other:
|
|
169
|
+
def equals(self, other: Var) -> bool:
|
|
145
170
|
"""Check if two vars are equal.
|
|
146
171
|
|
|
147
172
|
Args:
|
|
@@ -151,7 +176,7 @@ class ImmutableVar(Var, Generic[VAR_TYPE]):
|
|
|
151
176
|
Whether the vars are equal.
|
|
152
177
|
"""
|
|
153
178
|
return (
|
|
154
|
-
self.
|
|
179
|
+
self._js_expr == other._js_expr
|
|
155
180
|
and self._var_type == other._var_type
|
|
156
181
|
and self._get_all_var_data() == other._get_all_var_data()
|
|
157
182
|
)
|
|
@@ -164,24 +189,20 @@ class ImmutableVar(Var, Generic[VAR_TYPE]):
|
|
|
164
189
|
**kwargs: Var fields to update.
|
|
165
190
|
|
|
166
191
|
Returns:
|
|
167
|
-
A new
|
|
192
|
+
A new Var with the updated fields overwriting the corresponding fields in this Var.
|
|
168
193
|
|
|
169
194
|
Raises:
|
|
170
195
|
TypeError: If _var_is_local, _var_is_string, or _var_full_name_needs_state_prefix is not None.
|
|
171
196
|
"""
|
|
172
197
|
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
|
-
)
|
|
198
|
+
raise TypeError("The _var_is_local argument is not supported for Var.")
|
|
176
199
|
|
|
177
200
|
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
|
-
)
|
|
201
|
+
raise TypeError("The _var_is_string argument is not supported for Var.")
|
|
181
202
|
|
|
182
203
|
if kwargs.get("_var_full_name_needs_state_prefix", False) is not False:
|
|
183
204
|
raise TypeError(
|
|
184
|
-
"The _var_full_name_needs_state_prefix argument is not supported for
|
|
205
|
+
"The _var_full_name_needs_state_prefix argument is not supported for Var."
|
|
185
206
|
)
|
|
186
207
|
|
|
187
208
|
return dataclasses.replace(
|
|
@@ -199,7 +220,7 @@ class ImmutableVar(Var, Generic[VAR_TYPE]):
|
|
|
199
220
|
_var_is_local: bool | None = None,
|
|
200
221
|
_var_is_string: bool | None = None,
|
|
201
222
|
_var_data: VarData | None = None,
|
|
202
|
-
) ->
|
|
223
|
+
) -> Var:
|
|
203
224
|
"""Create a var from a value.
|
|
204
225
|
|
|
205
226
|
Args:
|
|
@@ -210,80 +231,57 @@ class ImmutableVar(Var, Generic[VAR_TYPE]):
|
|
|
210
231
|
|
|
211
232
|
Returns:
|
|
212
233
|
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
234
|
"""
|
|
218
235
|
if _var_is_local is not None:
|
|
219
|
-
|
|
220
|
-
"
|
|
236
|
+
console.deprecate(
|
|
237
|
+
feature_name="_var_is_local",
|
|
238
|
+
reason="The _var_is_local argument is not supported for Var."
|
|
239
|
+
"If you want to create a Var from a raw Javascript expression, use the constructor directly",
|
|
240
|
+
deprecation_version="0.6.0",
|
|
241
|
+
removal_version="0.7.0",
|
|
221
242
|
)
|
|
222
|
-
|
|
223
243
|
if _var_is_string is not None:
|
|
224
|
-
|
|
225
|
-
"
|
|
244
|
+
console.deprecate(
|
|
245
|
+
feature_name="_var_is_string",
|
|
246
|
+
reason="The _var_is_string argument is not supported for Var."
|
|
247
|
+
"If you want to create a Var from a raw Javascript expression, use the constructor directly",
|
|
248
|
+
deprecation_version="0.6.0",
|
|
249
|
+
removal_version="0.7.0",
|
|
226
250
|
)
|
|
227
251
|
|
|
228
|
-
from reflex.utils import format
|
|
229
|
-
|
|
230
|
-
# Check for none values.
|
|
231
|
-
if value is None:
|
|
232
|
-
return None
|
|
233
|
-
|
|
234
252
|
# If the value is already a var, do nothing.
|
|
235
|
-
if isinstance(value,
|
|
253
|
+
if isinstance(value, Var):
|
|
236
254
|
return value
|
|
237
255
|
|
|
238
256
|
# Try to pull the imports and hooks from contained values.
|
|
239
257
|
if not isinstance(value, str):
|
|
240
|
-
|
|
258
|
+
return LiteralVar.create(value)
|
|
241
259
|
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
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_}."
|
|
260
|
+
if _var_is_string is False or _var_is_local is True:
|
|
261
|
+
return cls(
|
|
262
|
+
_js_expr=value,
|
|
263
|
+
_var_data=_var_data,
|
|
251
264
|
)
|
|
252
|
-
name = name if isinstance(name, str) else format.json_dumps(name)
|
|
253
265
|
|
|
254
|
-
return
|
|
255
|
-
_var_name=name,
|
|
256
|
-
_var_type=type_,
|
|
257
|
-
_var_data=_var_data,
|
|
258
|
-
)
|
|
266
|
+
return LiteralVar.create(value, _var_data=_var_data)
|
|
259
267
|
|
|
260
268
|
@classmethod
|
|
269
|
+
@deprecated("Use `.create()` instead.")
|
|
261
270
|
def create_safe(
|
|
262
271
|
cls,
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
) -> ImmutableVar:
|
|
268
|
-
"""Create a var from a value, asserting that it is not None.
|
|
272
|
+
*args: Any,
|
|
273
|
+
**kwargs: Any,
|
|
274
|
+
) -> Var:
|
|
275
|
+
"""Create a var from a value.
|
|
269
276
|
|
|
270
277
|
Args:
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
_var_is_string: Whether the var is a string literal. Deprecated.
|
|
274
|
-
_var_data: Additional hooks and imports associated with the Var.
|
|
278
|
+
*args: The arguments to create the var from.
|
|
279
|
+
**kwargs: The keyword arguments to create the var from.
|
|
275
280
|
|
|
276
281
|
Returns:
|
|
277
282
|
The var.
|
|
278
283
|
"""
|
|
279
|
-
|
|
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
|
|
284
|
+
return cls.create(*args, **kwargs)
|
|
287
285
|
|
|
288
286
|
def __format__(self, format_spec: str) -> str:
|
|
289
287
|
"""Format the var into a Javascript equivalent to an f-string.
|
|
@@ -299,7 +297,7 @@ class ImmutableVar(Var, Generic[VAR_TYPE]):
|
|
|
299
297
|
_global_vars[hashed_var] = self
|
|
300
298
|
|
|
301
299
|
# 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.
|
|
300
|
+
return f"{constants.REFLEX_VAR_OPENING_TAG}{hashed_var}{constants.REFLEX_VAR_CLOSING_TAG}{self._js_expr}"
|
|
303
301
|
|
|
304
302
|
@overload
|
|
305
303
|
def to(self, output: Type[StringVar]) -> ToStringOperation: ...
|
|
@@ -343,7 +341,7 @@ class ImmutableVar(Var, Generic[VAR_TYPE]):
|
|
|
343
341
|
self,
|
|
344
342
|
output: Type[OUTPUT] | types.GenericType,
|
|
345
343
|
var_type: types.GenericType | None = None,
|
|
346
|
-
) ->
|
|
344
|
+
) -> Var:
|
|
347
345
|
"""Convert the var to a different type.
|
|
348
346
|
|
|
349
347
|
Args:
|
|
@@ -387,6 +385,12 @@ class ImmutableVar(Var, Generic[VAR_TYPE]):
|
|
|
387
385
|
return self.to(BooleanVar, output)
|
|
388
386
|
if fixed_output_type is None:
|
|
389
387
|
return ToNoneOperation.create(self)
|
|
388
|
+
if issubclass(fixed_output_type, Base):
|
|
389
|
+
return self.to(ObjectVar, output)
|
|
390
|
+
if dataclasses.is_dataclass(fixed_output_type) and not issubclass(
|
|
391
|
+
fixed_output_type, Var
|
|
392
|
+
):
|
|
393
|
+
return self.to(ObjectVar, output)
|
|
390
394
|
|
|
391
395
|
if issubclass(output, BooleanVar):
|
|
392
396
|
return ToBooleanVarOperation.create(self)
|
|
@@ -421,6 +425,9 @@ class ImmutableVar(Var, Generic[VAR_TYPE]):
|
|
|
421
425
|
if issubclass(output, (ObjectVar, Base)):
|
|
422
426
|
return ToObjectOperation.create(self, var_type or dict)
|
|
423
427
|
|
|
428
|
+
if dataclasses.is_dataclass(output):
|
|
429
|
+
return ToObjectOperation.create(self, var_type or dict)
|
|
430
|
+
|
|
424
431
|
if issubclass(output, FunctionVar):
|
|
425
432
|
# if fixed_type is not None and not issubclass(fixed_type, Callable):
|
|
426
433
|
# raise TypeError(
|
|
@@ -447,11 +454,11 @@ class ImmutableVar(Var, Generic[VAR_TYPE]):
|
|
|
447
454
|
|
|
448
455
|
return self
|
|
449
456
|
|
|
450
|
-
def guess_type(self) ->
|
|
457
|
+
def guess_type(self) -> Var:
|
|
451
458
|
"""Guesses the type of the variable based on its `_var_type` attribute.
|
|
452
459
|
|
|
453
460
|
Returns:
|
|
454
|
-
|
|
461
|
+
Var: The guessed type of the variable.
|
|
455
462
|
|
|
456
463
|
Raises:
|
|
457
464
|
TypeError: If the type is not supported for guessing.
|
|
@@ -479,7 +486,11 @@ class ImmutableVar(Var, Generic[VAR_TYPE]):
|
|
|
479
486
|
):
|
|
480
487
|
return self.to(NumberVar, self._var_type)
|
|
481
488
|
|
|
482
|
-
if all(
|
|
489
|
+
if all(
|
|
490
|
+
inspect.isclass(t)
|
|
491
|
+
and (issubclass(t, Base) or dataclasses.is_dataclass(t))
|
|
492
|
+
for t in inner_types
|
|
493
|
+
):
|
|
483
494
|
return self.to(ObjectVar, self._var_type)
|
|
484
495
|
|
|
485
496
|
return self
|
|
@@ -499,6 +510,8 @@ class ImmutableVar(Var, Generic[VAR_TYPE]):
|
|
|
499
510
|
return self.to(StringVar, self._var_type)
|
|
500
511
|
if issubclass(fixed_type, Base):
|
|
501
512
|
return self.to(ObjectVar, self._var_type)
|
|
513
|
+
if dataclasses.is_dataclass(fixed_type):
|
|
514
|
+
return self.to(ObjectVar, self._var_type)
|
|
502
515
|
return self
|
|
503
516
|
|
|
504
517
|
def get_default_value(self) -> Any:
|
|
@@ -553,7 +566,7 @@ class ImmutableVar(Var, Generic[VAR_TYPE]):
|
|
|
553
566
|
Returns:
|
|
554
567
|
The name of the setter function.
|
|
555
568
|
"""
|
|
556
|
-
var_name_parts = self.
|
|
569
|
+
var_name_parts = self._js_expr.split(".")
|
|
557
570
|
setter = constants.SETTER_PREFIX + var_name_parts[-1]
|
|
558
571
|
var_data = self._get_all_var_data()
|
|
559
572
|
if var_data is None:
|
|
@@ -568,7 +581,7 @@ class ImmutableVar(Var, Generic[VAR_TYPE]):
|
|
|
568
581
|
Returns:
|
|
569
582
|
A function that that creates a setter for the var.
|
|
570
583
|
"""
|
|
571
|
-
actual_name = self.
|
|
584
|
+
actual_name = self._js_expr.split(".")[-1]
|
|
572
585
|
|
|
573
586
|
def setter(state: BaseState, value: Any):
|
|
574
587
|
"""Get the setter for the var.
|
|
@@ -583,7 +596,7 @@ class ImmutableVar(Var, Generic[VAR_TYPE]):
|
|
|
583
596
|
setattr(state, actual_name, value)
|
|
584
597
|
except ValueError:
|
|
585
598
|
console.debug(
|
|
586
|
-
f"{type(state).__name__}.{self.
|
|
599
|
+
f"{type(state).__name__}.{self._js_expr}: Failed conversion of {value} to '{self._var_type.__name__}'. Value not set.",
|
|
587
600
|
)
|
|
588
601
|
else:
|
|
589
602
|
setattr(state, actual_name, value)
|
|
@@ -613,11 +626,11 @@ class ImmutableVar(Var, Generic[VAR_TYPE]):
|
|
|
613
626
|
_var_data=VarData.merge(VarData.from_state(state), self._var_data),
|
|
614
627
|
).guess_type()
|
|
615
628
|
|
|
616
|
-
def __eq__(self, other:
|
|
629
|
+
def __eq__(self, other: Var | Any) -> BooleanVar:
|
|
617
630
|
"""Check if the current variable is equal to the given variable.
|
|
618
631
|
|
|
619
632
|
Args:
|
|
620
|
-
other (
|
|
633
|
+
other (Var | Any): The variable to compare with.
|
|
621
634
|
|
|
622
635
|
Returns:
|
|
623
636
|
BooleanVar: A BooleanVar object representing the result of the equality check.
|
|
@@ -626,11 +639,11 @@ class ImmutableVar(Var, Generic[VAR_TYPE]):
|
|
|
626
639
|
|
|
627
640
|
return equal_operation(self, other)
|
|
628
641
|
|
|
629
|
-
def __ne__(self, other:
|
|
642
|
+
def __ne__(self, other: Var | Any) -> BooleanVar:
|
|
630
643
|
"""Check if the current object is not equal to the given object.
|
|
631
644
|
|
|
632
645
|
Parameters:
|
|
633
|
-
other (
|
|
646
|
+
other (Var | Any): The object to compare with.
|
|
634
647
|
|
|
635
648
|
Returns:
|
|
636
649
|
BooleanVar: A BooleanVar object representing the result of the comparison.
|
|
@@ -649,7 +662,7 @@ class ImmutableVar(Var, Generic[VAR_TYPE]):
|
|
|
649
662
|
|
|
650
663
|
return boolify(self)
|
|
651
664
|
|
|
652
|
-
def __and__(self, other:
|
|
665
|
+
def __and__(self, other: Var | Any) -> Var:
|
|
653
666
|
"""Perform a logical AND operation on the current instance and another variable.
|
|
654
667
|
|
|
655
668
|
Args:
|
|
@@ -660,7 +673,7 @@ class ImmutableVar(Var, Generic[VAR_TYPE]):
|
|
|
660
673
|
"""
|
|
661
674
|
return and_operation(self, other)
|
|
662
675
|
|
|
663
|
-
def __rand__(self, other:
|
|
676
|
+
def __rand__(self, other: Var | Any) -> Var:
|
|
664
677
|
"""Perform a logical AND operation on the current instance and another variable.
|
|
665
678
|
|
|
666
679
|
Args:
|
|
@@ -671,7 +684,7 @@ class ImmutableVar(Var, Generic[VAR_TYPE]):
|
|
|
671
684
|
"""
|
|
672
685
|
return and_operation(other, self)
|
|
673
686
|
|
|
674
|
-
def __or__(self, other:
|
|
687
|
+
def __or__(self, other: Var | Any) -> Var:
|
|
675
688
|
"""Perform a logical OR operation on the current instance and another variable.
|
|
676
689
|
|
|
677
690
|
Args:
|
|
@@ -682,7 +695,7 @@ class ImmutableVar(Var, Generic[VAR_TYPE]):
|
|
|
682
695
|
"""
|
|
683
696
|
return or_operation(self, other)
|
|
684
697
|
|
|
685
|
-
def __ror__(self, other:
|
|
698
|
+
def __ror__(self, other: Var | Any) -> Var:
|
|
686
699
|
"""Perform a logical OR operation on the current instance and another variable.
|
|
687
700
|
|
|
688
701
|
Args:
|
|
@@ -712,7 +725,7 @@ class ImmutableVar(Var, Generic[VAR_TYPE]):
|
|
|
712
725
|
|
|
713
726
|
return JSON_STRINGIFY.call(self).to(StringVar)
|
|
714
727
|
|
|
715
|
-
def as_ref(self) ->
|
|
728
|
+
def as_ref(self) -> Var:
|
|
716
729
|
"""Get a reference to the var.
|
|
717
730
|
|
|
718
731
|
Returns:
|
|
@@ -720,14 +733,14 @@ class ImmutableVar(Var, Generic[VAR_TYPE]):
|
|
|
720
733
|
"""
|
|
721
734
|
from .object import ObjectVar
|
|
722
735
|
|
|
723
|
-
refs =
|
|
724
|
-
|
|
736
|
+
refs = Var(
|
|
737
|
+
_js_expr="refs",
|
|
725
738
|
_var_data=VarData(
|
|
726
739
|
imports={
|
|
727
740
|
f"/{constants.Dirs.STATE_PATH}": [imports.ImportVar(tag="refs")]
|
|
728
741
|
}
|
|
729
742
|
),
|
|
730
|
-
).to(ObjectVar)
|
|
743
|
+
).to(ObjectVar, Dict[str, str])
|
|
731
744
|
return refs[LiteralVar.create(str(self))]
|
|
732
745
|
|
|
733
746
|
@deprecated("Use `.js_type()` instead.")
|
|
@@ -813,7 +826,8 @@ class ImmutableVar(Var, Generic[VAR_TYPE]):
|
|
|
813
826
|
TypeError: If the var type is Any.
|
|
814
827
|
"""
|
|
815
828
|
if name.startswith("_"):
|
|
816
|
-
return
|
|
829
|
+
return self.__getattribute__(name)
|
|
830
|
+
|
|
817
831
|
if self._var_type is Any:
|
|
818
832
|
raise TypeError(
|
|
819
833
|
f"You must provide an annotation for the state var `{str(self)}`. Annotation cannot be `{self._var_type}`."
|
|
@@ -857,26 +871,85 @@ class ImmutableVar(Var, Generic[VAR_TYPE]):
|
|
|
857
871
|
var_data = self._get_all_var_data()
|
|
858
872
|
return var_data.state if var_data else ""
|
|
859
873
|
|
|
874
|
+
@overload
|
|
875
|
+
@classmethod
|
|
876
|
+
def range(cls, stop: int | NumberVar, /) -> ArrayVar[List[int]]: ...
|
|
877
|
+
|
|
878
|
+
@overload
|
|
879
|
+
@classmethod
|
|
880
|
+
def range(
|
|
881
|
+
cls,
|
|
882
|
+
start: int | NumberVar,
|
|
883
|
+
end: int | NumberVar,
|
|
884
|
+
step: int | NumberVar = 1,
|
|
885
|
+
/,
|
|
886
|
+
) -> ArrayVar[List[int]]: ...
|
|
887
|
+
|
|
888
|
+
@classmethod
|
|
889
|
+
def range(
|
|
890
|
+
cls,
|
|
891
|
+
first_endpoint: int | NumberVar,
|
|
892
|
+
second_endpoint: int | NumberVar | None = None,
|
|
893
|
+
step: int | NumberVar | None = None,
|
|
894
|
+
) -> ArrayVar[List[int]]:
|
|
895
|
+
"""Create a range of numbers.
|
|
860
896
|
|
|
861
|
-
|
|
897
|
+
Args:
|
|
898
|
+
first_endpoint: The end of the range if second_endpoint is not provided, otherwise the start of the range.
|
|
899
|
+
second_endpoint: The end of the range.
|
|
900
|
+
step: The step of the range.
|
|
862
901
|
|
|
902
|
+
Returns:
|
|
903
|
+
The range of numbers.
|
|
904
|
+
"""
|
|
905
|
+
from .sequence import ArrayVar
|
|
863
906
|
|
|
864
|
-
|
|
865
|
-
"""Encode the state name into a formatted var.
|
|
907
|
+
return ArrayVar.range(first_endpoint, second_endpoint, step)
|
|
866
908
|
|
|
867
|
-
|
|
868
|
-
|
|
909
|
+
def __bool__(self) -> bool:
|
|
910
|
+
"""Raise exception if using Var in a boolean context.
|
|
869
911
|
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
912
|
+
Raises:
|
|
913
|
+
VarTypeError: when attempting to bool-ify the Var.
|
|
914
|
+
"""
|
|
915
|
+
raise VarTypeError(
|
|
916
|
+
f"Cannot convert Var {str(self)!r} to bool for use with `if`, `and`, `or`, and `not`. "
|
|
917
|
+
"Instead use `rx.cond` and bitwise operators `&` (and), `|` (or), `~` (invert)."
|
|
918
|
+
)
|
|
919
|
+
|
|
920
|
+
def __iter__(self) -> Any:
|
|
921
|
+
"""Raise exception if using Var in an iterable context.
|
|
922
|
+
|
|
923
|
+
Raises:
|
|
924
|
+
VarTypeError: when attempting to iterate over the Var.
|
|
925
|
+
"""
|
|
926
|
+
raise VarTypeError(
|
|
927
|
+
f"Cannot iterate over Var {str(self)!r}. Instead use `rx.foreach`."
|
|
928
|
+
)
|
|
929
|
+
|
|
930
|
+
def __contains__(self, _: Any) -> Var:
|
|
931
|
+
"""Override the 'in' operator to alert the user that it is not supported.
|
|
932
|
+
|
|
933
|
+
Raises:
|
|
934
|
+
VarTypeError: the operation is not supported
|
|
935
|
+
"""
|
|
936
|
+
raise VarTypeError(
|
|
937
|
+
"'in' operator not supported for Var types, use Var.contains() instead."
|
|
938
|
+
)
|
|
939
|
+
|
|
940
|
+
def json(self) -> str:
|
|
941
|
+
"""Serialize the var to a JSON string.
|
|
942
|
+
|
|
943
|
+
Raises:
|
|
944
|
+
NotImplementedError: If the method is not implemented.
|
|
945
|
+
"""
|
|
946
|
+
raise NotImplementedError("Var subclasses must implement the json method.")
|
|
874
947
|
|
|
875
948
|
|
|
876
|
-
|
|
949
|
+
OUTPUT = TypeVar("OUTPUT", bound=Var)
|
|
877
950
|
|
|
878
951
|
|
|
879
|
-
class LiteralVar(
|
|
952
|
+
class LiteralVar(Var):
|
|
880
953
|
"""Base class for immutable literal vars."""
|
|
881
954
|
|
|
882
955
|
@classmethod
|
|
@@ -884,7 +957,7 @@ class LiteralVar(ImmutableVar):
|
|
|
884
957
|
cls,
|
|
885
958
|
value: Any,
|
|
886
959
|
_var_data: VarData | None = None,
|
|
887
|
-
) ->
|
|
960
|
+
) -> Var:
|
|
888
961
|
"""Create a var from a value.
|
|
889
962
|
|
|
890
963
|
Args:
|
|
@@ -901,7 +974,7 @@ class LiteralVar(ImmutableVar):
|
|
|
901
974
|
from .object import LiteralObjectVar
|
|
902
975
|
from .sequence import LiteralArrayVar, LiteralStringVar
|
|
903
976
|
|
|
904
|
-
if isinstance(value,
|
|
977
|
+
if isinstance(value, Var):
|
|
905
978
|
if _var_data is None:
|
|
906
979
|
return value
|
|
907
980
|
return value._replace(merge_var_data=_var_data)
|
|
@@ -924,7 +997,7 @@ class LiteralVar(ImmutableVar):
|
|
|
924
997
|
if value is None:
|
|
925
998
|
return LiteralNoneVar.create(_var_data=_var_data)
|
|
926
999
|
|
|
927
|
-
from reflex.event import EventChain, EventSpec
|
|
1000
|
+
from reflex.event import EventChain, EventHandler, EventSpec
|
|
928
1001
|
from reflex.utils.format import get_event_handler_parts
|
|
929
1002
|
|
|
930
1003
|
from .function import ArgsFunctionOperation, FunctionStringVar
|
|
@@ -948,14 +1021,12 @@ class LiteralVar(ImmutableVar):
|
|
|
948
1021
|
sig = inspect.signature(value.args_spec) # type: ignore
|
|
949
1022
|
if sig.parameters:
|
|
950
1023
|
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
|
-
)
|
|
1024
|
+
arg_def_expr = LiteralVar.create([Var(_js_expr=arg) for arg in arg_def])
|
|
954
1025
|
else:
|
|
955
1026
|
# add a default argument for addEvents if none were specified in value.args_spec
|
|
956
1027
|
# used to trigger the preventDefault() on the event.
|
|
957
1028
|
arg_def = ("...args",)
|
|
958
|
-
arg_def_expr =
|
|
1029
|
+
arg_def_expr = Var(_js_expr="args")
|
|
959
1030
|
|
|
960
1031
|
return ArgsFunctionOperation.create(
|
|
961
1032
|
arg_def,
|
|
@@ -968,12 +1039,8 @@ class LiteralVar(ImmutableVar):
|
|
|
968
1039
|
),
|
|
969
1040
|
)
|
|
970
1041
|
|
|
971
|
-
if isinstance(value,
|
|
972
|
-
return
|
|
973
|
-
{k: (None if callable(v) else v) for k, v in value.dict().items()},
|
|
974
|
-
_var_type=type(value),
|
|
975
|
-
_var_data=_var_data,
|
|
976
|
-
)
|
|
1042
|
+
if isinstance(value, EventHandler):
|
|
1043
|
+
return Var(_js_expr=".".join(filter(None, get_event_handler_parts(value))))
|
|
977
1044
|
|
|
978
1045
|
serialized_value = serializers.serialize(value)
|
|
979
1046
|
if serialized_value is not None:
|
|
@@ -983,8 +1050,37 @@ class LiteralVar(ImmutableVar):
|
|
|
983
1050
|
_var_type=type(value),
|
|
984
1051
|
_var_data=_var_data,
|
|
985
1052
|
)
|
|
1053
|
+
if isinstance(serialized_value, str):
|
|
1054
|
+
return LiteralStringVar.create(
|
|
1055
|
+
serialized_value, _var_type=type(value), _var_data=_var_data
|
|
1056
|
+
)
|
|
986
1057
|
return LiteralVar.create(serialized_value, _var_data=_var_data)
|
|
987
1058
|
|
|
1059
|
+
if isinstance(value, Base):
|
|
1060
|
+
# get the fields of the pydantic class
|
|
1061
|
+
fields = value.__fields__.keys()
|
|
1062
|
+
one_level_dict = {field: getattr(value, field) for field in fields}
|
|
1063
|
+
|
|
1064
|
+
return LiteralObjectVar.create(
|
|
1065
|
+
{
|
|
1066
|
+
field: value
|
|
1067
|
+
for field, value in one_level_dict.items()
|
|
1068
|
+
if not callable(value)
|
|
1069
|
+
},
|
|
1070
|
+
_var_type=type(value),
|
|
1071
|
+
_var_data=_var_data,
|
|
1072
|
+
)
|
|
1073
|
+
|
|
1074
|
+
if dataclasses.is_dataclass(value) and not isinstance(value, type):
|
|
1075
|
+
return LiteralObjectVar.create(
|
|
1076
|
+
{
|
|
1077
|
+
k: (None if callable(v) else v)
|
|
1078
|
+
for k, v in dataclasses.asdict(value).items()
|
|
1079
|
+
},
|
|
1080
|
+
_var_type=type(value),
|
|
1081
|
+
_var_data=_var_data,
|
|
1082
|
+
)
|
|
1083
|
+
|
|
988
1084
|
raise TypeError(
|
|
989
1085
|
f"Unsupported type {type(value)} for LiteralVar. Tried to create a LiteralVar from {value}."
|
|
990
1086
|
)
|
|
@@ -1003,6 +1099,19 @@ class LiteralVar(ImmutableVar):
|
|
|
1003
1099
|
)
|
|
1004
1100
|
|
|
1005
1101
|
|
|
1102
|
+
@serializers.serializer
|
|
1103
|
+
def serialize_literal(value: LiteralVar):
|
|
1104
|
+
"""Serialize a Literal type.
|
|
1105
|
+
|
|
1106
|
+
Args:
|
|
1107
|
+
value: The Literal to serialize.
|
|
1108
|
+
|
|
1109
|
+
Returns:
|
|
1110
|
+
The serialized Literal.
|
|
1111
|
+
"""
|
|
1112
|
+
return serializers.serialize(value._var_value)
|
|
1113
|
+
|
|
1114
|
+
|
|
1006
1115
|
P = ParamSpec("P")
|
|
1007
1116
|
T = TypeVar("T")
|
|
1008
1117
|
|
|
@@ -1011,7 +1120,7 @@ T = TypeVar("T")
|
|
|
1011
1120
|
@overload
|
|
1012
1121
|
def var_operation(
|
|
1013
1122
|
func: Callable[P, CustomVarOperationReturn[NoReturn]],
|
|
1014
|
-
) -> Callable[P,
|
|
1123
|
+
) -> Callable[P, Var]: ...
|
|
1015
1124
|
|
|
1016
1125
|
|
|
1017
1126
|
@overload
|
|
@@ -1055,7 +1164,7 @@ def var_operation(
|
|
|
1055
1164
|
|
|
1056
1165
|
def var_operation(
|
|
1057
1166
|
func: Callable[P, CustomVarOperationReturn[T]],
|
|
1058
|
-
) -> Callable[P,
|
|
1167
|
+
) -> Callable[P, Var[T]]:
|
|
1059
1168
|
"""Decorator for creating a var operation.
|
|
1060
1169
|
|
|
1061
1170
|
Example:
|
|
@@ -1073,18 +1182,14 @@ def var_operation(
|
|
|
1073
1182
|
"""
|
|
1074
1183
|
|
|
1075
1184
|
@functools.wraps(func)
|
|
1076
|
-
def wrapper(*args: P.args, **kwargs: P.kwargs) ->
|
|
1185
|
+
def wrapper(*args: P.args, **kwargs: P.kwargs) -> Var[T]:
|
|
1077
1186
|
func_args = list(inspect.signature(func).parameters)
|
|
1078
1187
|
args_vars = {
|
|
1079
|
-
func_args[i]: (
|
|
1080
|
-
LiteralVar.create(arg) if not isinstance(arg, ImmutableVar) else arg
|
|
1081
|
-
)
|
|
1188
|
+
func_args[i]: (LiteralVar.create(arg) if not isinstance(arg, Var) else arg)
|
|
1082
1189
|
for i, arg in enumerate(args)
|
|
1083
1190
|
}
|
|
1084
1191
|
kwargs_vars = {
|
|
1085
|
-
key: LiteralVar.create(value)
|
|
1086
|
-
if not isinstance(value, ImmutableVar)
|
|
1087
|
-
else value
|
|
1192
|
+
key: LiteralVar.create(value) if not isinstance(value, Var) else value
|
|
1088
1193
|
for key, value in kwargs.items()
|
|
1089
1194
|
}
|
|
1090
1195
|
|
|
@@ -1107,10 +1212,13 @@ def unionize(*args: Type) -> Type:
|
|
|
1107
1212
|
"""
|
|
1108
1213
|
if not args:
|
|
1109
1214
|
return Any
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
return Union[
|
|
1215
|
+
if len(args) == 1:
|
|
1216
|
+
return args[0]
|
|
1217
|
+
# We are bisecting the args list here to avoid hitting the recursion limit
|
|
1218
|
+
# In Python versions >= 3.11, we can simply do `return Union[*args]`
|
|
1219
|
+
midpoint = len(args) // 2
|
|
1220
|
+
first_half, second_half = args[:midpoint], args[midpoint:]
|
|
1221
|
+
return Union[unionize(*first_half), unionize(*second_half)]
|
|
1114
1222
|
|
|
1115
1223
|
|
|
1116
1224
|
def figure_out_type(value: Any) -> types.GenericType:
|
|
@@ -1133,7 +1241,7 @@ def figure_out_type(value: Any) -> types.GenericType:
|
|
|
1133
1241
|
unionize(*(figure_out_type(k) for k in value)),
|
|
1134
1242
|
unionize(*(figure_out_type(v) for v in value.values())),
|
|
1135
1243
|
]
|
|
1136
|
-
if isinstance(value,
|
|
1244
|
+
if isinstance(value, Var):
|
|
1137
1245
|
return value._var_type
|
|
1138
1246
|
return type(value)
|
|
1139
1247
|
|
|
@@ -1156,7 +1264,7 @@ class CachedVarOperation:
|
|
|
1156
1264
|
|
|
1157
1265
|
def __post_init__(self):
|
|
1158
1266
|
"""Post-initialize the CachedVarOperation."""
|
|
1159
|
-
object.__delattr__(self, "
|
|
1267
|
+
object.__delattr__(self, "_js_expr")
|
|
1160
1268
|
|
|
1161
1269
|
def __getattr__(self, name: str) -> Any:
|
|
1162
1270
|
"""Get an attribute of the var.
|
|
@@ -1167,7 +1275,7 @@ class CachedVarOperation:
|
|
|
1167
1275
|
Returns:
|
|
1168
1276
|
The attribute.
|
|
1169
1277
|
"""
|
|
1170
|
-
if name == "
|
|
1278
|
+
if name == "_js_expr":
|
|
1171
1279
|
return self._cached_var_name
|
|
1172
1280
|
|
|
1173
1281
|
parent_classes = inspect.getmro(self.__class__)
|
|
@@ -1194,9 +1302,7 @@ class CachedVarOperation:
|
|
|
1194
1302
|
return VarData.merge(
|
|
1195
1303
|
*map(
|
|
1196
1304
|
lambda value: (
|
|
1197
|
-
value._get_all_var_data()
|
|
1198
|
-
if isinstance(value, ImmutableVar)
|
|
1199
|
-
else None
|
|
1305
|
+
value._get_all_var_data() if isinstance(value, Var) else None
|
|
1200
1306
|
),
|
|
1201
1307
|
map(
|
|
1202
1308
|
lambda field: getattr(self, field.name),
|
|
@@ -1218,13 +1324,13 @@ class CachedVarOperation:
|
|
|
1218
1324
|
*[
|
|
1219
1325
|
getattr(self, field.name)
|
|
1220
1326
|
for field in dataclasses.fields(self) # type: ignore
|
|
1221
|
-
if field.name not in ["
|
|
1327
|
+
if field.name not in ["_js_expr", "_var_data", "_var_type"]
|
|
1222
1328
|
],
|
|
1223
1329
|
)
|
|
1224
1330
|
)
|
|
1225
1331
|
|
|
1226
1332
|
|
|
1227
|
-
def and_operation(a:
|
|
1333
|
+
def and_operation(a: Var | Any, b: Var | Any) -> Var:
|
|
1228
1334
|
"""Perform a logical AND operation on two variables.
|
|
1229
1335
|
|
|
1230
1336
|
Args:
|
|
@@ -1238,7 +1344,7 @@ def and_operation(a: ImmutableVar | Any, b: ImmutableVar | Any) -> ImmutableVar:
|
|
|
1238
1344
|
|
|
1239
1345
|
|
|
1240
1346
|
@var_operation
|
|
1241
|
-
def _and_operation(a:
|
|
1347
|
+
def _and_operation(a: Var, b: Var):
|
|
1242
1348
|
"""Perform a logical AND operation on two variables.
|
|
1243
1349
|
|
|
1244
1350
|
Args:
|
|
@@ -1254,7 +1360,7 @@ def _and_operation(a: ImmutableVar, b: ImmutableVar):
|
|
|
1254
1360
|
)
|
|
1255
1361
|
|
|
1256
1362
|
|
|
1257
|
-
def or_operation(a:
|
|
1363
|
+
def or_operation(a: Var | Any, b: Var | Any) -> Var:
|
|
1258
1364
|
"""Perform a logical OR operation on two variables.
|
|
1259
1365
|
|
|
1260
1366
|
Args:
|
|
@@ -1268,7 +1374,7 @@ def or_operation(a: ImmutableVar | Any, b: ImmutableVar | Any) -> ImmutableVar:
|
|
|
1268
1374
|
|
|
1269
1375
|
|
|
1270
1376
|
@var_operation
|
|
1271
|
-
def _or_operation(a:
|
|
1377
|
+
def _or_operation(a: Var, b: Var):
|
|
1272
1378
|
"""Perform a logical OR operation on two variables.
|
|
1273
1379
|
|
|
1274
1380
|
Args:
|
|
@@ -1289,36 +1395,36 @@ def _or_operation(a: ImmutableVar, b: ImmutableVar):
|
|
|
1289
1395
|
frozen=True,
|
|
1290
1396
|
**{"slots": True} if sys.version_info >= (3, 10) else {},
|
|
1291
1397
|
)
|
|
1292
|
-
class
|
|
1398
|
+
class CallableVar(Var):
|
|
1293
1399
|
"""Decorate a Var-returning function to act as both a Var and a function.
|
|
1294
1400
|
|
|
1295
1401
|
This is used as a compatibility shim for replacing Var objects in the
|
|
1296
1402
|
API with functions that return a family of Var.
|
|
1297
1403
|
"""
|
|
1298
1404
|
|
|
1299
|
-
fn: Callable[...,
|
|
1300
|
-
default_factory=lambda: lambda:
|
|
1405
|
+
fn: Callable[..., Var] = dataclasses.field(
|
|
1406
|
+
default_factory=lambda: lambda: Var(_js_expr="undefined")
|
|
1301
1407
|
)
|
|
1302
|
-
original_var:
|
|
1303
|
-
default_factory=lambda:
|
|
1408
|
+
original_var: Var = dataclasses.field(
|
|
1409
|
+
default_factory=lambda: Var(_js_expr="undefined")
|
|
1304
1410
|
)
|
|
1305
1411
|
|
|
1306
|
-
def __init__(self, fn: Callable[...,
|
|
1412
|
+
def __init__(self, fn: Callable[..., Var]):
|
|
1307
1413
|
"""Initialize a CallableVar.
|
|
1308
1414
|
|
|
1309
1415
|
Args:
|
|
1310
1416
|
fn: The function to decorate (must return Var)
|
|
1311
1417
|
"""
|
|
1312
1418
|
original_var = fn()
|
|
1313
|
-
super(
|
|
1314
|
-
|
|
1419
|
+
super(CallableVar, self).__init__(
|
|
1420
|
+
_js_expr=original_var._js_expr,
|
|
1315
1421
|
_var_type=original_var._var_type,
|
|
1316
1422
|
_var_data=VarData.merge(original_var._get_all_var_data()),
|
|
1317
1423
|
)
|
|
1318
1424
|
object.__setattr__(self, "fn", fn)
|
|
1319
1425
|
object.__setattr__(self, "original_var", original_var)
|
|
1320
1426
|
|
|
1321
|
-
def __call__(self, *args, **kwargs) ->
|
|
1427
|
+
def __call__(self, *args, **kwargs) -> Var:
|
|
1322
1428
|
"""Call the decorated function.
|
|
1323
1429
|
|
|
1324
1430
|
Args:
|
|
@@ -1347,13 +1453,13 @@ DICT_VAL = TypeVar("DICT_VAL")
|
|
|
1347
1453
|
LIST_INSIDE = TypeVar("LIST_INSIDE")
|
|
1348
1454
|
|
|
1349
1455
|
|
|
1350
|
-
class FakeComputedVarBaseClass(
|
|
1456
|
+
class FakeComputedVarBaseClass(property):
|
|
1351
1457
|
"""A fake base class for ComputedVar to avoid inheriting from property."""
|
|
1352
1458
|
|
|
1353
1459
|
__pydantic_run_validation__ = False
|
|
1354
1460
|
|
|
1355
1461
|
|
|
1356
|
-
def is_computed_var(obj: Any) -> TypeGuard[
|
|
1462
|
+
def is_computed_var(obj: Any) -> TypeGuard[ComputedVar]:
|
|
1357
1463
|
"""Check if the object is a ComputedVar.
|
|
1358
1464
|
|
|
1359
1465
|
Args:
|
|
@@ -1370,7 +1476,7 @@ def is_computed_var(obj: Any) -> TypeGuard[ImmutableComputedVar]:
|
|
|
1370
1476
|
frozen=True,
|
|
1371
1477
|
**{"slots": True} if sys.version_info >= (3, 10) else {},
|
|
1372
1478
|
)
|
|
1373
|
-
class
|
|
1479
|
+
class ComputedVar(Var[RETURN_TYPE]):
|
|
1374
1480
|
"""A field with computed getters."""
|
|
1375
1481
|
|
|
1376
1482
|
# Whether to track dependencies and cache computed values
|
|
@@ -1400,7 +1506,7 @@ class ImmutableComputedVar(ImmutableVar[RETURN_TYPE]):
|
|
|
1400
1506
|
fget: Callable[[BASE_STATE], RETURN_TYPE],
|
|
1401
1507
|
initial_value: RETURN_TYPE | types.Unset = types.Unset(),
|
|
1402
1508
|
cache: bool = False,
|
|
1403
|
-
deps: Optional[List[Union[str,
|
|
1509
|
+
deps: Optional[List[Union[str, Var]]] = None,
|
|
1404
1510
|
auto_deps: bool = True,
|
|
1405
1511
|
interval: Optional[Union[int, datetime.timedelta]] = None,
|
|
1406
1512
|
backend: bool | None = None,
|
|
@@ -1424,12 +1530,12 @@ class ImmutableComputedVar(ImmutableVar[RETURN_TYPE]):
|
|
|
1424
1530
|
hints = get_type_hints(fget)
|
|
1425
1531
|
hint = hints.get("return", Any)
|
|
1426
1532
|
|
|
1427
|
-
kwargs["
|
|
1533
|
+
kwargs["_js_expr"] = kwargs.pop("_js_expr", fget.__name__)
|
|
1428
1534
|
kwargs["_var_type"] = kwargs.pop("_var_type", hint)
|
|
1429
1535
|
|
|
1430
|
-
|
|
1536
|
+
Var.__init__(
|
|
1431
1537
|
self,
|
|
1432
|
-
|
|
1538
|
+
_js_expr=kwargs.pop("_js_expr"),
|
|
1433
1539
|
_var_type=kwargs.pop("_var_type"),
|
|
1434
1540
|
_var_data=kwargs.pop("_var_data", None),
|
|
1435
1541
|
)
|
|
@@ -1450,7 +1556,7 @@ class ImmutableComputedVar(ImmutableVar[RETURN_TYPE]):
|
|
|
1450
1556
|
deps = []
|
|
1451
1557
|
else:
|
|
1452
1558
|
for dep in deps:
|
|
1453
|
-
if isinstance(dep,
|
|
1559
|
+
if isinstance(dep, Var):
|
|
1454
1560
|
continue
|
|
1455
1561
|
if isinstance(dep, str) and dep != "":
|
|
1456
1562
|
continue
|
|
@@ -1460,7 +1566,7 @@ class ImmutableComputedVar(ImmutableVar[RETURN_TYPE]):
|
|
|
1460
1566
|
object.__setattr__(
|
|
1461
1567
|
self,
|
|
1462
1568
|
"_static_deps",
|
|
1463
|
-
{dep.
|
|
1569
|
+
{dep._js_expr if isinstance(dep, Var) else dep for dep in deps},
|
|
1464
1570
|
)
|
|
1465
1571
|
object.__setattr__(self, "_auto_deps", auto_deps)
|
|
1466
1572
|
|
|
@@ -1488,7 +1594,7 @@ class ImmutableComputedVar(ImmutableVar[RETURN_TYPE]):
|
|
|
1488
1594
|
auto_deps=kwargs.pop("auto_deps", self._auto_deps),
|
|
1489
1595
|
interval=kwargs.pop("interval", self._update_interval),
|
|
1490
1596
|
backend=kwargs.pop("backend", self._backend),
|
|
1491
|
-
|
|
1597
|
+
_js_expr=kwargs.pop("_js_expr", self._js_expr),
|
|
1492
1598
|
_var_type=kwargs.pop("_var_type", self._var_type),
|
|
1493
1599
|
_var_data=kwargs.pop(
|
|
1494
1600
|
"_var_data", VarData.merge(self._var_data, merge_var_data)
|
|
@@ -1508,7 +1614,7 @@ class ImmutableComputedVar(ImmutableVar[RETURN_TYPE]):
|
|
|
1508
1614
|
Returns:
|
|
1509
1615
|
An attribute name.
|
|
1510
1616
|
"""
|
|
1511
|
-
return f"__cached_{self.
|
|
1617
|
+
return f"__cached_{self._js_expr}"
|
|
1512
1618
|
|
|
1513
1619
|
@property
|
|
1514
1620
|
def _last_updated_attr(self) -> str:
|
|
@@ -1517,7 +1623,7 @@ class ImmutableComputedVar(ImmutableVar[RETURN_TYPE]):
|
|
|
1517
1623
|
Returns:
|
|
1518
1624
|
An attribute name.
|
|
1519
1625
|
"""
|
|
1520
|
-
return f"__last_updated_{self.
|
|
1626
|
+
return f"__last_updated_{self._js_expr}"
|
|
1521
1627
|
|
|
1522
1628
|
def needs_update(self, instance: BaseState) -> bool:
|
|
1523
1629
|
"""Check if the computed var needs to be updated.
|
|
@@ -1537,50 +1643,48 @@ class ImmutableComputedVar(ImmutableVar[RETURN_TYPE]):
|
|
|
1537
1643
|
|
|
1538
1644
|
@overload
|
|
1539
1645
|
def __get__(
|
|
1540
|
-
self:
|
|
1646
|
+
self: ComputedVar[int] | ComputedVar[float],
|
|
1541
1647
|
instance: None,
|
|
1542
1648
|
owner: Type,
|
|
1543
1649
|
) -> NumberVar: ...
|
|
1544
1650
|
|
|
1545
1651
|
@overload
|
|
1546
1652
|
def __get__(
|
|
1547
|
-
self:
|
|
1653
|
+
self: ComputedVar[str],
|
|
1548
1654
|
instance: None,
|
|
1549
1655
|
owner: Type,
|
|
1550
1656
|
) -> StringVar: ...
|
|
1551
1657
|
|
|
1552
1658
|
@overload
|
|
1553
1659
|
def __get__(
|
|
1554
|
-
self:
|
|
1660
|
+
self: ComputedVar[dict[DICT_KEY, DICT_VAL]],
|
|
1555
1661
|
instance: None,
|
|
1556
1662
|
owner: Type,
|
|
1557
1663
|
) -> ObjectVar[dict[DICT_KEY, DICT_VAL]]: ...
|
|
1558
1664
|
|
|
1559
1665
|
@overload
|
|
1560
1666
|
def __get__(
|
|
1561
|
-
self:
|
|
1667
|
+
self: ComputedVar[list[LIST_INSIDE]],
|
|
1562
1668
|
instance: None,
|
|
1563
1669
|
owner: Type,
|
|
1564
1670
|
) -> ArrayVar[list[LIST_INSIDE]]: ...
|
|
1565
1671
|
|
|
1566
1672
|
@overload
|
|
1567
1673
|
def __get__(
|
|
1568
|
-
self:
|
|
1674
|
+
self: ComputedVar[set[LIST_INSIDE]],
|
|
1569
1675
|
instance: None,
|
|
1570
1676
|
owner: Type,
|
|
1571
1677
|
) -> ArrayVar[set[LIST_INSIDE]]: ...
|
|
1572
1678
|
|
|
1573
1679
|
@overload
|
|
1574
1680
|
def __get__(
|
|
1575
|
-
self:
|
|
1681
|
+
self: ComputedVar[tuple[LIST_INSIDE, ...]],
|
|
1576
1682
|
instance: None,
|
|
1577
1683
|
owner: Type,
|
|
1578
1684
|
) -> ArrayVar[tuple[LIST_INSIDE, ...]]: ...
|
|
1579
1685
|
|
|
1580
1686
|
@overload
|
|
1581
|
-
def __get__(
|
|
1582
|
-
self, instance: None, owner: Type
|
|
1583
|
-
) -> ImmutableComputedVar[RETURN_TYPE]: ...
|
|
1687
|
+
def __get__(self, instance: None, owner: Type) -> ComputedVar[RETURN_TYPE]: ...
|
|
1584
1688
|
|
|
1585
1689
|
@overload
|
|
1586
1690
|
def __get__(self, instance: BaseState, owner: Type) -> RETURN_TYPE: ...
|
|
@@ -1599,13 +1703,13 @@ class ImmutableComputedVar(ImmutableVar[RETURN_TYPE]):
|
|
|
1599
1703
|
"""
|
|
1600
1704
|
if instance is None:
|
|
1601
1705
|
state_where_defined = owner
|
|
1602
|
-
while self.
|
|
1706
|
+
while self._js_expr in state_where_defined.inherited_vars:
|
|
1603
1707
|
state_where_defined = state_where_defined.get_parent_state()
|
|
1604
1708
|
|
|
1605
1709
|
return self._replace(
|
|
1606
|
-
|
|
1710
|
+
_js_expr=format_state_name(state_where_defined.get_full_name())
|
|
1607
1711
|
+ "."
|
|
1608
|
-
+ self.
|
|
1712
|
+
+ self._js_expr,
|
|
1609
1713
|
merge_var_data=VarData.from_state(state_where_defined),
|
|
1610
1714
|
).guess_type()
|
|
1611
1715
|
|
|
@@ -1705,7 +1809,7 @@ class ImmutableComputedVar(ImmutableVar[RETURN_TYPE]):
|
|
|
1705
1809
|
)
|
|
1706
1810
|
# recurse into property fget functions
|
|
1707
1811
|
elif isinstance(ref_obj, property) and not isinstance(
|
|
1708
|
-
ref_obj,
|
|
1812
|
+
ref_obj, ComputedVar
|
|
1709
1813
|
):
|
|
1710
1814
|
d.update(
|
|
1711
1815
|
self._deps(
|
|
@@ -1773,7 +1877,7 @@ class ImmutableComputedVar(ImmutableVar[RETURN_TYPE]):
|
|
|
1773
1877
|
return self._fget
|
|
1774
1878
|
|
|
1775
1879
|
|
|
1776
|
-
class DynamicRouteVar(
|
|
1880
|
+
class DynamicRouteVar(ComputedVar[Union[str, List[str]]]):
|
|
1777
1881
|
"""A ComputedVar that represents a dynamic route."""
|
|
1778
1882
|
|
|
1779
1883
|
pass
|
|
@@ -1784,45 +1888,41 @@ if TYPE_CHECKING:
|
|
|
1784
1888
|
|
|
1785
1889
|
|
|
1786
1890
|
@overload
|
|
1787
|
-
def
|
|
1891
|
+
def computed_var(
|
|
1788
1892
|
fget: None = None,
|
|
1789
1893
|
initial_value: Any | types.Unset = types.Unset(),
|
|
1790
1894
|
cache: bool = False,
|
|
1791
|
-
deps: Optional[List[Union[str,
|
|
1895
|
+
deps: Optional[List[Union[str, Var]]] = None,
|
|
1792
1896
|
auto_deps: bool = True,
|
|
1793
1897
|
interval: Optional[Union[datetime.timedelta, int]] = None,
|
|
1794
1898
|
backend: bool | None = None,
|
|
1795
1899
|
**kwargs,
|
|
1796
|
-
) -> Callable[
|
|
1797
|
-
[Callable[[BASE_STATE], RETURN_TYPE]], ImmutableComputedVar[RETURN_TYPE]
|
|
1798
|
-
]: ...
|
|
1900
|
+
) -> Callable[[Callable[[BASE_STATE], RETURN_TYPE]], ComputedVar[RETURN_TYPE]]: ...
|
|
1799
1901
|
|
|
1800
1902
|
|
|
1801
1903
|
@overload
|
|
1802
|
-
def
|
|
1904
|
+
def computed_var(
|
|
1803
1905
|
fget: Callable[[BASE_STATE], RETURN_TYPE],
|
|
1804
1906
|
initial_value: RETURN_TYPE | types.Unset = types.Unset(),
|
|
1805
1907
|
cache: bool = False,
|
|
1806
|
-
deps: Optional[List[Union[str,
|
|
1908
|
+
deps: Optional[List[Union[str, Var]]] = None,
|
|
1807
1909
|
auto_deps: bool = True,
|
|
1808
1910
|
interval: Optional[Union[datetime.timedelta, int]] = None,
|
|
1809
1911
|
backend: bool | None = None,
|
|
1810
1912
|
**kwargs,
|
|
1811
|
-
) ->
|
|
1913
|
+
) -> ComputedVar[RETURN_TYPE]: ...
|
|
1812
1914
|
|
|
1813
1915
|
|
|
1814
|
-
def
|
|
1916
|
+
def computed_var(
|
|
1815
1917
|
fget: Callable[[BASE_STATE], Any] | None = None,
|
|
1816
1918
|
initial_value: Any | types.Unset = types.Unset(),
|
|
1817
1919
|
cache: bool = False,
|
|
1818
|
-
deps: Optional[List[Union[str,
|
|
1920
|
+
deps: Optional[List[Union[str, Var]]] = None,
|
|
1819
1921
|
auto_deps: bool = True,
|
|
1820
1922
|
interval: Optional[Union[datetime.timedelta, int]] = None,
|
|
1821
1923
|
backend: bool | None = None,
|
|
1822
1924
|
**kwargs,
|
|
1823
|
-
) ->
|
|
1824
|
-
ImmutableComputedVar | Callable[[Callable[[BASE_STATE], Any]], ImmutableComputedVar]
|
|
1825
|
-
):
|
|
1925
|
+
) -> ComputedVar | Callable[[Callable[[BASE_STATE], Any]], ComputedVar]:
|
|
1826
1926
|
"""A ComputedVar decorator with or without kwargs.
|
|
1827
1927
|
|
|
1828
1928
|
Args:
|
|
@@ -1849,10 +1949,10 @@ def immutable_computed_var(
|
|
|
1849
1949
|
raise VarDependencyError("Cannot track dependencies without caching.")
|
|
1850
1950
|
|
|
1851
1951
|
if fget is not None:
|
|
1852
|
-
return
|
|
1952
|
+
return ComputedVar(fget, cache=cache)
|
|
1853
1953
|
|
|
1854
|
-
def wrapper(fget: Callable[[BASE_STATE], Any]) ->
|
|
1855
|
-
return
|
|
1954
|
+
def wrapper(fget: Callable[[BASE_STATE], Any]) -> ComputedVar:
|
|
1955
|
+
return ComputedVar(
|
|
1856
1956
|
fget,
|
|
1857
1957
|
initial_value=initial_value,
|
|
1858
1958
|
cache=cache,
|
|
@@ -1869,7 +1969,7 @@ def immutable_computed_var(
|
|
|
1869
1969
|
RETURN = TypeVar("RETURN")
|
|
1870
1970
|
|
|
1871
1971
|
|
|
1872
|
-
class CustomVarOperationReturn(
|
|
1972
|
+
class CustomVarOperationReturn(Var[RETURN]):
|
|
1873
1973
|
"""Base class for custom var operations."""
|
|
1874
1974
|
|
|
1875
1975
|
@classmethod
|
|
@@ -1890,7 +1990,7 @@ class CustomVarOperationReturn(ImmutableVar[RETURN]):
|
|
|
1890
1990
|
The CustomVarOperation.
|
|
1891
1991
|
"""
|
|
1892
1992
|
return CustomVarOperationReturn(
|
|
1893
|
-
|
|
1993
|
+
_js_expr=js_expression,
|
|
1894
1994
|
_var_type=_var_type or Any,
|
|
1895
1995
|
_var_data=_var_data,
|
|
1896
1996
|
)
|
|
@@ -1899,17 +1999,23 @@ class CustomVarOperationReturn(ImmutableVar[RETURN]):
|
|
|
1899
1999
|
def var_operation_return(
|
|
1900
2000
|
js_expression: str,
|
|
1901
2001
|
var_type: Type[RETURN] | None = None,
|
|
2002
|
+
var_data: VarData | None = None,
|
|
1902
2003
|
) -> CustomVarOperationReturn[RETURN]:
|
|
1903
2004
|
"""Shortcut for creating a CustomVarOperationReturn.
|
|
1904
2005
|
|
|
1905
2006
|
Args:
|
|
1906
2007
|
js_expression: The JavaScript expression to evaluate.
|
|
1907
2008
|
var_type: The type of the var.
|
|
2009
|
+
var_data: Additional hooks and imports associated with the Var.
|
|
1908
2010
|
|
|
1909
2011
|
Returns:
|
|
1910
2012
|
The CustomVarOperationReturn.
|
|
1911
2013
|
"""
|
|
1912
|
-
return CustomVarOperationReturn.create(
|
|
2014
|
+
return CustomVarOperationReturn.create(
|
|
2015
|
+
js_expression,
|
|
2016
|
+
var_type,
|
|
2017
|
+
var_data,
|
|
2018
|
+
)
|
|
1913
2019
|
|
|
1914
2020
|
|
|
1915
2021
|
@dataclasses.dataclass(
|
|
@@ -1917,12 +2023,10 @@ def var_operation_return(
|
|
|
1917
2023
|
frozen=True,
|
|
1918
2024
|
**{"slots": True} if sys.version_info >= (3, 10) else {},
|
|
1919
2025
|
)
|
|
1920
|
-
class CustomVarOperation(CachedVarOperation,
|
|
2026
|
+
class CustomVarOperation(CachedVarOperation, Var[T]):
|
|
1921
2027
|
"""Base class for custom var operations."""
|
|
1922
2028
|
|
|
1923
|
-
_args: Tuple[Tuple[str,
|
|
1924
|
-
default_factory=tuple
|
|
1925
|
-
)
|
|
2029
|
+
_args: Tuple[Tuple[str, Var], ...] = dataclasses.field(default_factory=tuple)
|
|
1926
2030
|
|
|
1927
2031
|
_return: CustomVarOperationReturn[T] = dataclasses.field(
|
|
1928
2032
|
default_factory=lambda: CustomVarOperationReturn.create("")
|
|
@@ -1956,7 +2060,7 @@ class CustomVarOperation(CachedVarOperation, ImmutableVar[T]):
|
|
|
1956
2060
|
@classmethod
|
|
1957
2061
|
def create(
|
|
1958
2062
|
cls,
|
|
1959
|
-
args: Tuple[Tuple[str,
|
|
2063
|
+
args: Tuple[Tuple[str, Var], ...],
|
|
1960
2064
|
return_var: CustomVarOperationReturn[T],
|
|
1961
2065
|
_var_data: VarData | None = None,
|
|
1962
2066
|
) -> CustomVarOperation[T]:
|
|
@@ -1971,7 +2075,7 @@ class CustomVarOperation(CachedVarOperation, ImmutableVar[T]):
|
|
|
1971
2075
|
The CustomVarOperation.
|
|
1972
2076
|
"""
|
|
1973
2077
|
return CustomVarOperation(
|
|
1974
|
-
|
|
2078
|
+
_js_expr="",
|
|
1975
2079
|
_var_type=return_var._var_type,
|
|
1976
2080
|
_var_data=_var_data,
|
|
1977
2081
|
_args=args,
|
|
@@ -1979,7 +2083,7 @@ class CustomVarOperation(CachedVarOperation, ImmutableVar[T]):
|
|
|
1979
2083
|
)
|
|
1980
2084
|
|
|
1981
2085
|
|
|
1982
|
-
class NoneVar(
|
|
2086
|
+
class NoneVar(Var[None]):
|
|
1983
2087
|
"""A var representing None."""
|
|
1984
2088
|
|
|
1985
2089
|
|
|
@@ -2008,7 +2112,7 @@ class LiteralNoneVar(LiteralVar, NoneVar):
|
|
|
2008
2112
|
The var.
|
|
2009
2113
|
"""
|
|
2010
2114
|
return LiteralNoneVar(
|
|
2011
|
-
|
|
2115
|
+
_js_expr="null",
|
|
2012
2116
|
_var_type=None,
|
|
2013
2117
|
_var_data=_var_data,
|
|
2014
2118
|
)
|
|
@@ -2051,7 +2155,7 @@ class ToNoneOperation(CachedVarOperation, NoneVar):
|
|
|
2051
2155
|
The ToNoneOperation.
|
|
2052
2156
|
"""
|
|
2053
2157
|
return ToNoneOperation(
|
|
2054
|
-
|
|
2158
|
+
_js_expr="",
|
|
2055
2159
|
_var_type=None,
|
|
2056
2160
|
_var_data=_var_data,
|
|
2057
2161
|
_original_var=var,
|
|
@@ -2063,7 +2167,7 @@ class ToNoneOperation(CachedVarOperation, NoneVar):
|
|
|
2063
2167
|
frozen=True,
|
|
2064
2168
|
**{"slots": True} if sys.version_info >= (3, 10) else {},
|
|
2065
2169
|
)
|
|
2066
|
-
class StateOperation(CachedVarOperation,
|
|
2170
|
+
class StateOperation(CachedVarOperation, Var):
|
|
2067
2171
|
"""A var operation that accesses a field on an object."""
|
|
2068
2172
|
|
|
2069
2173
|
_state_name: str = dataclasses.field(default="")
|
|
@@ -2087,7 +2191,7 @@ class StateOperation(CachedVarOperation, ImmutableVar):
|
|
|
2087
2191
|
Returns:
|
|
2088
2192
|
The attribute.
|
|
2089
2193
|
"""
|
|
2090
|
-
if name == "
|
|
2194
|
+
if name == "_js_expr":
|
|
2091
2195
|
return self._cached_var_name
|
|
2092
2196
|
|
|
2093
2197
|
return getattr(self._field, name)
|
|
@@ -2096,7 +2200,7 @@ class StateOperation(CachedVarOperation, ImmutableVar):
|
|
|
2096
2200
|
def create(
|
|
2097
2201
|
cls,
|
|
2098
2202
|
state_name: str,
|
|
2099
|
-
field:
|
|
2203
|
+
field: Var,
|
|
2100
2204
|
_var_data: VarData | None = None,
|
|
2101
2205
|
) -> StateOperation:
|
|
2102
2206
|
"""Create a DotOperation.
|
|
@@ -2110,7 +2214,7 @@ class StateOperation(CachedVarOperation, ImmutableVar):
|
|
|
2110
2214
|
The DotOperation.
|
|
2111
2215
|
"""
|
|
2112
2216
|
return StateOperation(
|
|
2113
|
-
|
|
2217
|
+
_js_expr="",
|
|
2114
2218
|
_var_type=field._var_type,
|
|
2115
2219
|
_var_data=_var_data,
|
|
2116
2220
|
_state_name=state_name,
|
|
@@ -2134,7 +2238,7 @@ class ToOperation:
|
|
|
2134
2238
|
|
|
2135
2239
|
def __post_init__(self):
|
|
2136
2240
|
"""Post initialization."""
|
|
2137
|
-
object.__delattr__(self, "
|
|
2241
|
+
object.__delattr__(self, "_js_expr")
|
|
2138
2242
|
|
|
2139
2243
|
def __hash__(self) -> int:
|
|
2140
2244
|
"""Calculate the hash value of the object.
|
|
@@ -2173,8 +2277,287 @@ class ToOperation:
|
|
|
2173
2277
|
The ToOperation.
|
|
2174
2278
|
"""
|
|
2175
2279
|
return cls(
|
|
2176
|
-
|
|
2280
|
+
_js_expr="", # type: ignore
|
|
2177
2281
|
_var_data=_var_data, # type: ignore
|
|
2178
2282
|
_var_type=_var_type or cls._default_var_type, # type: ignore
|
|
2179
2283
|
_original=value, # type: ignore
|
|
2180
2284
|
)
|
|
2285
|
+
|
|
2286
|
+
|
|
2287
|
+
def get_uuid_string_var() -> Var:
|
|
2288
|
+
"""Return a Var that generates a single memoized UUID via .web/utils/state.js.
|
|
2289
|
+
|
|
2290
|
+
useMemo with an empty dependency array ensures that the generated UUID is
|
|
2291
|
+
consistent across re-renders of the component.
|
|
2292
|
+
|
|
2293
|
+
Returns:
|
|
2294
|
+
A Var that generates a UUID at runtime.
|
|
2295
|
+
"""
|
|
2296
|
+
from reflex.utils.imports import ImportVar
|
|
2297
|
+
from reflex.vars import Var
|
|
2298
|
+
|
|
2299
|
+
unique_uuid_var = get_unique_variable_name()
|
|
2300
|
+
unique_uuid_var_data = VarData(
|
|
2301
|
+
imports={
|
|
2302
|
+
f"/{constants.Dirs.STATE_PATH}": {ImportVar(tag="generateUUID")}, # type: ignore
|
|
2303
|
+
"react": "useMemo",
|
|
2304
|
+
},
|
|
2305
|
+
hooks={f"const {unique_uuid_var} = useMemo(generateUUID, [])": None},
|
|
2306
|
+
)
|
|
2307
|
+
|
|
2308
|
+
return Var(
|
|
2309
|
+
_js_expr=unique_uuid_var,
|
|
2310
|
+
_var_type=str,
|
|
2311
|
+
_var_data=unique_uuid_var_data,
|
|
2312
|
+
)
|
|
2313
|
+
|
|
2314
|
+
|
|
2315
|
+
# Set of unique variable names.
|
|
2316
|
+
USED_VARIABLES = set()
|
|
2317
|
+
|
|
2318
|
+
|
|
2319
|
+
def get_unique_variable_name() -> str:
|
|
2320
|
+
"""Get a unique variable name.
|
|
2321
|
+
|
|
2322
|
+
Returns:
|
|
2323
|
+
The unique variable name.
|
|
2324
|
+
"""
|
|
2325
|
+
name = "".join([random.choice(string.ascii_lowercase) for _ in range(8)])
|
|
2326
|
+
if name not in USED_VARIABLES:
|
|
2327
|
+
USED_VARIABLES.add(name)
|
|
2328
|
+
return name
|
|
2329
|
+
return get_unique_variable_name()
|
|
2330
|
+
|
|
2331
|
+
|
|
2332
|
+
@dataclasses.dataclass(
|
|
2333
|
+
eq=True,
|
|
2334
|
+
frozen=True,
|
|
2335
|
+
)
|
|
2336
|
+
class VarData:
|
|
2337
|
+
"""Metadata associated with a x."""
|
|
2338
|
+
|
|
2339
|
+
# The name of the enclosing state.
|
|
2340
|
+
state: str = dataclasses.field(default="")
|
|
2341
|
+
|
|
2342
|
+
# Imports needed to render this var
|
|
2343
|
+
imports: ImmutableParsedImportDict = dataclasses.field(default_factory=tuple)
|
|
2344
|
+
|
|
2345
|
+
# Hooks that need to be present in the component to render this var
|
|
2346
|
+
hooks: Tuple[str, ...] = dataclasses.field(default_factory=tuple)
|
|
2347
|
+
|
|
2348
|
+
def __init__(
|
|
2349
|
+
self,
|
|
2350
|
+
state: str = "",
|
|
2351
|
+
imports: ImportDict | ParsedImportDict | None = None,
|
|
2352
|
+
hooks: dict[str, None] | None = None,
|
|
2353
|
+
):
|
|
2354
|
+
"""Initialize the var data.
|
|
2355
|
+
|
|
2356
|
+
Args:
|
|
2357
|
+
state: The name of the enclosing state.
|
|
2358
|
+
imports: Imports needed to render this var.
|
|
2359
|
+
hooks: Hooks that need to be present in the component to render this var.
|
|
2360
|
+
"""
|
|
2361
|
+
immutable_imports: ImmutableParsedImportDict = tuple(
|
|
2362
|
+
sorted(
|
|
2363
|
+
((k, tuple(sorted(v))) for k, v in parse_imports(imports or {}).items())
|
|
2364
|
+
)
|
|
2365
|
+
)
|
|
2366
|
+
object.__setattr__(self, "state", state)
|
|
2367
|
+
object.__setattr__(self, "imports", immutable_imports)
|
|
2368
|
+
object.__setattr__(self, "hooks", tuple(hooks or {}))
|
|
2369
|
+
|
|
2370
|
+
def old_school_imports(self) -> ImportDict:
|
|
2371
|
+
"""Return the imports as a mutable dict.
|
|
2372
|
+
|
|
2373
|
+
Returns:
|
|
2374
|
+
The imports as a mutable dict.
|
|
2375
|
+
"""
|
|
2376
|
+
return dict((k, list(v)) for k, v in self.imports)
|
|
2377
|
+
|
|
2378
|
+
@classmethod
|
|
2379
|
+
def merge(cls, *others: VarData | None) -> VarData | None:
|
|
2380
|
+
"""Merge multiple var data objects.
|
|
2381
|
+
|
|
2382
|
+
Args:
|
|
2383
|
+
*others: The var data objects to merge.
|
|
2384
|
+
|
|
2385
|
+
Returns:
|
|
2386
|
+
The merged var data object.
|
|
2387
|
+
"""
|
|
2388
|
+
state = ""
|
|
2389
|
+
_imports = {}
|
|
2390
|
+
hooks = {}
|
|
2391
|
+
for var_data in others:
|
|
2392
|
+
if var_data is None:
|
|
2393
|
+
continue
|
|
2394
|
+
state = state or var_data.state
|
|
2395
|
+
_imports = imports.merge_imports(_imports, var_data.imports)
|
|
2396
|
+
hooks.update(
|
|
2397
|
+
var_data.hooks
|
|
2398
|
+
if isinstance(var_data.hooks, dict)
|
|
2399
|
+
else {k: None for k in var_data.hooks}
|
|
2400
|
+
)
|
|
2401
|
+
|
|
2402
|
+
if state or _imports or hooks:
|
|
2403
|
+
return VarData(
|
|
2404
|
+
state=state,
|
|
2405
|
+
imports=_imports,
|
|
2406
|
+
hooks=hooks,
|
|
2407
|
+
)
|
|
2408
|
+
return None
|
|
2409
|
+
|
|
2410
|
+
def __bool__(self) -> bool:
|
|
2411
|
+
"""Check if the var data is non-empty.
|
|
2412
|
+
|
|
2413
|
+
Returns:
|
|
2414
|
+
True if any field is set to a non-default value.
|
|
2415
|
+
"""
|
|
2416
|
+
return bool(self.state or self.imports or self.hooks)
|
|
2417
|
+
|
|
2418
|
+
def __eq__(self, other: Any) -> bool:
|
|
2419
|
+
"""Check if two var data objects are equal.
|
|
2420
|
+
|
|
2421
|
+
Args:
|
|
2422
|
+
other: The other var data object to compare.
|
|
2423
|
+
|
|
2424
|
+
Returns:
|
|
2425
|
+
True if all fields are equal and collapsed imports are equal.
|
|
2426
|
+
"""
|
|
2427
|
+
if not isinstance(other, VarData):
|
|
2428
|
+
return False
|
|
2429
|
+
|
|
2430
|
+
# Don't compare interpolations - that's added in by the decoder, and
|
|
2431
|
+
# not part of the vardata itself.
|
|
2432
|
+
return (
|
|
2433
|
+
self.state == other.state
|
|
2434
|
+
and self.hooks
|
|
2435
|
+
== (
|
|
2436
|
+
other.hooks if isinstance(other, VarData) else tuple(other.hooks.keys())
|
|
2437
|
+
)
|
|
2438
|
+
and imports.collapse_imports(self.imports)
|
|
2439
|
+
== imports.collapse_imports(other.imports)
|
|
2440
|
+
)
|
|
2441
|
+
|
|
2442
|
+
@classmethod
|
|
2443
|
+
def from_state(cls, state: Type[BaseState] | str) -> VarData:
|
|
2444
|
+
"""Set the state of the var.
|
|
2445
|
+
|
|
2446
|
+
Args:
|
|
2447
|
+
state: The state to set or the full name of the state.
|
|
2448
|
+
|
|
2449
|
+
Returns:
|
|
2450
|
+
The var with the set state.
|
|
2451
|
+
"""
|
|
2452
|
+
from reflex.utils import format
|
|
2453
|
+
|
|
2454
|
+
state_name = state if isinstance(state, str) else state.get_full_name()
|
|
2455
|
+
new_var_data = VarData(
|
|
2456
|
+
state=state_name,
|
|
2457
|
+
hooks={
|
|
2458
|
+
"const {0} = useContext(StateContexts.{0})".format(
|
|
2459
|
+
format.format_state_name(state_name)
|
|
2460
|
+
): None
|
|
2461
|
+
},
|
|
2462
|
+
imports={
|
|
2463
|
+
f"/{constants.Dirs.CONTEXTS_PATH}": [ImportVar(tag="StateContexts")],
|
|
2464
|
+
"react": [ImportVar(tag="useContext")],
|
|
2465
|
+
},
|
|
2466
|
+
)
|
|
2467
|
+
return new_var_data
|
|
2468
|
+
|
|
2469
|
+
|
|
2470
|
+
def _decode_var_immutable(value: str) -> tuple[VarData | None, str]:
|
|
2471
|
+
"""Decode the state name from a formatted var.
|
|
2472
|
+
|
|
2473
|
+
Args:
|
|
2474
|
+
value: The value to extract the state name from.
|
|
2475
|
+
|
|
2476
|
+
Returns:
|
|
2477
|
+
The extracted state name and the value without the state name.
|
|
2478
|
+
"""
|
|
2479
|
+
var_datas = []
|
|
2480
|
+
if isinstance(value, str):
|
|
2481
|
+
# fast path if there is no encoded VarData
|
|
2482
|
+
if constants.REFLEX_VAR_OPENING_TAG not in value:
|
|
2483
|
+
return None, value
|
|
2484
|
+
|
|
2485
|
+
offset = 0
|
|
2486
|
+
|
|
2487
|
+
# Find all tags.
|
|
2488
|
+
while m := _decode_var_pattern.search(value):
|
|
2489
|
+
start, end = m.span()
|
|
2490
|
+
value = value[:start] + value[end:]
|
|
2491
|
+
|
|
2492
|
+
serialized_data = m.group(1)
|
|
2493
|
+
|
|
2494
|
+
if serialized_data.isnumeric() or (
|
|
2495
|
+
serialized_data[0] == "-" and serialized_data[1:].isnumeric()
|
|
2496
|
+
):
|
|
2497
|
+
# This is a global immutable var.
|
|
2498
|
+
var = _global_vars[int(serialized_data)]
|
|
2499
|
+
var_data = var._get_all_var_data()
|
|
2500
|
+
|
|
2501
|
+
if var_data is not None:
|
|
2502
|
+
var_datas.append(var_data)
|
|
2503
|
+
offset += end - start
|
|
2504
|
+
|
|
2505
|
+
return VarData.merge(*var_datas) if var_datas else None, value
|
|
2506
|
+
|
|
2507
|
+
|
|
2508
|
+
# Compile regex for finding reflex var tags.
|
|
2509
|
+
_decode_var_pattern_re = (
|
|
2510
|
+
rf"{constants.REFLEX_VAR_OPENING_TAG}(.*?){constants.REFLEX_VAR_CLOSING_TAG}"
|
|
2511
|
+
)
|
|
2512
|
+
_decode_var_pattern = re.compile(_decode_var_pattern_re, flags=re.DOTALL)
|
|
2513
|
+
|
|
2514
|
+
# Defined global immutable vars.
|
|
2515
|
+
_global_vars: Dict[int, Var] = {}
|
|
2516
|
+
|
|
2517
|
+
|
|
2518
|
+
def _extract_var_data(value: Iterable) -> list[VarData | None]:
|
|
2519
|
+
"""Extract the var imports and hooks from an iterable containing a Var.
|
|
2520
|
+
|
|
2521
|
+
Args:
|
|
2522
|
+
value: The iterable to extract the VarData from
|
|
2523
|
+
|
|
2524
|
+
Returns:
|
|
2525
|
+
The extracted VarDatas.
|
|
2526
|
+
"""
|
|
2527
|
+
from reflex.style import Style
|
|
2528
|
+
from reflex.vars import Var
|
|
2529
|
+
|
|
2530
|
+
var_datas = []
|
|
2531
|
+
with contextlib.suppress(TypeError):
|
|
2532
|
+
for sub in value:
|
|
2533
|
+
if isinstance(sub, Var):
|
|
2534
|
+
var_datas.append(sub._var_data)
|
|
2535
|
+
elif not isinstance(sub, str):
|
|
2536
|
+
# Recurse into dict values.
|
|
2537
|
+
if hasattr(sub, "values") and callable(sub.values):
|
|
2538
|
+
var_datas.extend(_extract_var_data(sub.values()))
|
|
2539
|
+
# Recurse into iterable values (or dict keys).
|
|
2540
|
+
var_datas.extend(_extract_var_data(sub))
|
|
2541
|
+
|
|
2542
|
+
# Style objects should already have _var_data.
|
|
2543
|
+
if isinstance(value, Style):
|
|
2544
|
+
var_datas.append(value._var_data)
|
|
2545
|
+
else:
|
|
2546
|
+
# Recurse when value is a dict itself.
|
|
2547
|
+
values = getattr(value, "values", None)
|
|
2548
|
+
if callable(values):
|
|
2549
|
+
var_datas.extend(_extract_var_data(values()))
|
|
2550
|
+
return var_datas
|
|
2551
|
+
|
|
2552
|
+
|
|
2553
|
+
# These names were changed in reflex 0.3.0
|
|
2554
|
+
REPLACED_NAMES = {
|
|
2555
|
+
"full_name": "_var_full_name",
|
|
2556
|
+
"name": "_js_expr",
|
|
2557
|
+
"state": "_var_data.state",
|
|
2558
|
+
"type_": "_var_type",
|
|
2559
|
+
"is_local": "_var_is_local",
|
|
2560
|
+
"is_string": "_var_is_string",
|
|
2561
|
+
"set_state": "_var_set_state",
|
|
2562
|
+
"deps": "_deps",
|
|
2563
|
+
}
|