reflex 0.7.4a3__py3-none-any.whl → 0.7.5a1__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/__init__.py +1 -0
- reflex/__init__.pyi +1 -0
- reflex/app.py +10 -6
- reflex/app_mixins/middleware.py +13 -20
- reflex/compiler/compiler.py +10 -3
- reflex/compiler/utils.py +4 -4
- reflex/components/base/app_wrap.pyi +7 -3
- reflex/components/base/body.pyi +7 -3
- reflex/components/base/document.pyi +27 -7
- reflex/components/base/error_boundary.pyi +7 -3
- reflex/components/base/fragment.pyi +7 -3
- reflex/components/base/head.pyi +12 -4
- reflex/components/base/link.pyi +12 -4
- reflex/components/base/meta.pyi +22 -6
- reflex/components/base/script.pyi +7 -3
- reflex/components/base/strict_mode.pyi +7 -3
- reflex/components/component.py +64 -23
- reflex/components/core/auto_scroll.pyi +7 -3
- reflex/components/core/banner.py +6 -2
- reflex/components/core/banner.pyi +32 -8
- reflex/components/core/client_side_routing.pyi +12 -4
- reflex/components/core/clipboard.pyi +7 -3
- reflex/components/core/debounce.pyi +7 -3
- reflex/components/core/foreach.py +5 -1
- reflex/components/core/html.pyi +7 -3
- reflex/components/core/match.py +5 -5
- reflex/components/core/sticky.pyi +21 -6
- reflex/components/core/upload.pyi +27 -7
- reflex/components/datadisplay/code.pyi +12 -4
- reflex/components/datadisplay/dataeditor.py +2 -2
- reflex/components/datadisplay/dataeditor.pyi +17 -3
- reflex/components/datadisplay/shiki_code_block.pyi +17 -4
- reflex/components/el/__init__.pyi +1 -1
- reflex/components/el/element.pyi +7 -3
- reflex/components/el/elements/__init__.py +3 -1
- reflex/components/el/elements/__init__.pyi +3 -2
- reflex/components/el/elements/base.pyi +7 -3
- reflex/components/el/elements/forms.py +1 -1
- reflex/components/el/elements/forms.pyi +72 -16
- reflex/components/el/elements/inline.pyi +142 -30
- reflex/components/el/elements/media.pyi +127 -27
- reflex/components/el/elements/metadata.pyi +32 -8
- reflex/components/el/elements/other.pyi +37 -9
- reflex/components/el/elements/scripts.pyi +17 -5
- reflex/components/el/elements/sectioning.pyi +77 -17
- reflex/components/el/elements/tables.pyi +52 -12
- reflex/components/el/elements/typography.pyi +77 -17
- reflex/components/gridjs/datatable.py +2 -2
- reflex/components/gridjs/datatable.pyi +12 -4
- reflex/components/lucide/icon.py +7 -6
- reflex/components/lucide/icon.pyi +22 -7
- reflex/components/markdown/markdown.py +1 -1
- reflex/components/markdown/markdown.pyi +7 -3
- reflex/components/moment/moment.pyi +7 -3
- reflex/components/next/base.pyi +7 -3
- reflex/components/next/image.pyi +7 -3
- reflex/components/next/link.pyi +7 -3
- reflex/components/next/video.pyi +7 -3
- reflex/components/plotly/plotly.pyi +47 -11
- reflex/components/radix/primitives/accordion.pyi +37 -9
- reflex/components/radix/primitives/base.pyi +12 -4
- reflex/components/radix/primitives/drawer.pyi +57 -13
- reflex/components/radix/primitives/form.pyi +52 -12
- reflex/components/radix/primitives/progress.pyi +27 -7
- reflex/components/radix/primitives/slider.pyi +27 -7
- reflex/components/radix/themes/base.pyi +41 -10
- reflex/components/radix/themes/color_mode.py +2 -2
- reflex/components/radix/themes/color_mode.pyi +17 -5
- reflex/components/radix/themes/components/alert_dialog.pyi +36 -9
- reflex/components/radix/themes/components/aspect_ratio.pyi +7 -3
- reflex/components/radix/themes/components/avatar.pyi +6 -3
- reflex/components/radix/themes/components/badge.pyi +6 -3
- reflex/components/radix/themes/components/button.pyi +6 -3
- reflex/components/radix/themes/components/callout.pyi +26 -7
- reflex/components/radix/themes/components/card.pyi +6 -3
- reflex/components/radix/themes/components/checkbox.pyi +16 -5
- reflex/components/radix/themes/components/checkbox_cards.pyi +11 -4
- reflex/components/radix/themes/components/checkbox_group.pyi +11 -4
- reflex/components/radix/themes/components/context_menu.pyi +66 -15
- reflex/components/radix/themes/components/data_list.pyi +21 -6
- reflex/components/radix/themes/components/dialog.pyi +36 -9
- reflex/components/radix/themes/components/dropdown_menu.pyi +41 -10
- reflex/components/radix/themes/components/hover_card.pyi +21 -6
- reflex/components/radix/themes/components/icon_button.pyi +6 -3
- reflex/components/radix/themes/components/inset.pyi +6 -3
- reflex/components/radix/themes/components/popover.pyi +21 -6
- reflex/components/radix/themes/components/progress.pyi +6 -3
- reflex/components/radix/themes/components/radio.pyi +6 -3
- reflex/components/radix/themes/components/radio_cards.pyi +11 -4
- reflex/components/radix/themes/components/radio_group.py +6 -1
- reflex/components/radix/themes/components/radio_group.pyi +21 -6
- reflex/components/radix/themes/components/scroll_area.pyi +7 -3
- reflex/components/radix/themes/components/segmented_control.pyi +11 -4
- reflex/components/radix/themes/components/select.pyi +46 -11
- reflex/components/radix/themes/components/separator.pyi +6 -3
- reflex/components/radix/themes/components/skeleton.pyi +6 -3
- reflex/components/radix/themes/components/slider.pyi +6 -3
- reflex/components/radix/themes/components/spinner.pyi +6 -3
- reflex/components/radix/themes/components/switch.pyi +6 -3
- reflex/components/radix/themes/components/table.pyi +36 -9
- reflex/components/radix/themes/components/tabs.pyi +26 -7
- reflex/components/radix/themes/components/text_area.pyi +6 -3
- reflex/components/radix/themes/components/text_field.py +3 -2
- reflex/components/radix/themes/components/text_field.pyi +16 -5
- reflex/components/radix/themes/components/tooltip.pyi +7 -3
- reflex/components/radix/themes/layout/base.pyi +6 -3
- reflex/components/radix/themes/layout/box.pyi +7 -3
- reflex/components/radix/themes/layout/center.pyi +6 -3
- reflex/components/radix/themes/layout/container.pyi +6 -3
- reflex/components/radix/themes/layout/flex.pyi +6 -3
- reflex/components/radix/themes/layout/grid.pyi +6 -3
- reflex/components/radix/themes/layout/list.pyi +27 -7
- reflex/components/radix/themes/layout/section.pyi +6 -3
- reflex/components/radix/themes/layout/spacer.pyi +6 -3
- reflex/components/radix/themes/layout/stack.pyi +16 -5
- reflex/components/radix/themes/typography/blockquote.pyi +6 -3
- reflex/components/radix/themes/typography/code.pyi +6 -3
- reflex/components/radix/themes/typography/heading.pyi +6 -3
- reflex/components/radix/themes/typography/link.pyi +6 -3
- reflex/components/radix/themes/typography/text.pyi +36 -9
- reflex/components/react_player/audio.pyi +7 -3
- reflex/components/react_player/react_player.pyi +7 -3
- reflex/components/react_player/video.pyi +7 -3
- reflex/components/recharts/cartesian.pyi +97 -21
- reflex/components/recharts/charts.pyi +62 -14
- reflex/components/recharts/general.pyi +32 -8
- reflex/components/recharts/polar.py +1 -1
- reflex/components/recharts/polar.pyi +33 -9
- reflex/components/recharts/recharts.pyi +12 -4
- reflex/components/sonner/toast.pyi +7 -2
- reflex/components/suneditor/editor.pyi +7 -3
- reflex/config.py +15 -1
- reflex/constants/installer.py +22 -1
- reflex/custom_components/custom_components.py +12 -7
- reflex/event.py +26 -10
- reflex/experimental/__init__.py +17 -6
- reflex/experimental/layout.pyi +27 -7
- reflex/model.py +3 -3
- reflex/reflex.py +33 -18
- reflex/state.py +3 -3
- reflex/style.py +2 -2
- reflex/testing.py +17 -5
- reflex/utils/console.py +2 -3
- reflex/utils/exec.py +4 -0
- reflex/utils/imports.py +14 -7
- reflex/utils/prerequisites.py +72 -7
- reflex/utils/processes.py +52 -19
- reflex/utils/pyi_generator.py +66 -53
- reflex/utils/registry.py +5 -3
- reflex/utils/serializers.py +1 -2
- reflex/utils/types.py +4 -4
- reflex/vars/base.py +58 -22
- reflex/vars/number.py +23 -6
- reflex/vars/sequence.py +2 -0
- {reflex-0.7.4a3.dist-info → reflex-0.7.5a1.dist-info}/METADATA +2 -2
- {reflex-0.7.4a3.dist-info → reflex-0.7.5a1.dist-info}/RECORD +160 -160
- /reflex/{experimental → utils}/misc.py +0 -0
- {reflex-0.7.4a3.dist-info → reflex-0.7.5a1.dist-info}/WHEEL +0 -0
- {reflex-0.7.4a3.dist-info → reflex-0.7.5a1.dist-info}/entry_points.txt +0 -0
- {reflex-0.7.4a3.dist-info → reflex-0.7.5a1.dist-info}/licenses/LICENSE +0 -0
reflex/utils/pyi_generator.py
CHANGED
|
@@ -55,6 +55,10 @@ EXCLUDED_PROPS = [
|
|
|
55
55
|
"State",
|
|
56
56
|
]
|
|
57
57
|
|
|
58
|
+
OVERWRITE_TYPES = {
|
|
59
|
+
"style": "Sequence[Mapping[str, Any]] | Mapping[str, Any] | Var[Mapping[str, Any]] | Breakpoints | None",
|
|
60
|
+
}
|
|
61
|
+
|
|
58
62
|
DEFAULT_TYPING_IMPORTS = {
|
|
59
63
|
"overload",
|
|
60
64
|
"Any",
|
|
@@ -62,6 +66,7 @@ DEFAULT_TYPING_IMPORTS = {
|
|
|
62
66
|
"Dict",
|
|
63
67
|
# "List",
|
|
64
68
|
"Sequence",
|
|
69
|
+
"Mapping",
|
|
65
70
|
"Literal",
|
|
66
71
|
"Optional",
|
|
67
72
|
"Union",
|
|
@@ -377,7 +382,9 @@ def _extract_class_props_as_ast_nodes(
|
|
|
377
382
|
ast.arg(
|
|
378
383
|
arg=name,
|
|
379
384
|
annotation=ast.Name(
|
|
380
|
-
id=
|
|
385
|
+
id=OVERWRITE_TYPES.get(
|
|
386
|
+
name, _get_type_hint(value, type_hint_globals)
|
|
387
|
+
)
|
|
381
388
|
),
|
|
382
389
|
),
|
|
383
390
|
ast.Constant(value=default),
|
|
@@ -386,7 +393,7 @@ def _extract_class_props_as_ast_nodes(
|
|
|
386
393
|
return kwargs
|
|
387
394
|
|
|
388
395
|
|
|
389
|
-
def type_to_ast(typ: Any, cls: type) -> ast.
|
|
396
|
+
def type_to_ast(typ: Any, cls: type) -> ast.expr:
|
|
390
397
|
"""Converts any type annotation into its AST representation.
|
|
391
398
|
Handles nested generic types, unions, etc.
|
|
392
399
|
|
|
@@ -439,11 +446,11 @@ def type_to_ast(typ: Any, cls: type) -> ast.AST:
|
|
|
439
446
|
if len(arg_nodes) == 1:
|
|
440
447
|
slice_value = arg_nodes[0]
|
|
441
448
|
else:
|
|
442
|
-
slice_value = ast.Tuple(elts=arg_nodes, ctx=ast.Load())
|
|
449
|
+
slice_value = ast.Tuple(elts=arg_nodes, ctx=ast.Load())
|
|
443
450
|
|
|
444
451
|
return ast.Subscript(
|
|
445
452
|
value=ast.Name(id=base_name),
|
|
446
|
-
slice=
|
|
453
|
+
slice=slice_value,
|
|
447
454
|
ctx=ast.Load(),
|
|
448
455
|
)
|
|
449
456
|
|
|
@@ -463,16 +470,18 @@ def _get_parent_imports(func: Callable):
|
|
|
463
470
|
|
|
464
471
|
|
|
465
472
|
def _generate_component_create_functiondef(
|
|
466
|
-
|
|
467
|
-
clz: type[Component] | type[SimpleNamespace],
|
|
473
|
+
clz: type[Component],
|
|
468
474
|
type_hint_globals: dict[str, Any],
|
|
475
|
+
lineno: int,
|
|
476
|
+
decorator_list: Sequence[ast.expr] = (ast.Name(id="classmethod"),),
|
|
469
477
|
) -> ast.FunctionDef:
|
|
470
478
|
"""Generate the create function definition for a Component.
|
|
471
479
|
|
|
472
480
|
Args:
|
|
473
|
-
node: The existing create functiondef node from the ast
|
|
474
481
|
clz: The Component class to generate the create functiondef for.
|
|
475
482
|
type_hint_globals: The globals to use to resolving a type hint str.
|
|
483
|
+
lineno: The line number to use for the ast nodes.
|
|
484
|
+
decorator_list: The list of decorators to apply to the create functiondef.
|
|
476
485
|
|
|
477
486
|
Returns:
|
|
478
487
|
The create functiondef node for the ast.
|
|
@@ -584,28 +593,26 @@ def _generate_component_create_functiondef(
|
|
|
584
593
|
arg=trigger,
|
|
585
594
|
annotation=ast.Subscript(
|
|
586
595
|
ast.Name("Optional"),
|
|
587
|
-
ast.
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
),
|
|
608
|
-
)
|
|
596
|
+
ast.Name(
|
|
597
|
+
id=ast.unparse(
|
|
598
|
+
figure_out_return_type(
|
|
599
|
+
inspect.signature(event_specs).return_annotation
|
|
600
|
+
)
|
|
601
|
+
if not isinstance(
|
|
602
|
+
event_specs := event_triggers[trigger], Sequence
|
|
603
|
+
)
|
|
604
|
+
else ast.Subscript(
|
|
605
|
+
ast.Name("Union"),
|
|
606
|
+
ast.Tuple(
|
|
607
|
+
[
|
|
608
|
+
figure_out_return_type(
|
|
609
|
+
inspect.signature(
|
|
610
|
+
event_spec
|
|
611
|
+
).return_annotation
|
|
612
|
+
)
|
|
613
|
+
for event_spec in event_specs
|
|
614
|
+
]
|
|
615
|
+
),
|
|
609
616
|
)
|
|
610
617
|
)
|
|
611
618
|
),
|
|
@@ -630,7 +637,7 @@ def _generate_component_create_functiondef(
|
|
|
630
637
|
definition = ast.FunctionDef( # pyright: ignore [reportCallIssue]
|
|
631
638
|
name="create",
|
|
632
639
|
args=create_args,
|
|
633
|
-
body=[
|
|
640
|
+
body=[
|
|
634
641
|
ast.Expr(
|
|
635
642
|
value=ast.Constant(
|
|
636
643
|
value=_generate_docstrings(
|
|
@@ -644,25 +651,19 @@ def _generate_component_create_functiondef(
|
|
|
644
651
|
],
|
|
645
652
|
decorator_list=[
|
|
646
653
|
ast.Name(id="overload"),
|
|
647
|
-
*
|
|
648
|
-
node.decorator_list
|
|
649
|
-
if node is not None
|
|
650
|
-
else [ast.Name(id="classmethod")]
|
|
651
|
-
),
|
|
654
|
+
*decorator_list,
|
|
652
655
|
],
|
|
653
|
-
lineno=
|
|
656
|
+
lineno=lineno,
|
|
654
657
|
returns=ast.Constant(value=clz.__name__),
|
|
655
658
|
)
|
|
656
659
|
return definition
|
|
657
660
|
|
|
658
661
|
|
|
659
662
|
def _generate_staticmethod_call_functiondef(
|
|
660
|
-
node: ast.
|
|
663
|
+
node: ast.ClassDef,
|
|
661
664
|
clz: type[Component] | type[SimpleNamespace],
|
|
662
665
|
type_hint_globals: dict[str, Any],
|
|
663
666
|
) -> ast.FunctionDef | None:
|
|
664
|
-
...
|
|
665
|
-
|
|
666
667
|
fullspec = getfullargspec(clz.__call__)
|
|
667
668
|
|
|
668
669
|
call_args = ast.arguments(
|
|
@@ -699,7 +700,7 @@ def _generate_staticmethod_call_functiondef(
|
|
|
699
700
|
),
|
|
700
701
|
],
|
|
701
702
|
decorator_list=[ast.Name(id="staticmethod")],
|
|
702
|
-
lineno=node.lineno
|
|
703
|
+
lineno=node.lineno,
|
|
703
704
|
returns=ast.Constant(
|
|
704
705
|
value=_get_type_hint(
|
|
705
706
|
typing.get_type_hints(clz.__call__).get("return", None),
|
|
@@ -712,7 +713,7 @@ def _generate_staticmethod_call_functiondef(
|
|
|
712
713
|
|
|
713
714
|
|
|
714
715
|
def _generate_namespace_call_functiondef(
|
|
715
|
-
node: ast.ClassDef
|
|
716
|
+
node: ast.ClassDef,
|
|
716
717
|
clz_name: str,
|
|
717
718
|
classes: dict[str, type[Component] | type[SimpleNamespace]],
|
|
718
719
|
type_hint_globals: dict[str, Any],
|
|
@@ -736,7 +737,7 @@ def _generate_namespace_call_functiondef(
|
|
|
736
737
|
clz = classes[clz_name]
|
|
737
738
|
|
|
738
739
|
if not hasattr(clz.__call__, "__self__"):
|
|
739
|
-
return _generate_staticmethod_call_functiondef(node, clz, type_hint_globals)
|
|
740
|
+
return _generate_staticmethod_call_functiondef(node, clz, type_hint_globals)
|
|
740
741
|
|
|
741
742
|
# Determine which class is wrapped by the namespace __call__ method
|
|
742
743
|
component_clz = clz.__call__.__self__
|
|
@@ -744,10 +745,14 @@ def _generate_namespace_call_functiondef(
|
|
|
744
745
|
if clz.__call__.__func__.__name__ != "create": # pyright: ignore [reportFunctionMemberAccess]
|
|
745
746
|
return None
|
|
746
747
|
|
|
748
|
+
if not issubclass(component_clz, Component):
|
|
749
|
+
return None
|
|
750
|
+
|
|
747
751
|
definition = _generate_component_create_functiondef(
|
|
748
|
-
|
|
749
|
-
clz=component_clz, # pyright: ignore [reportArgumentType]
|
|
752
|
+
clz=component_clz,
|
|
750
753
|
type_hint_globals=type_hint_globals,
|
|
754
|
+
lineno=node.lineno,
|
|
755
|
+
decorator_list=[],
|
|
751
756
|
)
|
|
752
757
|
definition.name = "__call__"
|
|
753
758
|
|
|
@@ -804,17 +809,18 @@ class StubGenerator(ast.NodeTransformer):
|
|
|
804
809
|
node.body.pop(0)
|
|
805
810
|
return node
|
|
806
811
|
|
|
807
|
-
def _current_class_is_component(self) ->
|
|
812
|
+
def _current_class_is_component(self) -> type[Component] | None:
|
|
808
813
|
"""Check if the current class is a Component.
|
|
809
814
|
|
|
810
815
|
Returns:
|
|
811
816
|
Whether the current class is a Component.
|
|
812
817
|
"""
|
|
813
|
-
|
|
818
|
+
if (
|
|
814
819
|
self.current_class is not None
|
|
815
820
|
and self.current_class in self.classes
|
|
816
|
-
and issubclass(self.classes[self.current_class], Component)
|
|
817
|
-
)
|
|
821
|
+
and issubclass((clz := self.classes[self.current_class]), Component)
|
|
822
|
+
):
|
|
823
|
+
return clz
|
|
818
824
|
|
|
819
825
|
def visit_Module(self, node: ast.Module) -> ast.Module:
|
|
820
826
|
"""Visit a Module node and remove docstring from body.
|
|
@@ -916,14 +922,14 @@ class StubGenerator(ast.NodeTransformer):
|
|
|
916
922
|
isinstance(child, ast.FunctionDef) and child.name == "create"
|
|
917
923
|
for child in node.body
|
|
918
924
|
)
|
|
919
|
-
and self._current_class_is_component()
|
|
925
|
+
and (clz := self._current_class_is_component()) is not None
|
|
920
926
|
):
|
|
921
927
|
# Add a new .create FunctionDef since one does not exist.
|
|
922
928
|
node.body.append(
|
|
923
929
|
_generate_component_create_functiondef(
|
|
924
|
-
|
|
925
|
-
clz=self.classes[self.current_class],
|
|
930
|
+
clz=clz,
|
|
926
931
|
type_hint_globals=self.type_hint_globals,
|
|
932
|
+
lineno=node.lineno,
|
|
927
933
|
)
|
|
928
934
|
)
|
|
929
935
|
if call_definition is not None:
|
|
@@ -949,9 +955,16 @@ class StubGenerator(ast.NodeTransformer):
|
|
|
949
955
|
Returns:
|
|
950
956
|
The modified FunctionDef node (or None).
|
|
951
957
|
"""
|
|
952
|
-
if
|
|
958
|
+
if (
|
|
959
|
+
node.name == "create"
|
|
960
|
+
and self.current_class in self.classes
|
|
961
|
+
and issubclass((clz := self.classes[self.current_class]), Component)
|
|
962
|
+
):
|
|
953
963
|
node = _generate_component_create_functiondef(
|
|
954
|
-
|
|
964
|
+
clz=clz,
|
|
965
|
+
type_hint_globals=self.type_hint_globals,
|
|
966
|
+
lineno=node.lineno,
|
|
967
|
+
decorator_list=node.decorator_list,
|
|
955
968
|
)
|
|
956
969
|
else:
|
|
957
970
|
if node.name.startswith("_") and node.name != "__call__":
|
reflex/utils/registry.py
CHANGED
|
@@ -4,6 +4,7 @@ import httpx
|
|
|
4
4
|
|
|
5
5
|
from reflex.config import environment
|
|
6
6
|
from reflex.utils import console, net
|
|
7
|
+
from reflex.utils.decorator import once
|
|
7
8
|
|
|
8
9
|
|
|
9
10
|
def latency(registry: str) -> int:
|
|
@@ -48,15 +49,16 @@ def _get_best_registry() -> str:
|
|
|
48
49
|
"""
|
|
49
50
|
console.debug("Getting best registry...")
|
|
50
51
|
registries = [
|
|
51
|
-
"https://registry.npmjs.org",
|
|
52
|
-
"https://
|
|
52
|
+
("https://registry.npmjs.org", 1),
|
|
53
|
+
("https://registry.npmmirror.com", 2),
|
|
53
54
|
]
|
|
54
55
|
|
|
55
|
-
best_registry = min(registries, key=average_latency)
|
|
56
|
+
best_registry = min(registries, key=lambda x: average_latency(x[0]) * x[1])[0]
|
|
56
57
|
console.debug(f"Best registry: {best_registry}")
|
|
57
58
|
return best_registry
|
|
58
59
|
|
|
59
60
|
|
|
61
|
+
@once
|
|
60
62
|
def get_npm_registry() -> str:
|
|
61
63
|
"""Get npm registry. If environment variable is set, use it first.
|
|
62
64
|
|
reflex/utils/serializers.py
CHANGED
|
@@ -16,7 +16,6 @@ from typing import (
|
|
|
16
16
|
Callable,
|
|
17
17
|
Literal,
|
|
18
18
|
Sequence,
|
|
19
|
-
Set,
|
|
20
19
|
Type,
|
|
21
20
|
TypeVar,
|
|
22
21
|
Union,
|
|
@@ -322,7 +321,7 @@ if BaseModelV1 is not BaseModelV2:
|
|
|
322
321
|
|
|
323
322
|
|
|
324
323
|
@serializer
|
|
325
|
-
def serialize_set(value:
|
|
324
|
+
def serialize_set(value: set) -> list:
|
|
326
325
|
"""Serialize a set to a JSON serializable list.
|
|
327
326
|
|
|
328
327
|
Args:
|
reflex/utils/types.py
CHANGED
|
@@ -140,7 +140,7 @@ def is_generic_alias(cls: GenericType) -> bool:
|
|
|
140
140
|
Returns:
|
|
141
141
|
Whether the class is a generic alias.
|
|
142
142
|
"""
|
|
143
|
-
return isinstance(cls, GenericAliasTypes)
|
|
143
|
+
return isinstance(cls, GenericAliasTypes)
|
|
144
144
|
|
|
145
145
|
|
|
146
146
|
@lru_cache()
|
|
@@ -923,7 +923,7 @@ StateBases = get_base_class(StateVar)
|
|
|
923
923
|
StateIterBases = get_base_class(StateIterVar)
|
|
924
924
|
|
|
925
925
|
|
|
926
|
-
def safe_issubclass(cls:
|
|
926
|
+
def safe_issubclass(cls: Any, cls_check: Any | tuple[Any, ...]):
|
|
927
927
|
"""Check if a class is a subclass of another class. Returns False if internal error occurs.
|
|
928
928
|
|
|
929
929
|
Args:
|
|
@@ -1047,8 +1047,8 @@ def typehint_issubclass(
|
|
|
1047
1047
|
|
|
1048
1048
|
# Check if the origin of both types is the same (e.g., list for list[int])
|
|
1049
1049
|
if not safe_issubclass(
|
|
1050
|
-
provided_type_origin or possible_subclass,
|
|
1051
|
-
accepted_type_origin or possible_superclass,
|
|
1050
|
+
provided_type_origin or possible_subclass,
|
|
1051
|
+
accepted_type_origin or possible_superclass,
|
|
1052
1052
|
):
|
|
1053
1053
|
return False
|
|
1054
1054
|
|
reflex/vars/base.py
CHANGED
|
@@ -30,6 +30,7 @@ from typing import (
|
|
|
30
30
|
Mapping,
|
|
31
31
|
NoReturn,
|
|
32
32
|
ParamSpec,
|
|
33
|
+
Protocol,
|
|
33
34
|
Sequence,
|
|
34
35
|
Set,
|
|
35
36
|
Tuple,
|
|
@@ -59,10 +60,11 @@ from reflex.utils.exceptions import (
|
|
|
59
60
|
)
|
|
60
61
|
from reflex.utils.format import format_state_name
|
|
61
62
|
from reflex.utils.imports import (
|
|
63
|
+
ImmutableImportDict,
|
|
62
64
|
ImmutableParsedImportDict,
|
|
63
65
|
ImportDict,
|
|
64
66
|
ImportVar,
|
|
65
|
-
|
|
67
|
+
ParsedImportTuple,
|
|
66
68
|
parse_imports,
|
|
67
69
|
)
|
|
68
70
|
from reflex.utils.types import (
|
|
@@ -122,7 +124,7 @@ class VarData:
|
|
|
122
124
|
field_name: str = dataclasses.field(default="")
|
|
123
125
|
|
|
124
126
|
# Imports needed to render this var
|
|
125
|
-
imports:
|
|
127
|
+
imports: ParsedImportTuple = dataclasses.field(default_factory=tuple)
|
|
126
128
|
|
|
127
129
|
# Hooks that need to be present in the component to render this var
|
|
128
130
|
hooks: tuple[str, ...] = dataclasses.field(default_factory=tuple)
|
|
@@ -140,7 +142,7 @@ class VarData:
|
|
|
140
142
|
self,
|
|
141
143
|
state: str = "",
|
|
142
144
|
field_name: str = "",
|
|
143
|
-
imports:
|
|
145
|
+
imports: ImmutableImportDict | ImmutableParsedImportDict | None = None,
|
|
144
146
|
hooks: Mapping[str, VarData | None] | Sequence[str] | str | None = None,
|
|
145
147
|
deps: list[Var] | None = None,
|
|
146
148
|
position: Hooks.HookPosition | None = None,
|
|
@@ -161,7 +163,7 @@ class VarData:
|
|
|
161
163
|
hooks = [hooks]
|
|
162
164
|
if not isinstance(hooks, dict):
|
|
163
165
|
hooks = dict.fromkeys(hooks or [])
|
|
164
|
-
immutable_imports:
|
|
166
|
+
immutable_imports: ParsedImportTuple = tuple(
|
|
165
167
|
(k, tuple(v)) for k, v in parse_imports(imports or {}).items()
|
|
166
168
|
)
|
|
167
169
|
object.__setattr__(self, "state", state)
|
|
@@ -988,7 +990,7 @@ class Var(Generic[VAR_TYPE]):
|
|
|
988
990
|
setattr(state, actual_name, value)
|
|
989
991
|
except ValueError:
|
|
990
992
|
console.debug(
|
|
991
|
-
f"{type(state).__name__}.{self._js_expr}: Failed conversion of {value} to '{self._var_type.__name__}'. Value not set.",
|
|
993
|
+
f"{type(state).__name__}.{self._js_expr}: Failed conversion of {value!s} to '{self._var_type.__name__}'. Value not set.",
|
|
992
994
|
)
|
|
993
995
|
else:
|
|
994
996
|
setattr(state, actual_name, value)
|
|
@@ -1058,7 +1060,9 @@ class Var(Generic[VAR_TYPE]):
|
|
|
1058
1060
|
|
|
1059
1061
|
return boolify(self)
|
|
1060
1062
|
|
|
1061
|
-
def __and__(
|
|
1063
|
+
def __and__(
|
|
1064
|
+
self, other: Var[OTHER_VAR_TYPE] | Any
|
|
1065
|
+
) -> Var[VAR_TYPE | OTHER_VAR_TYPE]:
|
|
1062
1066
|
"""Perform a logical AND operation on the current instance and another variable.
|
|
1063
1067
|
|
|
1064
1068
|
Args:
|
|
@@ -1069,7 +1073,9 @@ class Var(Generic[VAR_TYPE]):
|
|
|
1069
1073
|
"""
|
|
1070
1074
|
return and_operation(self, other)
|
|
1071
1075
|
|
|
1072
|
-
def __rand__(
|
|
1076
|
+
def __rand__(
|
|
1077
|
+
self, other: Var[OTHER_VAR_TYPE] | Any
|
|
1078
|
+
) -> Var[VAR_TYPE | OTHER_VAR_TYPE]:
|
|
1073
1079
|
"""Perform a logical AND operation on the current instance and another variable.
|
|
1074
1080
|
|
|
1075
1081
|
Args:
|
|
@@ -1080,7 +1086,9 @@ class Var(Generic[VAR_TYPE]):
|
|
|
1080
1086
|
"""
|
|
1081
1087
|
return and_operation(other, self)
|
|
1082
1088
|
|
|
1083
|
-
def __or__(
|
|
1089
|
+
def __or__(
|
|
1090
|
+
self, other: Var[OTHER_VAR_TYPE] | Any
|
|
1091
|
+
) -> Var[VAR_TYPE | OTHER_VAR_TYPE]:
|
|
1084
1092
|
"""Perform a logical OR operation on the current instance and another variable.
|
|
1085
1093
|
|
|
1086
1094
|
Args:
|
|
@@ -1091,7 +1099,9 @@ class Var(Generic[VAR_TYPE]):
|
|
|
1091
1099
|
"""
|
|
1092
1100
|
return or_operation(self, other)
|
|
1093
1101
|
|
|
1094
|
-
def __ror__(
|
|
1102
|
+
def __ror__(
|
|
1103
|
+
self, other: Var[OTHER_VAR_TYPE] | Any
|
|
1104
|
+
) -> Var[VAR_TYPE | OTHER_VAR_TYPE]:
|
|
1095
1105
|
"""Perform a logical OR operation on the current instance and another variable.
|
|
1096
1106
|
|
|
1097
1107
|
Args:
|
|
@@ -1478,7 +1488,7 @@ class LiteralVar(Var):
|
|
|
1478
1488
|
_var_literal_subclasses.append((cls, var_subclass))
|
|
1479
1489
|
|
|
1480
1490
|
@classmethod
|
|
1481
|
-
def
|
|
1491
|
+
def _create_literal_var(
|
|
1482
1492
|
cls,
|
|
1483
1493
|
value: Any,
|
|
1484
1494
|
_var_data: VarData | None = None,
|
|
@@ -1559,6 +1569,9 @@ class LiteralVar(Var):
|
|
|
1559
1569
|
f"Unsupported type {type(value)} for LiteralVar. Tried to create a LiteralVar from {value}."
|
|
1560
1570
|
)
|
|
1561
1571
|
|
|
1572
|
+
if not TYPE_CHECKING:
|
|
1573
|
+
create = _create_literal_var
|
|
1574
|
+
|
|
1562
1575
|
def __post_init__(self):
|
|
1563
1576
|
"""Post-initialize the var."""
|
|
1564
1577
|
|
|
@@ -1835,6 +1848,21 @@ class cached_property: # noqa: N801
|
|
|
1835
1848
|
cached_property_no_lock = cached_property
|
|
1836
1849
|
|
|
1837
1850
|
|
|
1851
|
+
class VarProtocol(Protocol):
|
|
1852
|
+
"""A protocol for Var."""
|
|
1853
|
+
|
|
1854
|
+
__dataclass_fields__: ClassVar[dict[str, dataclasses.Field[Any]]]
|
|
1855
|
+
|
|
1856
|
+
@property
|
|
1857
|
+
def _js_expr(self) -> str: ...
|
|
1858
|
+
|
|
1859
|
+
@property
|
|
1860
|
+
def _var_type(self) -> types.GenericType: ...
|
|
1861
|
+
|
|
1862
|
+
@property
|
|
1863
|
+
def _var_data(self) -> VarData: ...
|
|
1864
|
+
|
|
1865
|
+
|
|
1838
1866
|
class CachedVarOperation:
|
|
1839
1867
|
"""Base class for cached var operations to lower boilerplate code."""
|
|
1840
1868
|
|
|
@@ -1869,7 +1897,7 @@ class CachedVarOperation:
|
|
|
1869
1897
|
return self._cached_get_all_var_data
|
|
1870
1898
|
|
|
1871
1899
|
@cached_property_no_lock
|
|
1872
|
-
def _cached_get_all_var_data(self) -> VarData | None:
|
|
1900
|
+
def _cached_get_all_var_data(self: VarProtocol) -> VarData | None:
|
|
1873
1901
|
"""Get the cached VarData.
|
|
1874
1902
|
|
|
1875
1903
|
Returns:
|
|
@@ -1879,14 +1907,13 @@ class CachedVarOperation:
|
|
|
1879
1907
|
*(
|
|
1880
1908
|
value._get_all_var_data() if isinstance(value, Var) else None
|
|
1881
1909
|
for value in (
|
|
1882
|
-
getattr(self, field.name)
|
|
1883
|
-
for field in dataclasses.fields(self) # pyright: ignore [reportArgumentType]
|
|
1910
|
+
getattr(self, field.name) for field in dataclasses.fields(self)
|
|
1884
1911
|
)
|
|
1885
1912
|
),
|
|
1886
1913
|
self._var_data,
|
|
1887
1914
|
)
|
|
1888
1915
|
|
|
1889
|
-
def __hash__(self) -> int:
|
|
1916
|
+
def __hash__(self: DataclassInstance) -> int:
|
|
1890
1917
|
"""Calculate the hash of the object.
|
|
1891
1918
|
|
|
1892
1919
|
Returns:
|
|
@@ -1897,14 +1924,16 @@ class CachedVarOperation:
|
|
|
1897
1924
|
type(self).__name__,
|
|
1898
1925
|
*[
|
|
1899
1926
|
getattr(self, field.name)
|
|
1900
|
-
for field in dataclasses.fields(self)
|
|
1927
|
+
for field in dataclasses.fields(self)
|
|
1901
1928
|
if field.name not in ["_js_expr", "_var_data", "_var_type"]
|
|
1902
1929
|
],
|
|
1903
1930
|
)
|
|
1904
1931
|
)
|
|
1905
1932
|
|
|
1906
1933
|
|
|
1907
|
-
def and_operation(
|
|
1934
|
+
def and_operation(
|
|
1935
|
+
a: Var[VAR_TYPE] | Any, b: Var[OTHER_VAR_TYPE] | Any
|
|
1936
|
+
) -> Var[VAR_TYPE | OTHER_VAR_TYPE]:
|
|
1908
1937
|
"""Perform a logical AND operation on two variables.
|
|
1909
1938
|
|
|
1910
1939
|
Args:
|
|
@@ -1934,7 +1963,9 @@ def _and_operation(a: Var, b: Var):
|
|
|
1934
1963
|
)
|
|
1935
1964
|
|
|
1936
1965
|
|
|
1937
|
-
def or_operation(
|
|
1966
|
+
def or_operation(
|
|
1967
|
+
a: Var[VAR_TYPE] | Any, b: Var[OTHER_VAR_TYPE] | Any
|
|
1968
|
+
) -> Var[VAR_TYPE | OTHER_VAR_TYPE]:
|
|
1938
1969
|
"""Perform a logical OR operation on two variables.
|
|
1939
1970
|
|
|
1940
1971
|
Args:
|
|
@@ -2340,7 +2371,7 @@ class ComputedVar(Var[RETURN_TYPE]):
|
|
|
2340
2371
|
if not _isinstance(value, self._var_type, nested=1, treat_var_as_type=False):
|
|
2341
2372
|
console.error(
|
|
2342
2373
|
f"Computed var '{type(instance).__name__}.{self._js_expr}' must return"
|
|
2343
|
-
f" a value of type '{self._var_type}', got '{value}' of type {type(value)}."
|
|
2374
|
+
f" a value of type '{self._var_type}', got '{value!s}' of type {type(value)}."
|
|
2344
2375
|
)
|
|
2345
2376
|
|
|
2346
2377
|
def _deps(
|
|
@@ -2976,7 +3007,7 @@ def get_uuid_string_var() -> Var:
|
|
|
2976
3007
|
unique_uuid_var = get_unique_variable_name()
|
|
2977
3008
|
unique_uuid_var_data = VarData(
|
|
2978
3009
|
imports={
|
|
2979
|
-
f"$/{constants.Dirs.STATE_PATH}":
|
|
3010
|
+
f"$/{constants.Dirs.STATE_PATH}": ImportVar(tag="generateUUID"),
|
|
2980
3011
|
"react": "useMemo",
|
|
2981
3012
|
},
|
|
2982
3013
|
hooks={f"const {unique_uuid_var} = useMemo(generateUUID, [])": None},
|
|
@@ -3286,10 +3317,15 @@ class Field(Generic[FIELD_TYPE]):
|
|
|
3286
3317
|
|
|
3287
3318
|
@overload
|
|
3288
3319
|
def __get__(
|
|
3289
|
-
self: Field[int]
|
|
3290
|
-
|
|
3320
|
+
self: Field[int] | Field[int | None],
|
|
3321
|
+
instance: None,
|
|
3322
|
+
owner: Any,
|
|
3323
|
+
) -> NumberVar[int]: ...
|
|
3324
|
+
|
|
3325
|
+
@overload
|
|
3326
|
+
def __get__(
|
|
3327
|
+
self: Field[float]
|
|
3291
3328
|
| Field[int | float]
|
|
3292
|
-
| Field[int | None]
|
|
3293
3329
|
| Field[float | None]
|
|
3294
3330
|
| Field[int | float | None],
|
|
3295
3331
|
instance: None,
|
reflex/vars/number.py
CHANGED
|
@@ -16,6 +16,8 @@ from typing import (
|
|
|
16
16
|
overload,
|
|
17
17
|
)
|
|
18
18
|
|
|
19
|
+
from typing_extensions import TypeVar as TypeVarExt
|
|
20
|
+
|
|
19
21
|
from reflex.constants.base import Dirs
|
|
20
22
|
from reflex.utils.exceptions import (
|
|
21
23
|
PrimitiveUnserializableToJSONError,
|
|
@@ -35,7 +37,9 @@ from .base import (
|
|
|
35
37
|
var_operation_return,
|
|
36
38
|
)
|
|
37
39
|
|
|
38
|
-
NUMBER_T =
|
|
40
|
+
NUMBER_T = TypeVarExt(
|
|
41
|
+
"NUMBER_T", bound=(int | float), default=(int | float), covariant=True
|
|
42
|
+
)
|
|
39
43
|
|
|
40
44
|
if TYPE_CHECKING:
|
|
41
45
|
from .sequence import ArrayVar
|
|
@@ -313,13 +317,19 @@ class NumberVar(Var[NUMBER_T], python_types=(int, float)):
|
|
|
313
317
|
"""
|
|
314
318
|
return self
|
|
315
319
|
|
|
316
|
-
def __round__(self):
|
|
320
|
+
def __round__(self, ndigits: int | NumberVar = 0) -> NumberVar:
|
|
317
321
|
"""Round the number.
|
|
318
322
|
|
|
323
|
+
Args:
|
|
324
|
+
ndigits: The number of digits to round.
|
|
325
|
+
|
|
319
326
|
Returns:
|
|
320
327
|
The number round operation.
|
|
321
328
|
"""
|
|
322
|
-
|
|
329
|
+
if not isinstance(ndigits, NUMBER_TYPES):
|
|
330
|
+
raise_unsupported_operand_types("round", (type(self), type(ndigits)))
|
|
331
|
+
|
|
332
|
+
return number_round_operation(self, +ndigits)
|
|
323
333
|
|
|
324
334
|
def __ceil__(self):
|
|
325
335
|
"""Ceil the number.
|
|
@@ -653,16 +663,23 @@ def number_exponent_operation(lhs: NumberVar, rhs: NumberVar):
|
|
|
653
663
|
|
|
654
664
|
|
|
655
665
|
@var_operation
|
|
656
|
-
def number_round_operation(value: NumberVar):
|
|
666
|
+
def number_round_operation(value: NumberVar, ndigits: NumberVar | int):
|
|
657
667
|
"""Round the number.
|
|
658
668
|
|
|
659
669
|
Args:
|
|
660
670
|
value: The number.
|
|
671
|
+
ndigits: The number of digits.
|
|
661
672
|
|
|
662
673
|
Returns:
|
|
663
674
|
The number round operation.
|
|
664
675
|
"""
|
|
665
|
-
|
|
676
|
+
if (isinstance(ndigits, LiteralNumberVar) and ndigits._var_value == 0) or (
|
|
677
|
+
isinstance(ndigits, int) and ndigits == 0
|
|
678
|
+
):
|
|
679
|
+
return var_operation_return(js_expression=f"Math.round({value})", var_type=int)
|
|
680
|
+
return var_operation_return(
|
|
681
|
+
js_expression=f"(+{value}.toFixed({ndigits}))", var_type=float
|
|
682
|
+
)
|
|
666
683
|
|
|
667
684
|
|
|
668
685
|
@var_operation
|
|
@@ -1064,7 +1081,7 @@ U = TypeVar("U")
|
|
|
1064
1081
|
|
|
1065
1082
|
@var_operation
|
|
1066
1083
|
def ternary_operation(
|
|
1067
|
-
condition:
|
|
1084
|
+
condition: Var[bool], if_true: Var[T], if_false: Var[U]
|
|
1068
1085
|
) -> CustomVarOperationReturn[T | U]:
|
|
1069
1086
|
"""Create a ternary operation.
|
|
1070
1087
|
|
reflex/vars/sequence.py
CHANGED
|
@@ -1604,6 +1604,8 @@ def _determine_value_of_array_index(
|
|
|
1604
1604
|
return args[0] if args else Any
|
|
1605
1605
|
if origin_var_type is tuple:
|
|
1606
1606
|
args = get_args(var_type)
|
|
1607
|
+
if len(args) == 2 and args[1] is ...:
|
|
1608
|
+
return args[0]
|
|
1607
1609
|
return (
|
|
1608
1610
|
args[int(index) % len(args)]
|
|
1609
1611
|
if args and index is not None
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: reflex
|
|
3
|
-
Version: 0.7.
|
|
3
|
+
Version: 0.7.5a1
|
|
4
4
|
Summary: Web apps in pure Python.
|
|
5
5
|
Project-URL: homepage, https://reflex.dev
|
|
6
6
|
Project-URL: repository, https://github.com/reflex-dev/reflex
|
|
@@ -23,7 +23,7 @@ Requires-Dist: build<2.0,>=1.0.3
|
|
|
23
23
|
Requires-Dist: charset-normalizer<4.0,>=3.3.2
|
|
24
24
|
Requires-Dist: distro<2.0,>=1.8.0; platform_system == 'Linux'
|
|
25
25
|
Requires-Dist: fastapi!=0.111.0,!=0.111.1,>=0.96.0
|
|
26
|
-
Requires-Dist: granian[reload]>=2.
|
|
26
|
+
Requires-Dist: granian[reload]>=2.2.0
|
|
27
27
|
Requires-Dist: gunicorn<24.0.0,>=23.0.0
|
|
28
28
|
Requires-Dist: httpx<1.0,>=0.25.1
|
|
29
29
|
Requires-Dist: jinja2<4.0,>=3.1.2
|