reflex 0.6.4a2__py3-none-any.whl → 0.6.5__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/web/pages/custom_component.js.jinja2 +0 -14
- reflex/.templates/jinja/web/pages/utils.js.jinja2 +4 -8
- reflex/.templates/web/components/shiki/code.js +16 -11
- reflex/.templates/web/utils/state.js +29 -21
- reflex/__init__.py +4 -0
- reflex/__init__.pyi +4 -0
- reflex/app.py +148 -154
- reflex/app_mixins/lifespan.py +5 -1
- reflex/app_mixins/middleware.py +3 -1
- reflex/app_mixins/mixin.py +3 -2
- reflex/base.py +2 -4
- reflex/compiler/compiler.py +111 -37
- reflex/components/base/app_wrap.pyi +17 -17
- reflex/components/base/bare.py +72 -3
- reflex/components/base/body.pyi +17 -17
- reflex/components/base/document.pyi +81 -81
- reflex/components/base/error_boundary.pyi +25 -18
- reflex/components/base/fragment.pyi +17 -17
- reflex/components/base/head.pyi +33 -33
- reflex/components/base/link.pyi +33 -33
- reflex/components/base/meta.pyi +65 -65
- reflex/components/base/script.py +4 -4
- reflex/components/base/script.pyi +23 -20
- reflex/components/component.py +250 -31
- reflex/components/core/banner.py +1 -1
- reflex/components/core/banner.pyi +81 -81
- reflex/components/core/client_side_routing.pyi +33 -33
- reflex/components/core/clipboard.py +2 -2
- reflex/components/core/clipboard.pyi +24 -18
- reflex/components/core/debounce.py +2 -2
- reflex/components/core/debounce.pyi +18 -18
- reflex/components/core/html.pyi +17 -17
- reflex/components/core/upload.py +90 -28
- reflex/components/core/upload.pyi +128 -72
- reflex/components/datadisplay/code.py +55 -40
- reflex/components/datadisplay/code.pyi +46 -44
- reflex/components/datadisplay/dataeditor.py +21 -20
- reflex/components/datadisplay/dataeditor.pyi +103 -35
- reflex/components/datadisplay/shiki_code_block.py +60 -27
- reflex/components/datadisplay/shiki_code_block.pyi +86 -65
- reflex/components/dynamic.py +9 -5
- reflex/components/el/element.pyi +17 -17
- reflex/components/el/elements/base.pyi +17 -17
- reflex/components/el/elements/forms.py +12 -3
- reflex/components/el/elements/forms.pyi +293 -233
- reflex/components/el/elements/inline.pyi +449 -449
- reflex/components/el/elements/media.pyi +401 -401
- reflex/components/el/elements/metadata.pyi +97 -97
- reflex/components/el/elements/other.pyi +113 -113
- reflex/components/el/elements/scripts.pyi +49 -49
- reflex/components/el/elements/sectioning.pyi +241 -241
- reflex/components/el/elements/tables.pyi +161 -161
- reflex/components/el/elements/typography.pyi +241 -241
- reflex/components/gridjs/datatable.pyi +33 -33
- reflex/components/lucide/icon.py +1 -1
- reflex/components/lucide/icon.pyi +33 -33
- reflex/components/markdown/markdown.py +180 -49
- reflex/components/markdown/markdown.pyi +36 -19
- reflex/components/moment/moment.py +17 -21
- reflex/components/moment/moment.pyi +26 -21
- reflex/components/next/base.pyi +17 -17
- reflex/components/next/image.py +3 -3
- reflex/components/next/image.pyi +21 -19
- reflex/components/next/link.pyi +17 -17
- reflex/components/next/video.pyi +17 -17
- reflex/components/plotly/plotly.py +79 -78
- reflex/components/plotly/plotly.pyi +91 -41
- reflex/components/props.py +34 -0
- reflex/components/radix/primitives/accordion.py +15 -8
- reflex/components/radix/primitives/accordion.pyi +121 -118
- reflex/components/radix/primitives/base.pyi +33 -33
- reflex/components/radix/primitives/drawer.py +41 -20
- reflex/components/radix/primitives/drawer.pyi +279 -190
- reflex/components/radix/primitives/form.py +2 -2
- reflex/components/radix/primitives/form.pyi +200 -167
- reflex/components/radix/primitives/progress.pyi +81 -81
- reflex/components/radix/primitives/slider.pyi +89 -83
- reflex/components/radix/themes/base.py +30 -1
- reflex/components/radix/themes/base.pyi +286 -113
- reflex/components/radix/themes/color_mode.py +17 -9
- reflex/components/radix/themes/color_mode.pyi +68 -56
- reflex/components/radix/themes/components/alert_dialog.py +8 -5
- reflex/components/radix/themes/components/alert_dialog.pyi +125 -117
- reflex/components/radix/themes/components/aspect_ratio.pyi +17 -17
- reflex/components/radix/themes/components/avatar.py +1 -5
- reflex/components/radix/themes/components/avatar.pyi +17 -17
- reflex/components/radix/themes/components/badge.py +1 -5
- reflex/components/radix/themes/components/badge.pyi +17 -17
- reflex/components/radix/themes/components/button.pyi +18 -21
- reflex/components/radix/themes/components/callout.py +1 -4
- reflex/components/radix/themes/components/callout.pyi +81 -81
- reflex/components/radix/themes/components/card.py +1 -3
- reflex/components/radix/themes/components/card.pyi +17 -17
- reflex/components/radix/themes/components/checkbox.py +4 -8
- reflex/components/radix/themes/components/checkbox.pyi +61 -52
- reflex/components/radix/themes/components/checkbox_cards.pyi +33 -33
- reflex/components/radix/themes/components/checkbox_group.pyi +33 -33
- reflex/components/radix/themes/components/context_menu.py +121 -28
- reflex/components/radix/themes/components/context_menu.pyi +250 -147
- reflex/components/radix/themes/components/data_list.pyi +65 -65
- reflex/components/radix/themes/components/dialog.py +11 -11
- reflex/components/radix/themes/components/dialog.pyi +135 -120
- reflex/components/radix/themes/components/dropdown_menu.py +14 -25
- reflex/components/radix/themes/components/dropdown_menu.pyi +157 -145
- reflex/components/radix/themes/components/hover_card.py +19 -7
- reflex/components/radix/themes/components/hover_card.pyi +102 -67
- reflex/components/radix/themes/components/icon_button.pyi +18 -21
- reflex/components/radix/themes/components/inset.py +1 -3
- reflex/components/radix/themes/components/inset.pyi +17 -17
- reflex/components/radix/themes/components/popover.py +22 -13
- reflex/components/radix/themes/components/popover.pyi +98 -72
- reflex/components/radix/themes/components/progress.pyi +17 -17
- reflex/components/radix/themes/components/radio.pyi +17 -17
- reflex/components/radix/themes/components/radio_cards.py +2 -2
- reflex/components/radix/themes/components/radio_cards.pyi +37 -34
- reflex/components/radix/themes/components/radio_group.py +3 -7
- reflex/components/radix/themes/components/radio_group.pyi +69 -66
- reflex/components/radix/themes/components/scroll_area.py +1 -3
- reflex/components/radix/themes/components/scroll_area.pyi +17 -17
- reflex/components/radix/themes/components/segmented_control.pyi +37 -34
- reflex/components/radix/themes/components/select.py +7 -11
- reflex/components/radix/themes/components/select.pyi +175 -154
- reflex/components/radix/themes/components/separator.py +1 -4
- reflex/components/radix/themes/components/separator.pyi +17 -17
- reflex/components/radix/themes/components/skeleton.pyi +17 -17
- reflex/components/radix/themes/components/slider.py +12 -21
- reflex/components/radix/themes/components/slider.pyi +47 -25
- reflex/components/radix/themes/components/spinner.py +1 -4
- reflex/components/radix/themes/components/spinner.pyi +17 -17
- reflex/components/radix/themes/components/switch.py +3 -6
- reflex/components/radix/themes/components/switch.pyi +21 -18
- reflex/components/radix/themes/components/table.py +21 -5
- reflex/components/radix/themes/components/table.pyi +392 -116
- reflex/components/radix/themes/components/tabs.py +3 -6
- reflex/components/radix/themes/components/tabs.pyi +89 -83
- reflex/components/radix/themes/components/text_area.py +1 -5
- reflex/components/radix/themes/components/text_area.pyi +43 -20
- reflex/components/radix/themes/components/text_field.py +1 -5
- reflex/components/radix/themes/components/text_field.pyi +101 -55
- reflex/components/radix/themes/components/tooltip.py +5 -7
- reflex/components/radix/themes/components/tooltip.pyi +25 -22
- reflex/components/radix/themes/layout/base.py +2 -27
- reflex/components/radix/themes/layout/base.pyi +82 -82
- reflex/components/radix/themes/layout/box.pyi +17 -17
- reflex/components/radix/themes/layout/center.pyi +17 -17
- reflex/components/radix/themes/layout/container.pyi +17 -17
- reflex/components/radix/themes/layout/flex.py +1 -6
- reflex/components/radix/themes/layout/flex.pyi +17 -17
- reflex/components/radix/themes/layout/grid.py +1 -6
- reflex/components/radix/themes/layout/grid.pyi +17 -17
- reflex/components/radix/themes/layout/list.py +20 -15
- reflex/components/radix/themes/layout/list.pyi +175 -92
- reflex/components/radix/themes/layout/section.pyi +17 -17
- reflex/components/radix/themes/layout/spacer.pyi +17 -17
- reflex/components/radix/themes/layout/stack.py +6 -6
- reflex/components/radix/themes/layout/stack.pyi +91 -62
- reflex/components/radix/themes/typography/blockquote.py +2 -8
- reflex/components/radix/themes/typography/blockquote.pyi +17 -17
- reflex/components/radix/themes/typography/code.py +4 -10
- reflex/components/radix/themes/typography/code.pyi +19 -18
- reflex/components/radix/themes/typography/heading.py +4 -11
- reflex/components/radix/themes/typography/heading.pyi +19 -18
- reflex/components/radix/themes/typography/link.py +4 -10
- reflex/components/radix/themes/typography/link.pyi +19 -18
- reflex/components/radix/themes/typography/text.py +4 -11
- reflex/components/radix/themes/typography/text.pyi +115 -114
- reflex/components/react_player/audio.pyi +58 -33
- reflex/components/react_player/react_player.py +17 -17
- reflex/components/react_player/react_player.pyi +55 -33
- reflex/components/react_player/video.pyi +58 -33
- reflex/components/recharts/cartesian.py +45 -45
- reflex/components/recharts/cartesian.pyi +389 -304
- reflex/components/recharts/charts.py +22 -22
- reflex/components/recharts/charts.pyi +226 -179
- reflex/components/recharts/general.py +26 -27
- reflex/components/recharts/general.pyi +106 -99
- reflex/components/recharts/polar.py +33 -33
- reflex/components/recharts/polar.pyi +70 -64
- reflex/components/recharts/recharts.pyi +33 -33
- reflex/components/sonner/toast.py +9 -36
- reflex/components/sonner/toast.pyi +20 -24
- reflex/components/suneditor/editor.py +8 -8
- reflex/components/suneditor/editor.pyi +50 -25
- reflex/components/tags/iter_tag.py +1 -10
- reflex/components/tags/tag.py +1 -4
- reflex/config.py +252 -41
- reflex/constants/__init__.py +4 -16
- reflex/constants/base.py +7 -14
- reflex/constants/colors.py +0 -1
- reflex/constants/installer.py +12 -7
- reflex/constants/state.py +4 -0
- reflex/custom_components/custom_components.py +6 -6
- reflex/event.py +486 -241
- reflex/experimental/client_state.py +9 -9
- reflex/experimental/layout.py +2 -2
- reflex/experimental/layout.pyi +95 -87
- reflex/experimental/misc.py +1 -1
- reflex/istate/__init__.py +1 -0
- reflex/istate/proxy.py +33 -0
- reflex/istate/wrappers.py +27 -0
- reflex/model.py +7 -7
- reflex/page.py +2 -1
- reflex/reflex.py +142 -8
- reflex/state.py +133 -46
- reflex/testing.py +9 -7
- reflex/utils/console.py +0 -1
- reflex/utils/exceptions.py +31 -3
- reflex/utils/exec.py +33 -14
- reflex/utils/format.py +15 -12
- reflex/utils/net.py +1 -1
- reflex/utils/path_ops.py +2 -2
- reflex/utils/prerequisites.py +82 -46
- reflex/utils/pyi_generator.py +63 -20
- reflex/utils/registry.py +1 -1
- reflex/utils/serializers.py +75 -36
- reflex/utils/telemetry.py +3 -2
- reflex/utils/types.py +125 -10
- reflex/vars/base.py +131 -119
- reflex/vars/function.py +59 -12
- reflex/vars/number.py +3 -1
- reflex/vars/object.py +30 -24
- reflex/vars/sequence.py +7 -7
- {reflex-0.6.4a2.dist-info → reflex-0.6.5.dist-info}/METADATA +3 -3
- reflex-0.6.5.dist-info/RECORD +394 -0
- reflex-0.6.4a2.dist-info/RECORD +0 -391
- {reflex-0.6.4a2.dist-info → reflex-0.6.5.dist-info}/LICENSE +0 -0
- {reflex-0.6.4a2.dist-info → reflex-0.6.5.dist-info}/WHEEL +0 -0
- {reflex-0.6.4a2.dist-info → reflex-0.6.5.dist-info}/entry_points.txt +0 -0
reflex/vars/base.py
CHANGED
|
@@ -38,13 +38,7 @@ from typing import (
|
|
|
38
38
|
overload,
|
|
39
39
|
)
|
|
40
40
|
|
|
41
|
-
from typing_extensions import
|
|
42
|
-
ParamSpec,
|
|
43
|
-
TypeGuard,
|
|
44
|
-
deprecated,
|
|
45
|
-
get_type_hints,
|
|
46
|
-
override,
|
|
47
|
-
)
|
|
41
|
+
from typing_extensions import ParamSpec, TypeGuard, deprecated, get_type_hints, override
|
|
48
42
|
|
|
49
43
|
from reflex import constants
|
|
50
44
|
from reflex.base import Base
|
|
@@ -63,16 +57,19 @@ from reflex.utils.imports import (
|
|
|
63
57
|
ParsedImportDict,
|
|
64
58
|
parse_imports,
|
|
65
59
|
)
|
|
66
|
-
from reflex.utils.types import
|
|
60
|
+
from reflex.utils.types import (
|
|
61
|
+
GenericType,
|
|
62
|
+
Self,
|
|
63
|
+
_isinstance,
|
|
64
|
+
get_origin,
|
|
65
|
+
has_args,
|
|
66
|
+
unionize,
|
|
67
|
+
)
|
|
67
68
|
|
|
68
69
|
if TYPE_CHECKING:
|
|
69
70
|
from reflex.state import BaseState
|
|
70
71
|
|
|
71
|
-
from .
|
|
72
|
-
from .number import (
|
|
73
|
-
BooleanVar,
|
|
74
|
-
NumberVar,
|
|
75
|
-
)
|
|
72
|
+
from .number import BooleanVar, NumberVar
|
|
76
73
|
from .object import ObjectVar
|
|
77
74
|
from .sequence import ArrayVar, StringVar
|
|
78
75
|
|
|
@@ -151,31 +148,41 @@ class VarData:
|
|
|
151
148
|
"""
|
|
152
149
|
return dict((k, list(v)) for k, v in self.imports)
|
|
153
150
|
|
|
154
|
-
|
|
155
|
-
def merge(cls, *others: VarData | None) -> VarData | None:
|
|
151
|
+
def merge(*all: VarData | None) -> VarData | None:
|
|
156
152
|
"""Merge multiple var data objects.
|
|
157
153
|
|
|
158
154
|
Args:
|
|
159
|
-
*
|
|
155
|
+
*all: The var data objects to merge.
|
|
160
156
|
|
|
161
157
|
Returns:
|
|
162
158
|
The merged var data object.
|
|
159
|
+
|
|
160
|
+
# noqa: DAR102 *all
|
|
163
161
|
"""
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
162
|
+
all_var_datas = list(filter(None, all))
|
|
163
|
+
|
|
164
|
+
if not all_var_datas:
|
|
165
|
+
return None
|
|
166
|
+
|
|
167
|
+
if len(all_var_datas) == 1:
|
|
168
|
+
return all_var_datas[0]
|
|
169
|
+
|
|
170
|
+
# Get the first non-empty field name or default to empty string.
|
|
171
|
+
field_name = next(
|
|
172
|
+
(var_data.field_name for var_data in all_var_datas if var_data.field_name),
|
|
173
|
+
"",
|
|
174
|
+
)
|
|
175
|
+
|
|
176
|
+
# Get the first non-empty state or default to empty string.
|
|
177
|
+
state = next(
|
|
178
|
+
(var_data.state for var_data in all_var_datas if var_data.state), ""
|
|
179
|
+
)
|
|
180
|
+
|
|
181
|
+
hooks = {hook: None for var_data in all_var_datas for hook in var_data.hooks}
|
|
182
|
+
|
|
183
|
+
_imports = imports.merge_imports(
|
|
184
|
+
*(var_data.imports for var_data in all_var_datas)
|
|
185
|
+
)
|
|
179
186
|
|
|
180
187
|
if state or _imports or hooks or field_name:
|
|
181
188
|
return VarData(
|
|
@@ -184,6 +191,7 @@ class VarData:
|
|
|
184
191
|
imports=_imports,
|
|
185
192
|
hooks=hooks,
|
|
186
193
|
)
|
|
194
|
+
|
|
187
195
|
return None
|
|
188
196
|
|
|
189
197
|
def __bool__(self) -> bool:
|
|
@@ -261,6 +269,24 @@ def _decode_var_immutable(value: str) -> tuple[VarData | None, str]:
|
|
|
261
269
|
return VarData.merge(*var_datas) if var_datas else None, value
|
|
262
270
|
|
|
263
271
|
|
|
272
|
+
def can_use_in_object_var(cls: GenericType) -> bool:
|
|
273
|
+
"""Check if the class can be used in an ObjectVar.
|
|
274
|
+
|
|
275
|
+
Args:
|
|
276
|
+
cls: The class to check.
|
|
277
|
+
|
|
278
|
+
Returns:
|
|
279
|
+
Whether the class can be used in an ObjectVar.
|
|
280
|
+
"""
|
|
281
|
+
if types.is_union(cls):
|
|
282
|
+
return all(can_use_in_object_var(t) for t in types.get_args(cls))
|
|
283
|
+
return (
|
|
284
|
+
inspect.isclass(cls)
|
|
285
|
+
and not issubclass(cls, Var)
|
|
286
|
+
and serializers.can_serialize(cls, dict)
|
|
287
|
+
)
|
|
288
|
+
|
|
289
|
+
|
|
264
290
|
@dataclasses.dataclass(
|
|
265
291
|
eq=False,
|
|
266
292
|
frozen=True,
|
|
@@ -547,36 +573,33 @@ class Var(Generic[VAR_TYPE]):
|
|
|
547
573
|
# Encode the _var_data into the formatted output for tracking purposes.
|
|
548
574
|
return f"{constants.REFLEX_VAR_OPENING_TAG}{hashed_var}{constants.REFLEX_VAR_CLOSING_TAG}{self._js_expr}"
|
|
549
575
|
|
|
550
|
-
@overload
|
|
551
|
-
def to(self, output: Type[StringVar]) -> StringVar: ...
|
|
552
|
-
|
|
553
576
|
@overload
|
|
554
577
|
def to(self, output: Type[str]) -> StringVar: ...
|
|
555
578
|
|
|
556
579
|
@overload
|
|
557
|
-
def to(self, output: Type[
|
|
580
|
+
def to(self, output: Type[bool]) -> BooleanVar: ...
|
|
558
581
|
|
|
559
582
|
@overload
|
|
560
|
-
def to(
|
|
561
|
-
self, output: Type[NumberVar], var_type: type[int] | type[float] = float
|
|
562
|
-
) -> NumberVar: ...
|
|
583
|
+
def to(self, output: type[int] | type[float]) -> NumberVar: ...
|
|
563
584
|
|
|
564
585
|
@overload
|
|
565
586
|
def to(
|
|
566
587
|
self,
|
|
567
|
-
output:
|
|
568
|
-
var_type: type[list] | type[tuple] | type[set] = list,
|
|
588
|
+
output: type[list] | type[tuple] | type[set],
|
|
569
589
|
) -> ArrayVar: ...
|
|
570
590
|
|
|
571
591
|
@overload
|
|
572
592
|
def to(
|
|
573
|
-
self, output: Type[ObjectVar], var_type:
|
|
574
|
-
) -> ObjectVar: ...
|
|
593
|
+
self, output: Type[ObjectVar], var_type: Type[VAR_INSIDE]
|
|
594
|
+
) -> ObjectVar[VAR_INSIDE]: ...
|
|
575
595
|
|
|
576
596
|
@overload
|
|
577
597
|
def to(
|
|
578
|
-
self, output: Type[
|
|
579
|
-
) ->
|
|
598
|
+
self, output: Type[ObjectVar], var_type: None = None
|
|
599
|
+
) -> ObjectVar[VAR_TYPE]: ...
|
|
600
|
+
|
|
601
|
+
@overload
|
|
602
|
+
def to(self, output: VAR_SUBCLASS, var_type: None = None) -> VAR_SUBCLASS: ...
|
|
580
603
|
|
|
581
604
|
@overload
|
|
582
605
|
def to(
|
|
@@ -601,10 +624,6 @@ class Var(Generic[VAR_TYPE]):
|
|
|
601
624
|
"""
|
|
602
625
|
from .object import ObjectVar
|
|
603
626
|
|
|
604
|
-
base_type = var_type
|
|
605
|
-
if types.is_optional(base_type):
|
|
606
|
-
base_type = types.get_args(base_type)[0]
|
|
607
|
-
|
|
608
627
|
fixed_output_type = get_origin(output) or output
|
|
609
628
|
|
|
610
629
|
# If the first argument is a python type, we map it to the corresponding Var type.
|
|
@@ -616,21 +635,19 @@ class Var(Generic[VAR_TYPE]):
|
|
|
616
635
|
return get_to_operation(NoneVar).create(self) # type: ignore
|
|
617
636
|
|
|
618
637
|
# Handle fixed_output_type being Base or a dataclass.
|
|
619
|
-
|
|
620
|
-
if issubclass(fixed_output_type, Base):
|
|
621
|
-
return self.to(ObjectVar, output)
|
|
622
|
-
except TypeError:
|
|
623
|
-
pass
|
|
624
|
-
if dataclasses.is_dataclass(fixed_output_type) and not issubclass(
|
|
625
|
-
fixed_output_type, Var
|
|
626
|
-
):
|
|
638
|
+
if can_use_in_object_var(fixed_output_type):
|
|
627
639
|
return self.to(ObjectVar, output)
|
|
628
640
|
|
|
629
641
|
if inspect.isclass(output):
|
|
630
642
|
for var_subclass in _var_subclasses[::-1]:
|
|
631
643
|
if issubclass(output, var_subclass.var_subclass):
|
|
644
|
+
current_var_type = self._var_type
|
|
645
|
+
if current_var_type is Any:
|
|
646
|
+
new_var_type = var_type
|
|
647
|
+
else:
|
|
648
|
+
new_var_type = var_type or current_var_type
|
|
632
649
|
to_operation_return = var_subclass.to_var_subclass.create(
|
|
633
|
-
value=self, _var_type=
|
|
650
|
+
value=self, _var_type=new_var_type
|
|
634
651
|
)
|
|
635
652
|
return to_operation_return # type: ignore
|
|
636
653
|
|
|
@@ -693,11 +710,7 @@ class Var(Generic[VAR_TYPE]):
|
|
|
693
710
|
):
|
|
694
711
|
return self.to(NumberVar, self._var_type)
|
|
695
712
|
|
|
696
|
-
if
|
|
697
|
-
inspect.isclass(t)
|
|
698
|
-
and (issubclass(t, Base) or dataclasses.is_dataclass(t))
|
|
699
|
-
for t in inner_types
|
|
700
|
-
):
|
|
713
|
+
if can_use_in_object_var(var_type):
|
|
701
714
|
return self.to(ObjectVar, self._var_type)
|
|
702
715
|
|
|
703
716
|
return self
|
|
@@ -716,16 +729,12 @@ class Var(Generic[VAR_TYPE]):
|
|
|
716
729
|
if issubclass(fixed_type, var_subclass.python_types):
|
|
717
730
|
return self.to(var_subclass.var_subclass, self._var_type)
|
|
718
731
|
|
|
719
|
-
|
|
720
|
-
if issubclass(fixed_type, Base):
|
|
721
|
-
return self.to(ObjectVar, self._var_type)
|
|
722
|
-
except TypeError:
|
|
723
|
-
pass
|
|
724
|
-
if dataclasses.is_dataclass(fixed_type):
|
|
732
|
+
if can_use_in_object_var(fixed_type):
|
|
725
733
|
return self.to(ObjectVar, self._var_type)
|
|
734
|
+
|
|
726
735
|
return self
|
|
727
736
|
|
|
728
|
-
def
|
|
737
|
+
def _get_default_value(self) -> Any:
|
|
729
738
|
"""Get the default value of the var.
|
|
730
739
|
|
|
731
740
|
Returns:
|
|
@@ -768,7 +777,7 @@ class Var(Generic[VAR_TYPE]):
|
|
|
768
777
|
) from e
|
|
769
778
|
return set() if issubclass(type_, set) else None
|
|
770
779
|
|
|
771
|
-
def
|
|
780
|
+
def _get_setter_name(self, include_state: bool = True) -> str:
|
|
772
781
|
"""Get the name of the var's generated setter function.
|
|
773
782
|
|
|
774
783
|
Args:
|
|
@@ -785,7 +794,7 @@ class Var(Generic[VAR_TYPE]):
|
|
|
785
794
|
return setter
|
|
786
795
|
return ".".join((var_data.state, setter))
|
|
787
796
|
|
|
788
|
-
def
|
|
797
|
+
def _get_setter(self) -> Callable[[BaseState, Any], None]:
|
|
789
798
|
"""Get the var's setter function.
|
|
790
799
|
|
|
791
800
|
Returns:
|
|
@@ -811,7 +820,7 @@ class Var(Generic[VAR_TYPE]):
|
|
|
811
820
|
else:
|
|
812
821
|
setattr(state, actual_name, value)
|
|
813
822
|
|
|
814
|
-
setter.__qualname__ = self.
|
|
823
|
+
setter.__qualname__ = self._get_setter_name()
|
|
815
824
|
|
|
816
825
|
return setter
|
|
817
826
|
|
|
@@ -944,7 +953,7 @@ class Var(Generic[VAR_TYPE]):
|
|
|
944
953
|
else PROTOTYPE_TO_STRING.call(self).to(StringVar)
|
|
945
954
|
)
|
|
946
955
|
|
|
947
|
-
def
|
|
956
|
+
def _as_ref(self) -> Var:
|
|
948
957
|
"""Get a reference to the var.
|
|
949
958
|
|
|
950
959
|
Returns:
|
|
@@ -989,7 +998,7 @@ class Var(Generic[VAR_TYPE]):
|
|
|
989
998
|
type_of = FunctionStringVar("typeof")
|
|
990
999
|
return type_of.call(self).to(StringVar)
|
|
991
1000
|
|
|
992
|
-
def
|
|
1001
|
+
def _without_data(self):
|
|
993
1002
|
"""Create a copy of the var without the data.
|
|
994
1003
|
|
|
995
1004
|
Returns:
|
|
@@ -997,20 +1006,6 @@ class Var(Generic[VAR_TYPE]):
|
|
|
997
1006
|
"""
|
|
998
1007
|
return dataclasses.replace(self, _var_data=None)
|
|
999
1008
|
|
|
1000
|
-
def contains(self, value: Any = None, field: Any = None):
|
|
1001
|
-
"""Get an attribute of the var.
|
|
1002
|
-
|
|
1003
|
-
Args:
|
|
1004
|
-
value: The value to check for.
|
|
1005
|
-
field: The field to check for.
|
|
1006
|
-
|
|
1007
|
-
Raises:
|
|
1008
|
-
TypeError: If the var does not support contains check.
|
|
1009
|
-
"""
|
|
1010
|
-
raise TypeError(
|
|
1011
|
-
f"Var of type {self._var_type} does not support contains check."
|
|
1012
|
-
)
|
|
1013
|
-
|
|
1014
1009
|
def __get__(self, instance: Any, owner: Any):
|
|
1015
1010
|
"""Get the var.
|
|
1016
1011
|
|
|
@@ -1023,14 +1018,6 @@ class Var(Generic[VAR_TYPE]):
|
|
|
1023
1018
|
"""
|
|
1024
1019
|
return self
|
|
1025
1020
|
|
|
1026
|
-
def reverse(self):
|
|
1027
|
-
"""Reverse the var.
|
|
1028
|
-
|
|
1029
|
-
Raises:
|
|
1030
|
-
TypeError: If the var does not support reverse.
|
|
1031
|
-
"""
|
|
1032
|
-
raise TypeError("Cannot reverse non-list var.")
|
|
1033
|
-
|
|
1034
1021
|
def __getattr__(self, name: str):
|
|
1035
1022
|
"""Get an attribute of the var.
|
|
1036
1023
|
|
|
@@ -1047,6 +1034,13 @@ class Var(Generic[VAR_TYPE]):
|
|
|
1047
1034
|
if name.startswith("_"):
|
|
1048
1035
|
return self.__getattribute__(name)
|
|
1049
1036
|
|
|
1037
|
+
if name == "contains":
|
|
1038
|
+
raise TypeError(
|
|
1039
|
+
f"Var of type {self._var_type} does not support contains check."
|
|
1040
|
+
)
|
|
1041
|
+
if name == "reverse":
|
|
1042
|
+
raise TypeError("Cannot reverse non-list var.")
|
|
1043
|
+
|
|
1050
1044
|
if self._var_type is Any:
|
|
1051
1045
|
raise TypeError(
|
|
1052
1046
|
f"You must provide an annotation for the state var `{str(self)}`. Annotation cannot be `{self._var_type}`."
|
|
@@ -1075,10 +1069,7 @@ class Var(Generic[VAR_TYPE]):
|
|
|
1075
1069
|
try:
|
|
1076
1070
|
return json.loads(str(self))
|
|
1077
1071
|
except ValueError:
|
|
1078
|
-
|
|
1079
|
-
return json.loads(self.json())
|
|
1080
|
-
except (ValueError, NotImplementedError):
|
|
1081
|
-
return str(self)
|
|
1072
|
+
return str(self)
|
|
1082
1073
|
|
|
1083
1074
|
@property
|
|
1084
1075
|
def _var_state(self) -> str:
|
|
@@ -1156,17 +1147,12 @@ class Var(Generic[VAR_TYPE]):
|
|
|
1156
1147
|
"'in' operator not supported for Var types, use Var.contains() instead."
|
|
1157
1148
|
)
|
|
1158
1149
|
|
|
1159
|
-
def json(self) -> str:
|
|
1160
|
-
"""Serialize the var to a JSON string.
|
|
1161
|
-
|
|
1162
|
-
Raises:
|
|
1163
|
-
NotImplementedError: If the method is not implemented.
|
|
1164
|
-
"""
|
|
1165
|
-
raise NotImplementedError("Var subclasses must implement the json method.")
|
|
1166
|
-
|
|
1167
1150
|
|
|
1168
1151
|
OUTPUT = TypeVar("OUTPUT", bound=Var)
|
|
1169
1152
|
|
|
1153
|
+
VAR_SUBCLASS = TypeVar("VAR_SUBCLASS", bound=Var)
|
|
1154
|
+
VAR_INSIDE = TypeVar("VAR_INSIDE")
|
|
1155
|
+
|
|
1170
1156
|
|
|
1171
1157
|
class ToOperation:
|
|
1172
1158
|
"""A var operation that converts a var to another type."""
|
|
@@ -1822,6 +1808,14 @@ class ComputedVar(Var[RETURN_TYPE]):
|
|
|
1822
1808
|
"return", Any
|
|
1823
1809
|
)
|
|
1824
1810
|
|
|
1811
|
+
if hint is Any:
|
|
1812
|
+
console.deprecate(
|
|
1813
|
+
"untyped-computed-var",
|
|
1814
|
+
"ComputedVar should have a return type annotation.",
|
|
1815
|
+
"0.6.5",
|
|
1816
|
+
"0.7.0",
|
|
1817
|
+
)
|
|
1818
|
+
|
|
1825
1819
|
kwargs.setdefault("_js_expr", fget.__name__)
|
|
1826
1820
|
kwargs.setdefault("_var_type", hint)
|
|
1827
1821
|
|
|
@@ -2015,17 +2009,28 @@ class ComputedVar(Var[RETURN_TYPE]):
|
|
|
2015
2009
|
)
|
|
2016
2010
|
|
|
2017
2011
|
if not self._cache:
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
|
|
2012
|
+
value = self.fget(instance)
|
|
2013
|
+
else:
|
|
2014
|
+
# handle caching
|
|
2015
|
+
if not hasattr(instance, self._cache_attr) or self.needs_update(instance):
|
|
2016
|
+
# Set cache attr on state instance.
|
|
2017
|
+
setattr(instance, self._cache_attr, self.fget(instance))
|
|
2018
|
+
# Ensure the computed var gets serialized to redis.
|
|
2019
|
+
instance._was_touched = True
|
|
2020
|
+
# Set the last updated timestamp on the state instance.
|
|
2021
|
+
setattr(instance, self._last_updated_attr, datetime.datetime.now())
|
|
2022
|
+
value = getattr(instance, self._cache_attr)
|
|
2023
|
+
|
|
2024
|
+
if not _isinstance(value, self._var_type):
|
|
2025
|
+
console.deprecate(
|
|
2026
|
+
"mismatched-computed-var-return",
|
|
2027
|
+
f"Computed var {type(instance).__name__}.{self._js_expr} returned value of type {type(value)}, "
|
|
2028
|
+
f"expected {self._var_type}. This might cause unexpected behavior.",
|
|
2029
|
+
"0.6.5",
|
|
2030
|
+
"0.7.0",
|
|
2031
|
+
)
|
|
2032
|
+
|
|
2033
|
+
return value
|
|
2029
2034
|
|
|
2030
2035
|
def _deps(
|
|
2031
2036
|
self,
|
|
@@ -2855,6 +2860,8 @@ def dispatch(
|
|
|
2855
2860
|
|
|
2856
2861
|
V = TypeVar("V")
|
|
2857
2862
|
|
|
2863
|
+
BASE_TYPE = TypeVar("BASE_TYPE", bound=Base)
|
|
2864
|
+
|
|
2858
2865
|
|
|
2859
2866
|
class Field(Generic[T]):
|
|
2860
2867
|
"""Shadow class for Var to allow for type hinting in the IDE."""
|
|
@@ -2891,6 +2898,11 @@ class Field(Generic[T]):
|
|
|
2891
2898
|
self: Field[Dict[str, V]], instance: None, owner
|
|
2892
2899
|
) -> ObjectVar[Dict[str, V]]: ...
|
|
2893
2900
|
|
|
2901
|
+
@overload
|
|
2902
|
+
def __get__(
|
|
2903
|
+
self: Field[BASE_TYPE], instance: None, owner
|
|
2904
|
+
) -> ObjectVar[BASE_TYPE]: ...
|
|
2905
|
+
|
|
2894
2906
|
@overload
|
|
2895
2907
|
def __get__(self, instance: None, owner) -> Var[T]: ...
|
|
2896
2908
|
|
reflex/vars/function.py
CHANGED
|
@@ -4,17 +4,12 @@ from __future__ import annotations
|
|
|
4
4
|
|
|
5
5
|
import dataclasses
|
|
6
6
|
import sys
|
|
7
|
-
from typing import Any, Callable, Optional, Tuple, Type, Union
|
|
7
|
+
from typing import Any, Callable, Optional, Sequence, Tuple, Type, Union
|
|
8
8
|
|
|
9
|
+
from reflex.utils import format
|
|
9
10
|
from reflex.utils.types import GenericType
|
|
10
11
|
|
|
11
|
-
from .base import
|
|
12
|
-
CachedVarOperation,
|
|
13
|
-
LiteralVar,
|
|
14
|
-
Var,
|
|
15
|
-
VarData,
|
|
16
|
-
cached_property_no_lock,
|
|
17
|
-
)
|
|
12
|
+
from .base import CachedVarOperation, LiteralVar, Var, VarData, cached_property_no_lock
|
|
18
13
|
|
|
19
14
|
|
|
20
15
|
class FunctionVar(Var[Callable], python_types=Callable):
|
|
@@ -132,6 +127,36 @@ class VarOperationCall(CachedVarOperation, Var):
|
|
|
132
127
|
)
|
|
133
128
|
|
|
134
129
|
|
|
130
|
+
@dataclasses.dataclass(frozen=True)
|
|
131
|
+
class DestructuredArg:
|
|
132
|
+
"""Class for destructured arguments."""
|
|
133
|
+
|
|
134
|
+
fields: Tuple[str, ...] = tuple()
|
|
135
|
+
rest: Optional[str] = None
|
|
136
|
+
|
|
137
|
+
def to_javascript(self) -> str:
|
|
138
|
+
"""Convert the destructured argument to JavaScript.
|
|
139
|
+
|
|
140
|
+
Returns:
|
|
141
|
+
The destructured argument in JavaScript.
|
|
142
|
+
"""
|
|
143
|
+
return format.wrap(
|
|
144
|
+
", ".join(self.fields) + (f", ...{self.rest}" if self.rest else ""),
|
|
145
|
+
"{",
|
|
146
|
+
"}",
|
|
147
|
+
)
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
@dataclasses.dataclass(
|
|
151
|
+
frozen=True,
|
|
152
|
+
)
|
|
153
|
+
class FunctionArgs:
|
|
154
|
+
"""Class for function arguments."""
|
|
155
|
+
|
|
156
|
+
args: Tuple[Union[str, DestructuredArg], ...] = tuple()
|
|
157
|
+
rest: Optional[str] = None
|
|
158
|
+
|
|
159
|
+
|
|
135
160
|
@dataclasses.dataclass(
|
|
136
161
|
eq=False,
|
|
137
162
|
frozen=True,
|
|
@@ -140,8 +165,9 @@ class VarOperationCall(CachedVarOperation, Var):
|
|
|
140
165
|
class ArgsFunctionOperation(CachedVarOperation, FunctionVar):
|
|
141
166
|
"""Base class for immutable function defined via arguments and return expression."""
|
|
142
167
|
|
|
143
|
-
|
|
168
|
+
_args: FunctionArgs = dataclasses.field(default_factory=FunctionArgs)
|
|
144
169
|
_return_expr: Union[Var, Any] = dataclasses.field(default=None)
|
|
170
|
+
_explicit_return: bool = dataclasses.field(default=False)
|
|
145
171
|
|
|
146
172
|
@cached_property_no_lock
|
|
147
173
|
def _cached_var_name(self) -> str:
|
|
@@ -150,13 +176,31 @@ class ArgsFunctionOperation(CachedVarOperation, FunctionVar):
|
|
|
150
176
|
Returns:
|
|
151
177
|
The name of the var.
|
|
152
178
|
"""
|
|
153
|
-
|
|
179
|
+
arg_names_str = ", ".join(
|
|
180
|
+
[
|
|
181
|
+
arg if isinstance(arg, str) else arg.to_javascript()
|
|
182
|
+
for arg in self._args.args
|
|
183
|
+
]
|
|
184
|
+
) + (f", ...{self._args.rest}" if self._args.rest else "")
|
|
185
|
+
|
|
186
|
+
return_expr_str = str(LiteralVar.create(self._return_expr))
|
|
187
|
+
|
|
188
|
+
# Wrap return expression in curly braces if explicit return syntax is used.
|
|
189
|
+
return_expr_str_wrapped = (
|
|
190
|
+
format.wrap(return_expr_str, "{", "}")
|
|
191
|
+
if self._explicit_return
|
|
192
|
+
else return_expr_str
|
|
193
|
+
)
|
|
194
|
+
|
|
195
|
+
return f"(({arg_names_str}) => {return_expr_str_wrapped})"
|
|
154
196
|
|
|
155
197
|
@classmethod
|
|
156
198
|
def create(
|
|
157
199
|
cls,
|
|
158
|
-
args_names:
|
|
200
|
+
args_names: Sequence[Union[str, DestructuredArg]],
|
|
159
201
|
return_expr: Var | Any,
|
|
202
|
+
rest: str | None = None,
|
|
203
|
+
explicit_return: bool = False,
|
|
160
204
|
_var_type: GenericType = Callable,
|
|
161
205
|
_var_data: VarData | None = None,
|
|
162
206
|
) -> ArgsFunctionOperation:
|
|
@@ -165,6 +209,8 @@ class ArgsFunctionOperation(CachedVarOperation, FunctionVar):
|
|
|
165
209
|
Args:
|
|
166
210
|
args_names: The names of the arguments.
|
|
167
211
|
return_expr: The return expression of the function.
|
|
212
|
+
rest: The name of the rest argument.
|
|
213
|
+
explicit_return: Whether to use explicit return syntax.
|
|
168
214
|
_var_data: Additional hooks and imports associated with the Var.
|
|
169
215
|
|
|
170
216
|
Returns:
|
|
@@ -174,8 +220,9 @@ class ArgsFunctionOperation(CachedVarOperation, FunctionVar):
|
|
|
174
220
|
_js_expr="",
|
|
175
221
|
_var_type=_var_type,
|
|
176
222
|
_var_data=_var_data,
|
|
177
|
-
|
|
223
|
+
_args=FunctionArgs(args=tuple(args_names), rest=rest),
|
|
178
224
|
_return_expr=return_expr,
|
|
225
|
+
_explicit_return=explicit_return,
|
|
179
226
|
)
|
|
180
227
|
|
|
181
228
|
|
reflex/vars/number.py
CHANGED
|
@@ -1116,7 +1116,9 @@ U = TypeVar("U")
|
|
|
1116
1116
|
|
|
1117
1117
|
|
|
1118
1118
|
@var_operation
|
|
1119
|
-
def ternary_operation(
|
|
1119
|
+
def ternary_operation(
|
|
1120
|
+
condition: BooleanVar, if_true: Var[T], if_false: Var[U]
|
|
1121
|
+
) -> CustomVarOperationReturn[Union[T, U]]:
|
|
1120
1122
|
"""Create a ternary operation.
|
|
1121
1123
|
|
|
1122
1124
|
Args:
|