reflex 0.7.13a2__py3-none-any.whl → 0.7.14__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/apps/blank/code/blank.py +0 -2
- reflex/app.py +85 -89
- reflex/app_mixins/lifespan.py +2 -3
- reflex/app_mixins/middleware.py +1 -0
- reflex/app_mixins/mixin.py +0 -1
- reflex/assets.py +7 -4
- reflex/base.py +3 -2
- reflex/compiler/compiler.py +79 -65
- reflex/compiler/utils.py +8 -6
- reflex/components/base/app_wrap.pyi +0 -1
- reflex/components/base/bare.py +22 -12
- reflex/components/base/body.pyi +0 -1
- reflex/components/base/document.pyi +0 -5
- reflex/components/base/error_boundary.pyi +0 -1
- reflex/components/base/fragment.pyi +0 -1
- reflex/components/base/head.pyi +0 -2
- reflex/components/base/link.pyi +0 -2
- reflex/components/base/meta.py +2 -1
- reflex/components/base/meta.pyi +0 -4
- reflex/components/base/script.py +2 -1
- reflex/components/base/script.pyi +0 -1
- reflex/components/base/strict_mode.pyi +0 -1
- reflex/components/component.py +85 -45
- reflex/components/core/auto_scroll.pyi +0 -1
- reflex/components/core/banner.py +1 -1
- reflex/components/core/banner.pyi +0 -6
- reflex/components/core/breakpoints.py +9 -11
- reflex/components/core/client_side_routing.pyi +0 -2
- reflex/components/core/clipboard.pyi +0 -1
- reflex/components/core/colors.py +10 -7
- reflex/components/core/cond.py +4 -2
- reflex/components/core/debounce.py +5 -3
- reflex/components/core/debounce.pyi +0 -1
- reflex/components/core/foreach.py +8 -6
- reflex/components/core/html.py +3 -3
- reflex/components/core/html.pyi +0 -1
- reflex/components/core/match.py +19 -17
- reflex/components/core/sticky.pyi +0 -4
- reflex/components/core/upload.py +1 -1
- reflex/components/core/upload.pyi +0 -5
- reflex/components/datadisplay/code.py +1 -2
- reflex/components/datadisplay/code.pyi +0 -2
- reflex/components/datadisplay/dataeditor.py +7 -10
- reflex/components/datadisplay/dataeditor.pyi +0 -1
- reflex/components/datadisplay/logo.py +3 -4
- reflex/components/datadisplay/shiki_code_block.py +8 -11
- reflex/components/datadisplay/shiki_code_block.pyi +0 -3
- reflex/components/dynamic.py +2 -3
- reflex/components/el/__init__.pyi +2 -0
- reflex/components/el/element.pyi +0 -1
- reflex/components/el/elements/__init__.py +1 -0
- reflex/components/el/elements/__init__.pyi +3 -0
- reflex/components/el/elements/base.pyi +0 -1
- reflex/components/el/elements/forms.py +14 -15
- reflex/components/el/elements/forms.pyi +15 -32
- reflex/components/el/elements/inline.pyi +0 -28
- reflex/components/el/elements/media.py +26 -0
- reflex/components/el/elements/media.pyi +259 -25
- reflex/components/el/elements/metadata.py +0 -1
- reflex/components/el/elements/metadata.pyi +0 -6
- reflex/components/el/elements/other.pyi +0 -7
- reflex/components/el/elements/scripts.pyi +0 -3
- reflex/components/el/elements/sectioning.pyi +0 -15
- reflex/components/el/elements/tables.pyi +0 -10
- reflex/components/el/elements/typography.pyi +0 -15
- reflex/components/gridjs/datatable.py +10 -13
- reflex/components/gridjs/datatable.pyi +0 -2
- reflex/components/lucide/icon.py +10 -9
- reflex/components/lucide/icon.pyi +0 -3
- reflex/components/markdown/markdown.py +6 -8
- reflex/components/markdown/markdown.pyi +0 -1
- reflex/components/moment/moment.pyi +0 -1
- reflex/components/next/base.py +0 -2
- reflex/components/next/base.pyi +0 -3
- reflex/components/next/image.pyi +0 -1
- reflex/components/next/link.pyi +0 -1
- reflex/components/next/video.pyi +0 -1
- reflex/components/plotly/plotly.pyi +0 -9
- reflex/components/props.py +4 -3
- reflex/components/radix/primitives/accordion.pyi +0 -7
- reflex/components/radix/primitives/base.py +1 -3
- reflex/components/radix/primitives/base.pyi +0 -2
- reflex/components/radix/primitives/drawer.pyi +0 -11
- reflex/components/radix/primitives/form.py +4 -8
- reflex/components/radix/primitives/form.pyi +0 -12
- reflex/components/radix/primitives/progress.py +1 -1
- reflex/components/radix/primitives/progress.pyi +0 -5
- reflex/components/radix/primitives/slider.py +1 -1
- reflex/components/radix/primitives/slider.pyi +0 -5
- reflex/components/radix/themes/base.pyi +0 -8
- reflex/components/radix/themes/color_mode.pyi +0 -3
- reflex/components/radix/themes/components/alert_dialog.py +4 -2
- reflex/components/radix/themes/components/alert_dialog.pyi +4 -9
- reflex/components/radix/themes/components/aspect_ratio.py +1 -2
- reflex/components/radix/themes/components/aspect_ratio.pyi +1 -3
- reflex/components/radix/themes/components/avatar.py +5 -2
- reflex/components/radix/themes/components/avatar.pyi +1 -3
- reflex/components/radix/themes/components/badge.py +5 -2
- reflex/components/radix/themes/components/badge.pyi +1 -3
- reflex/components/radix/themes/components/button.py +2 -3
- reflex/components/radix/themes/components/button.pyi +1 -3
- reflex/components/radix/themes/components/callout.py +1 -2
- reflex/components/radix/themes/components/callout.pyi +1 -7
- reflex/components/radix/themes/components/card.py +1 -2
- reflex/components/radix/themes/components/card.pyi +1 -3
- reflex/components/radix/themes/components/checkbox.py +7 -4
- reflex/components/radix/themes/components/checkbox.pyi +1 -5
- reflex/components/radix/themes/components/checkbox_cards.py +1 -2
- reflex/components/radix/themes/components/checkbox_cards.pyi +1 -4
- reflex/components/radix/themes/components/checkbox_group.py +1 -2
- reflex/components/radix/themes/components/checkbox_group.pyi +1 -4
- reflex/components/radix/themes/components/context_menu.py +1 -1
- reflex/components/radix/themes/components/context_menu.pyi +1 -14
- reflex/components/radix/themes/components/data_list.py +1 -2
- reflex/components/radix/themes/components/data_list.pyi +1 -6
- reflex/components/radix/themes/components/dialog.py +4 -2
- reflex/components/radix/themes/components/dialog.pyi +4 -9
- reflex/components/radix/themes/components/dropdown_menu.py +5 -2
- reflex/components/radix/themes/components/dropdown_menu.pyi +4 -10
- reflex/components/radix/themes/components/hover_card.py +4 -2
- reflex/components/radix/themes/components/hover_card.pyi +4 -6
- reflex/components/radix/themes/components/icon_button.py +7 -8
- reflex/components/radix/themes/components/icon_button.pyi +1 -3
- reflex/components/radix/themes/components/inset.py +1 -2
- reflex/components/radix/themes/components/inset.pyi +1 -3
- reflex/components/radix/themes/components/popover.py +4 -2
- reflex/components/radix/themes/components/popover.pyi +4 -6
- reflex/components/radix/themes/components/progress.py +1 -2
- reflex/components/radix/themes/components/progress.pyi +1 -3
- reflex/components/radix/themes/components/radio.py +1 -2
- reflex/components/radix/themes/components/radio.pyi +1 -3
- reflex/components/radix/themes/components/radio_cards.py +1 -2
- reflex/components/radix/themes/components/radio_cards.pyi +1 -4
- reflex/components/radix/themes/components/radio_group.py +7 -5
- reflex/components/radix/themes/components/radio_group.pyi +1 -6
- reflex/components/radix/themes/components/scroll_area.py +1 -2
- reflex/components/radix/themes/components/scroll_area.pyi +1 -3
- reflex/components/radix/themes/components/segmented_control.py +1 -2
- reflex/components/radix/themes/components/segmented_control.pyi +1 -4
- reflex/components/radix/themes/components/select.py +5 -2
- reflex/components/radix/themes/components/select.pyi +1 -11
- reflex/components/radix/themes/components/separator.py +1 -2
- reflex/components/radix/themes/components/separator.pyi +1 -3
- reflex/components/radix/themes/components/skeleton.py +1 -2
- reflex/components/radix/themes/components/skeleton.pyi +1 -3
- reflex/components/radix/themes/components/slider.py +1 -2
- reflex/components/radix/themes/components/slider.pyi +1 -3
- reflex/components/radix/themes/components/spinner.py +1 -2
- reflex/components/radix/themes/components/spinner.pyi +1 -3
- reflex/components/radix/themes/components/switch.py +1 -2
- reflex/components/radix/themes/components/switch.pyi +1 -3
- reflex/components/radix/themes/components/table.py +1 -2
- reflex/components/radix/themes/components/table.pyi +1 -9
- reflex/components/radix/themes/components/tabs.py +1 -2
- reflex/components/radix/themes/components/tabs.pyi +1 -7
- reflex/components/radix/themes/components/text_area.py +5 -2
- reflex/components/radix/themes/components/text_area.pyi +2 -4
- reflex/components/radix/themes/components/text_field.py +5 -2
- reflex/components/radix/themes/components/text_field.pyi +1 -5
- reflex/components/radix/themes/components/tooltip.py +1 -2
- reflex/components/radix/themes/components/tooltip.pyi +1 -3
- reflex/components/radix/themes/layout/base.py +5 -2
- reflex/components/radix/themes/layout/base.pyi +5 -3
- reflex/components/radix/themes/layout/box.py +1 -2
- reflex/components/radix/themes/layout/box.pyi +1 -3
- reflex/components/radix/themes/layout/center.pyi +0 -1
- reflex/components/radix/themes/layout/container.py +1 -2
- reflex/components/radix/themes/layout/container.pyi +1 -3
- reflex/components/radix/themes/layout/flex.py +6 -2
- reflex/components/radix/themes/layout/flex.pyi +1 -3
- reflex/components/radix/themes/layout/grid.py +6 -2
- reflex/components/radix/themes/layout/grid.pyi +1 -3
- reflex/components/radix/themes/layout/list.py +2 -1
- reflex/components/radix/themes/layout/list.pyi +0 -5
- reflex/components/radix/themes/layout/section.py +1 -2
- reflex/components/radix/themes/layout/section.pyi +1 -3
- reflex/components/radix/themes/layout/spacer.pyi +0 -1
- reflex/components/radix/themes/layout/stack.py +1 -1
- reflex/components/radix/themes/layout/stack.pyi +0 -3
- reflex/components/radix/themes/typography/blockquote.py +1 -1
- reflex/components/radix/themes/typography/blockquote.pyi +1 -3
- reflex/components/radix/themes/typography/code.py +5 -1
- reflex/components/radix/themes/typography/code.pyi +1 -3
- reflex/components/radix/themes/typography/heading.py +1 -1
- reflex/components/radix/themes/typography/heading.pyi +1 -3
- reflex/components/radix/themes/typography/link.py +3 -2
- reflex/components/radix/themes/typography/link.pyi +1 -3
- reflex/components/radix/themes/typography/text.py +1 -1
- reflex/components/radix/themes/typography/text.pyi +1 -9
- reflex/components/react_player/audio.py +0 -2
- reflex/components/react_player/audio.pyi +0 -3
- reflex/components/react_player/react_player.pyi +0 -1
- reflex/components/react_player/video.py +0 -2
- reflex/components/react_player/video.pyi +0 -3
- reflex/components/recharts/__init__.py +1 -1
- reflex/components/recharts/__init__.pyi +1 -1
- reflex/components/recharts/cartesian.py +20 -25
- reflex/components/recharts/cartesian.pyi +20 -37
- reflex/components/recharts/charts.py +2 -1
- reflex/components/recharts/charts.pyi +0 -12
- reflex/components/recharts/general.pyi +0 -6
- reflex/components/recharts/polar.py +5 -4
- reflex/components/recharts/polar.pyi +4 -10
- reflex/components/recharts/recharts.py +12 -10
- reflex/components/recharts/recharts.pyi +10 -11
- reflex/components/sonner/toast.py +2 -2
- reflex/components/sonner/toast.pyi +0 -2
- reflex/components/suneditor/editor.py +2 -1
- reflex/components/suneditor/editor.pyi +0 -1
- reflex/components/tags/iter_tag.py +4 -2
- reflex/config.py +41 -615
- reflex/constants/base.py +6 -6
- reflex/constants/compiler.py +8 -6
- reflex/constants/installer.py +25 -16
- reflex/custom_components/custom_components.py +1 -2
- reflex/environment.py +606 -0
- reflex/event.py +58 -60
- reflex/experimental/__init__.py +2 -2
- reflex/experimental/client_state.py +9 -4
- reflex/experimental/layout.pyi +0 -5
- reflex/istate/manager.py +17 -20
- reflex/istate/proxy.py +19 -12
- reflex/model.py +8 -5
- reflex/plugins/base.py +8 -0
- reflex/plugins/tailwind_v3.py +8 -0
- reflex/plugins/tailwind_v4.py +8 -0
- reflex/reflex.py +11 -12
- reflex/route.py +7 -9
- reflex/state.py +67 -71
- reflex/style.py +3 -1
- reflex/testing.py +49 -30
- reflex/utils/build.py +2 -1
- reflex/utils/console.py +70 -17
- reflex/utils/exec.py +113 -39
- reflex/utils/export.py +2 -1
- reflex/utils/format.py +21 -24
- reflex/utils/imports.py +4 -3
- reflex/utils/lazy_loader.py +3 -3
- reflex/utils/misc.py +2 -1
- reflex/utils/net.py +2 -2
- reflex/utils/path_ops.py +4 -2
- reflex/utils/prerequisites.py +69 -39
- reflex/utils/processes.py +5 -7
- reflex/utils/pyi_generator.py +46 -41
- reflex/utils/redir.py +1 -1
- reflex/utils/registry.py +1 -1
- reflex/utils/serializers.py +4 -4
- reflex/utils/telemetry.py +36 -3
- reflex/utils/types.py +16 -13
- reflex/vars/base.py +96 -109
- reflex/vars/datetime.py +2 -1
- reflex/vars/dep_tracking.py +19 -28
- reflex/vars/number.py +6 -7
- reflex/vars/object.py +5 -6
- reflex/vars/sequence.py +11 -11
- {reflex-0.7.13a2.dist-info → reflex-0.7.14.dist-info}/METADATA +1 -1
- reflex-0.7.14.dist-info/RECORD +408 -0
- reflex-0.7.13a2.dist-info/RECORD +0 -407
- {reflex-0.7.13a2.dist-info → reflex-0.7.14.dist-info}/WHEEL +0 -0
- {reflex-0.7.13a2.dist-info → reflex-0.7.14.dist-info}/entry_points.txt +0 -0
- {reflex-0.7.13a2.dist-info → reflex-0.7.14.dist-info}/licenses/LICENSE +0 -0
reflex/utils/pyi_generator.py
CHANGED
|
@@ -30,6 +30,8 @@ logger = logging.getLogger("pyi_generator")
|
|
|
30
30
|
|
|
31
31
|
PWD = Path.cwd()
|
|
32
32
|
|
|
33
|
+
PYI_HASHES = "pyi_hashes.json"
|
|
34
|
+
|
|
33
35
|
EXCLUDED_FILES = [
|
|
34
36
|
"app.py",
|
|
35
37
|
"component.py",
|
|
@@ -157,9 +159,8 @@ def _get_type_hint(
|
|
|
157
159
|
res_args.sort()
|
|
158
160
|
if len(res_args) == 1:
|
|
159
161
|
return f"{res_args[0]} | None"
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
return f"{res} | None"
|
|
162
|
+
res = f"{' | '.join(res_args)}"
|
|
163
|
+
return f"{res} | None"
|
|
163
164
|
|
|
164
165
|
res_args = [
|
|
165
166
|
_get_type_hint(arg, type_hint_globals, rx_types.is_optional(arg))
|
|
@@ -183,10 +184,11 @@ def _get_type_hint(
|
|
|
183
184
|
value.__module__ not in ["builtins", "__builtins__"]
|
|
184
185
|
and value.__name__ not in type_hint_globals
|
|
185
186
|
):
|
|
186
|
-
|
|
187
|
+
msg = (
|
|
187
188
|
f"{value.__module__ + '.' + value.__name__} is not a default import, "
|
|
188
189
|
"add it to DEFAULT_IMPORTS in pyi_generator.py"
|
|
189
190
|
)
|
|
191
|
+
raise TypeError(msg)
|
|
190
192
|
|
|
191
193
|
res = f"{value.__name__}[{', '.join(inner_container_type_args)}]"
|
|
192
194
|
|
|
@@ -445,7 +447,7 @@ def type_to_ast(typ: Any, cls: type) -> ast.expr:
|
|
|
445
447
|
|
|
446
448
|
return ast.Name(id=typ.__module__ + "." + typ.__name__)
|
|
447
449
|
return ast.Name(id=typ.__name__)
|
|
448
|
-
|
|
450
|
+
if hasattr(typ, "_name"):
|
|
449
451
|
return ast.Name(id=typ._name)
|
|
450
452
|
return ast.Name(id=str(typ))
|
|
451
453
|
|
|
@@ -510,7 +512,8 @@ def _generate_component_create_functiondef(
|
|
|
510
512
|
TypeError: If clz is not a subclass of Component.
|
|
511
513
|
"""
|
|
512
514
|
if not issubclass(clz, Component):
|
|
513
|
-
|
|
515
|
+
msg = f"clz must be a subclass of Component, not {clz!r}"
|
|
516
|
+
raise TypeError(msg)
|
|
514
517
|
|
|
515
518
|
# add the imports needed by get_type_hint later
|
|
516
519
|
type_hint_globals.update(
|
|
@@ -654,7 +657,7 @@ def _generate_component_create_functiondef(
|
|
|
654
657
|
defaults=[],
|
|
655
658
|
)
|
|
656
659
|
|
|
657
|
-
|
|
660
|
+
return ast.FunctionDef( # pyright: ignore [reportCallIssue]
|
|
658
661
|
name="create",
|
|
659
662
|
args=create_args,
|
|
660
663
|
body=[
|
|
@@ -676,7 +679,6 @@ def _generate_component_create_functiondef(
|
|
|
676
679
|
lineno=lineno,
|
|
677
680
|
returns=ast.Constant(value=clz.__name__),
|
|
678
681
|
)
|
|
679
|
-
return definition
|
|
680
682
|
|
|
681
683
|
|
|
682
684
|
def _generate_staticmethod_call_functiondef(
|
|
@@ -710,7 +712,7 @@ def _generate_staticmethod_call_functiondef(
|
|
|
710
712
|
else []
|
|
711
713
|
),
|
|
712
714
|
)
|
|
713
|
-
|
|
715
|
+
return ast.FunctionDef( # pyright: ignore [reportCallIssue]
|
|
714
716
|
name="__call__",
|
|
715
717
|
args=call_args,
|
|
716
718
|
body=[
|
|
@@ -729,7 +731,6 @@ def _generate_staticmethod_call_functiondef(
|
|
|
729
731
|
)
|
|
730
732
|
),
|
|
731
733
|
)
|
|
732
|
-
return definition
|
|
733
734
|
|
|
734
735
|
|
|
735
736
|
def _generate_namespace_call_functiondef(
|
|
@@ -841,6 +842,7 @@ class StubGenerator(ast.NodeTransformer):
|
|
|
841
842
|
and issubclass((clz := self.classes[self.current_class]), Component)
|
|
842
843
|
):
|
|
843
844
|
return clz
|
|
845
|
+
return None
|
|
844
846
|
|
|
845
847
|
def visit_Module(self, node: ast.Module) -> ast.Module:
|
|
846
848
|
"""Visit a Module node and remove docstring from body.
|
|
@@ -1021,7 +1023,7 @@ class StubGenerator(ast.NodeTransformer):
|
|
|
1021
1023
|
if isinstance(target, ast.Tuple):
|
|
1022
1024
|
for name in target.elts:
|
|
1023
1025
|
if isinstance(name, ast.Name) and name.id.startswith("_"):
|
|
1024
|
-
return
|
|
1026
|
+
return None
|
|
1025
1027
|
|
|
1026
1028
|
return node
|
|
1027
1029
|
|
|
@@ -1107,7 +1109,7 @@ class PyiGenerator:
|
|
|
1107
1109
|
pyright_ignore_imports = getattr(mod, "_PYRIGHT_IGNORE_IMPORTS", [])
|
|
1108
1110
|
|
|
1109
1111
|
if not sub_mods and not sub_mod_attrs:
|
|
1110
|
-
return
|
|
1112
|
+
return None
|
|
1111
1113
|
sub_mods_imports = []
|
|
1112
1114
|
sub_mod_attrs_imports = []
|
|
1113
1115
|
|
|
@@ -1162,7 +1164,7 @@ class PyiGenerator:
|
|
|
1162
1164
|
}
|
|
1163
1165
|
is_init_file = _relative_to_pwd(module_path).name == "__init__.py"
|
|
1164
1166
|
if not class_names and not is_init_file:
|
|
1165
|
-
return
|
|
1167
|
+
return None
|
|
1166
1168
|
|
|
1167
1169
|
if is_init_file:
|
|
1168
1170
|
new_tree = InitStubGenerator(module, class_names).visit(
|
|
@@ -1170,7 +1172,7 @@ class PyiGenerator:
|
|
|
1170
1172
|
)
|
|
1171
1173
|
init_imports = self._get_init_lazy_imports(module, new_tree)
|
|
1172
1174
|
if not init_imports:
|
|
1173
|
-
return
|
|
1175
|
+
return None
|
|
1174
1176
|
content_hash = self._write_pyi_file(module_path, init_imports)
|
|
1175
1177
|
else:
|
|
1176
1178
|
new_tree = StubGenerator(module, class_names).visit(
|
|
@@ -1264,45 +1266,48 @@ class PyiGenerator:
|
|
|
1264
1266
|
file_parent = file_path.parent
|
|
1265
1267
|
while len(file_parent.parts) > len(top_dir.parts):
|
|
1266
1268
|
file_parent = file_parent.parent
|
|
1269
|
+
while len(top_dir.parts) > len(file_parent.parts):
|
|
1270
|
+
top_dir = top_dir.parent
|
|
1267
1271
|
while not file_parent.samefile(top_dir):
|
|
1268
1272
|
file_parent = file_parent.parent
|
|
1269
1273
|
top_dir = top_dir.parent
|
|
1270
1274
|
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
pyi_hashes_file.
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1275
|
+
while (
|
|
1276
|
+
not top_dir.samefile(top_dir.parent)
|
|
1277
|
+
and not (top_dir / PYI_HASHES).exists()
|
|
1278
|
+
):
|
|
1279
|
+
top_dir = top_dir.parent
|
|
1280
|
+
|
|
1281
|
+
pyi_hashes_file = top_dir / PYI_HASHES
|
|
1282
|
+
|
|
1283
|
+
if pyi_hashes_file.exists():
|
|
1284
|
+
pyi_hashes_file.write_text(
|
|
1285
|
+
json.dumps(
|
|
1286
|
+
dict(
|
|
1287
|
+
zip(
|
|
1288
|
+
[
|
|
1289
|
+
f.relative_to(pyi_hashes_file.parent).as_posix()
|
|
1290
|
+
for f in file_paths
|
|
1291
|
+
],
|
|
1292
|
+
hashes,
|
|
1293
|
+
strict=True,
|
|
1294
|
+
)
|
|
1295
|
+
),
|
|
1296
|
+
indent=2,
|
|
1297
|
+
sort_keys=True,
|
|
1298
|
+
)
|
|
1299
|
+
+ "\n",
|
|
1293
1300
|
)
|
|
1294
|
-
+ "\n",
|
|
1295
|
-
)
|
|
1296
1301
|
elif file_paths:
|
|
1297
1302
|
file_paths = list(map(Path, file_paths))
|
|
1298
1303
|
pyi_hashes_parent = file_paths[0].parent
|
|
1299
1304
|
while (
|
|
1300
|
-
pyi_hashes_parent.parent
|
|
1301
|
-
and not (pyi_hashes_parent /
|
|
1305
|
+
not pyi_hashes_parent.samefile(pyi_hashes_parent.parent)
|
|
1306
|
+
and not (pyi_hashes_parent / PYI_HASHES).exists()
|
|
1302
1307
|
):
|
|
1303
1308
|
pyi_hashes_parent = pyi_hashes_parent.parent
|
|
1304
1309
|
|
|
1305
|
-
pyi_hashes_file = pyi_hashes_parent /
|
|
1310
|
+
pyi_hashes_file = pyi_hashes_parent / PYI_HASHES
|
|
1306
1311
|
if pyi_hashes_file.exists():
|
|
1307
1312
|
pyi_hashes = json.loads(pyi_hashes_file.read_text())
|
|
1308
1313
|
for file_path, hashed_content in zip(
|
reflex/utils/redir.py
CHANGED
reflex/utils/registry.py
CHANGED
reflex/utils/serializers.py
CHANGED
|
@@ -76,7 +76,8 @@ def serializer(
|
|
|
76
76
|
|
|
77
77
|
# Make sure the function takes a single argument.
|
|
78
78
|
if len(args) != 1:
|
|
79
|
-
|
|
79
|
+
msg = "Serializer must take a single argument."
|
|
80
|
+
raise ValueError(msg)
|
|
80
81
|
|
|
81
82
|
# Get the type of the argument.
|
|
82
83
|
type_ = type_hints[args[0]]
|
|
@@ -166,8 +167,7 @@ def serialize(
|
|
|
166
167
|
# Return the serialized value and the type.
|
|
167
168
|
if get_type:
|
|
168
169
|
return serialized, get_serializer_type(type(value))
|
|
169
|
-
|
|
170
|
-
return serialized
|
|
170
|
+
return serialized
|
|
171
171
|
|
|
172
172
|
|
|
173
173
|
@functools.lru_cache
|
|
@@ -427,7 +427,7 @@ with contextlib.suppress(ImportError):
|
|
|
427
427
|
"""
|
|
428
428
|
return [
|
|
429
429
|
[str(d) if isinstance(d, (list, tuple)) else d for d in data]
|
|
430
|
-
for data in list(df.
|
|
430
|
+
for data in list(df.to_numpy().tolist())
|
|
431
431
|
]
|
|
432
432
|
|
|
433
433
|
@serializer
|
reflex/utils/telemetry.py
CHANGED
|
@@ -4,6 +4,7 @@ from __future__ import annotations
|
|
|
4
4
|
|
|
5
5
|
import asyncio
|
|
6
6
|
import dataclasses
|
|
7
|
+
import importlib.metadata
|
|
7
8
|
import multiprocessing
|
|
8
9
|
import platform
|
|
9
10
|
import warnings
|
|
@@ -15,11 +16,16 @@ import httpx
|
|
|
15
16
|
import psutil
|
|
16
17
|
|
|
17
18
|
from reflex import constants
|
|
18
|
-
from reflex.
|
|
19
|
+
from reflex.environment import environment
|
|
19
20
|
from reflex.utils import console
|
|
20
21
|
from reflex.utils.decorator import once_unless_none
|
|
21
22
|
from reflex.utils.exceptions import ReflexError
|
|
22
|
-
from reflex.utils.prerequisites import
|
|
23
|
+
from reflex.utils.prerequisites import (
|
|
24
|
+
ensure_reflex_installation_id,
|
|
25
|
+
get_bun_version,
|
|
26
|
+
get_node_version,
|
|
27
|
+
get_project_hash,
|
|
28
|
+
)
|
|
23
29
|
|
|
24
30
|
UTC = timezone.utc
|
|
25
31
|
POSTHOG_API_URL: str = "https://app.posthog.com/capture/"
|
|
@@ -71,6 +77,18 @@ def get_cpu_count() -> int:
|
|
|
71
77
|
return multiprocessing.cpu_count()
|
|
72
78
|
|
|
73
79
|
|
|
80
|
+
def get_reflex_enterprise_version() -> str | None:
|
|
81
|
+
"""Get the version of reflex-enterprise if installed.
|
|
82
|
+
|
|
83
|
+
Returns:
|
|
84
|
+
The version string if installed, None if not installed.
|
|
85
|
+
"""
|
|
86
|
+
try:
|
|
87
|
+
return importlib.metadata.version("reflex-enterprise")
|
|
88
|
+
except importlib.metadata.PackageNotFoundError:
|
|
89
|
+
return None
|
|
90
|
+
|
|
91
|
+
|
|
74
92
|
def get_memory() -> int:
|
|
75
93
|
"""Get the total memory in MB.
|
|
76
94
|
|
|
@@ -106,6 +124,9 @@ class _Properties(TypedDict):
|
|
|
106
124
|
user_os_detail: str
|
|
107
125
|
reflex_version: str
|
|
108
126
|
python_version: str
|
|
127
|
+
node_version: str | None
|
|
128
|
+
bun_version: str | None
|
|
129
|
+
reflex_enterprise_version: str | None
|
|
109
130
|
cpu_count: int
|
|
110
131
|
memory: int
|
|
111
132
|
cpu_info: dict
|
|
@@ -153,6 +174,13 @@ def _get_event_defaults() -> _DefaultEvent | None:
|
|
|
153
174
|
"user_os_detail": get_detailed_platform_str(),
|
|
154
175
|
"reflex_version": get_reflex_version(),
|
|
155
176
|
"python_version": get_python_version(),
|
|
177
|
+
"node_version": (
|
|
178
|
+
str(node_version) if (node_version := get_node_version()) else None
|
|
179
|
+
),
|
|
180
|
+
"bun_version": (
|
|
181
|
+
str(bun_version) if (bun_version := get_bun_version()) else None
|
|
182
|
+
),
|
|
183
|
+
"reflex_enterprise_version": get_reflex_enterprise_version(),
|
|
156
184
|
"cpu_count": get_cpu_count(),
|
|
157
185
|
"memory": get_memory(),
|
|
158
186
|
"cpu_info": dataclasses.asdict(cpuinfo) if cpuinfo else {},
|
|
@@ -232,6 +260,9 @@ def _send(event: str, telemetry_enabled: bool | None, **kwargs) -> bool:
|
|
|
232
260
|
return False
|
|
233
261
|
|
|
234
262
|
|
|
263
|
+
background_tasks = set()
|
|
264
|
+
|
|
265
|
+
|
|
235
266
|
def send(event: str, telemetry_enabled: bool | None = None, **kwargs):
|
|
236
267
|
"""Send anonymous telemetry for Reflex.
|
|
237
268
|
|
|
@@ -246,7 +277,9 @@ def send(event: str, telemetry_enabled: bool | None = None, **kwargs):
|
|
|
246
277
|
|
|
247
278
|
try:
|
|
248
279
|
# Within an event loop context, send the event asynchronously.
|
|
249
|
-
asyncio.create_task(async_send(event, telemetry_enabled, **kwargs))
|
|
280
|
+
task = asyncio.create_task(async_send(event, telemetry_enabled, **kwargs))
|
|
281
|
+
background_tasks.add(task)
|
|
282
|
+
task.add_done_callback(background_tasks.discard)
|
|
250
283
|
except RuntimeError:
|
|
251
284
|
# If there is no event loop, send the event synchronously.
|
|
252
285
|
warnings.filterwarnings("ignore", category=RuntimeWarning)
|
reflex/utils/types.py
CHANGED
|
@@ -263,8 +263,12 @@ def is_classvar(a_type: Any) -> bool:
|
|
|
263
263
|
Returns:
|
|
264
264
|
Whether the type is a ClassVar.
|
|
265
265
|
"""
|
|
266
|
-
return
|
|
267
|
-
|
|
266
|
+
return (
|
|
267
|
+
a_type is ClassVar
|
|
268
|
+
or (type(a_type) is _GenericAlias and a_type.__origin__ is ClassVar)
|
|
269
|
+
or (
|
|
270
|
+
type(a_type) is ForwardRef and a_type.__forward_arg__.startswith("ClassVar")
|
|
271
|
+
)
|
|
268
272
|
)
|
|
269
273
|
|
|
270
274
|
|
|
@@ -378,7 +382,7 @@ def get_attribute_access_type(cls: GenericType, name: str) -> GenericType | None
|
|
|
378
382
|
if hasattr(cls, "__fields__") and name in cls.__fields__:
|
|
379
383
|
# pydantic models
|
|
380
384
|
return get_field_type(cls, name)
|
|
381
|
-
|
|
385
|
+
if isinstance(cls, type) and issubclass(cls, DeclarativeBase):
|
|
382
386
|
insp = sqlalchemy.inspect(cls)
|
|
383
387
|
if name in insp.columns:
|
|
384
388
|
# check for list types
|
|
@@ -410,8 +414,7 @@ def get_attribute_access_type(cls: GenericType, name: str) -> GenericType | None
|
|
|
410
414
|
if isinstance(prop, Relationship):
|
|
411
415
|
type_ = prop.mapper.class_
|
|
412
416
|
# TODO: check for nullable?
|
|
413
|
-
|
|
414
|
-
return type_
|
|
417
|
+
return list[type_] if prop.uselist else type_ | None
|
|
415
418
|
if isinstance(attr, AssociationProxyInstance):
|
|
416
419
|
return list[
|
|
417
420
|
get_attribute_access_type(
|
|
@@ -444,7 +447,6 @@ def get_attribute_access_type(cls: GenericType, name: str) -> GenericType | None
|
|
|
444
447
|
return hints[name]
|
|
445
448
|
except exceptions as e:
|
|
446
449
|
console.warn(f"Failed to resolve ForwardRefs for {cls}.{name} due to {e}")
|
|
447
|
-
pass
|
|
448
450
|
return None # Attribute is not accessible.
|
|
449
451
|
|
|
450
452
|
|
|
@@ -465,7 +467,8 @@ def get_base_class(cls: GenericType) -> type:
|
|
|
465
467
|
# only literals of the same type are supported.
|
|
466
468
|
arg_type = type(get_args(cls)[0])
|
|
467
469
|
if not all(type(arg) is arg_type for arg in get_args(cls)):
|
|
468
|
-
|
|
470
|
+
msg = "only literals of the same type are supported"
|
|
471
|
+
raise TypeError(msg)
|
|
469
472
|
return type(get_args(cls)[0])
|
|
470
473
|
|
|
471
474
|
if is_union(cls):
|
|
@@ -493,13 +496,13 @@ def _breakpoints_satisfies_typing(cls_check: GenericType, instance: Any) -> bool
|
|
|
493
496
|
if not isinstance(value, str) or value not in get_args(expected_type):
|
|
494
497
|
return False
|
|
495
498
|
return True
|
|
496
|
-
|
|
499
|
+
if isinstance(cls_check_base, tuple):
|
|
497
500
|
# union type, so check all types
|
|
498
501
|
return any(
|
|
499
502
|
_breakpoints_satisfies_typing(type_to_check, instance)
|
|
500
503
|
for type_to_check in get_args(cls_check)
|
|
501
504
|
)
|
|
502
|
-
|
|
505
|
+
if cls_check_base == reflex.vars.Var and "__args__" in cls_check.__dict__:
|
|
503
506
|
return _breakpoints_satisfies_typing(get_args(cls_check)[0], instance)
|
|
504
507
|
|
|
505
508
|
return False
|
|
@@ -551,7 +554,8 @@ def _issubclass(cls: GenericType, cls_check: GenericType, instance: Any = None)
|
|
|
551
554
|
except TypeError as te:
|
|
552
555
|
# These errors typically arise from bad annotations and are hard to
|
|
553
556
|
# debug without knowing the type that we tried to compare.
|
|
554
|
-
|
|
557
|
+
msg = f"Invalid type for issubclass: {cls_base}"
|
|
558
|
+
raise TypeError(msg) from te
|
|
555
559
|
|
|
556
560
|
|
|
557
561
|
def does_obj_satisfy_typed_dict(obj: Any, cls: GenericType) -> bool:
|
|
@@ -909,9 +913,8 @@ def validate_literal(key: str, value: Any, expected_type: type, comp_name: str):
|
|
|
909
913
|
[str(v) if not isinstance(v, str) else f"'{v}'" for v in allowed_values]
|
|
910
914
|
)
|
|
911
915
|
value_str = f"'{value}'" if isinstance(value, str) else value
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
)
|
|
916
|
+
msg = f"prop value for {key!s} of the `{comp_name}` component should be one of the following: {allowed_value_str}. Got {value_str} instead"
|
|
917
|
+
raise ValueError(msg)
|
|
915
918
|
|
|
916
919
|
|
|
917
920
|
def validate_parameter_literals(func: Callable):
|