reflex 0.7.13a2__py3-none-any.whl → 0.7.14a1__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 +64 -69
- reflex/app_mixins/lifespan.py +2 -3
- reflex/app_mixins/middleware.py +1 -0
- reflex/app_mixins/mixin.py +0 -1
- reflex/assets.py +6 -3
- reflex/base.py +3 -2
- reflex/compiler/compiler.py +77 -64
- reflex/compiler/utils.py +8 -6
- reflex/components/base/app_wrap.pyi +0 -1
- reflex/components/base/bare.py +5 -7
- 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 +38 -40
- reflex/components/core/auto_scroll.pyi +0 -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.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 +3 -4
- reflex/components/el/elements/forms.pyi +1 -18
- 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 +1 -3
- 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 +47 -35
- reflex/constants/base.py +3 -3
- reflex/constants/compiler.py +8 -6
- reflex/constants/installer.py +24 -15
- reflex/custom_components/custom_components.py +1 -2
- 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 +15 -19
- reflex/istate/proxy.py +19 -12
- reflex/model.py +6 -4
- reflex/plugins/base.py +8 -0
- reflex/plugins/tailwind_v3.py +8 -0
- reflex/plugins/tailwind_v4.py +8 -0
- reflex/reflex.py +9 -11
- reflex/route.py +7 -9
- reflex/state.py +66 -70
- reflex/style.py +3 -1
- reflex/testing.py +46 -29
- reflex/utils/build.py +2 -1
- reflex/utils/console.py +9 -17
- reflex/utils/exec.py +9 -11
- 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 +2 -1
- reflex/utils/prerequisites.py +67 -38
- reflex/utils/processes.py +4 -6
- reflex/utils/pyi_generator.py +46 -41
- reflex/utils/redir.py +1 -1
- reflex/utils/serializers.py +4 -4
- reflex/utils/telemetry.py +42 -4
- 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.14a1.dist-info}/METADATA +1 -1
- reflex-0.7.14a1.dist-info/RECORD +407 -0
- reflex-0.7.13a2.dist-info/RECORD +0 -407
- {reflex-0.7.13a2.dist-info → reflex-0.7.14a1.dist-info}/WHEEL +0 -0
- {reflex-0.7.13a2.dist-info → reflex-0.7.14a1.dist-info}/entry_points.txt +0 -0
- {reflex-0.7.13a2.dist-info → reflex-0.7.14a1.dist-info}/licenses/LICENSE +0 -0
reflex/testing.py
CHANGED
|
@@ -155,9 +155,8 @@ class AppHarness:
|
|
|
155
155
|
app_name = f"{func_name}_{slug_suffix}"
|
|
156
156
|
app_name = re.sub(r"[^a-zA-Z0-9_]", "_", app_name)
|
|
157
157
|
elif isinstance(app_source, str):
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
)
|
|
158
|
+
msg = "app_name must be provided when app_source is a string."
|
|
159
|
+
raise ValueError(msg)
|
|
161
160
|
else:
|
|
162
161
|
app_name = app_source.__name__
|
|
163
162
|
|
|
@@ -285,7 +284,8 @@ class AppHarness:
|
|
|
285
284
|
self.app_instance._state_manager, StateManagerRedis
|
|
286
285
|
):
|
|
287
286
|
if self.app_instance._state is None:
|
|
288
|
-
|
|
287
|
+
msg = "State is not set."
|
|
288
|
+
raise RuntimeError(msg)
|
|
289
289
|
# Create our own redis connection for testing.
|
|
290
290
|
self.state_manager = StateManagerRedis.create(self.app_instance._state)
|
|
291
291
|
else:
|
|
@@ -299,7 +299,8 @@ class AppHarness:
|
|
|
299
299
|
|
|
300
300
|
def _get_backend_shutdown_handler(self):
|
|
301
301
|
if self.backend is None:
|
|
302
|
-
|
|
302
|
+
msg = "Backend was not initialized."
|
|
303
|
+
raise RuntimeError(msg)
|
|
303
304
|
|
|
304
305
|
original_shutdown = self.backend.shutdown
|
|
305
306
|
|
|
@@ -330,7 +331,8 @@ class AppHarness:
|
|
|
330
331
|
|
|
331
332
|
def _start_backend(self, port: int = 0):
|
|
332
333
|
if self.app_asgi is None:
|
|
333
|
-
|
|
334
|
+
msg = "App was not initialized."
|
|
335
|
+
raise RuntimeError(msg)
|
|
334
336
|
self.backend = uvicorn.Server(
|
|
335
337
|
uvicorn.Config(
|
|
336
338
|
app=self.app_asgi,
|
|
@@ -366,7 +368,8 @@ class AppHarness:
|
|
|
366
368
|
state=self.app_instance._state,
|
|
367
369
|
)
|
|
368
370
|
if not isinstance(self.app_instance.state_manager, StateManagerRedis):
|
|
369
|
-
|
|
371
|
+
msg = "Failed to reset state manager."
|
|
372
|
+
raise RuntimeError(msg)
|
|
370
373
|
|
|
371
374
|
def _start_frontend(self):
|
|
372
375
|
# Set up the frontend.
|
|
@@ -406,7 +409,8 @@ class AppHarness:
|
|
|
406
409
|
config.deploy_url = self.frontend_url
|
|
407
410
|
break
|
|
408
411
|
if self.frontend_url is None:
|
|
409
|
-
|
|
412
|
+
msg = "Frontend did not start"
|
|
413
|
+
raise RuntimeError(msg)
|
|
410
414
|
|
|
411
415
|
def consume_frontend_output():
|
|
412
416
|
while True:
|
|
@@ -578,20 +582,23 @@ class AppHarness:
|
|
|
578
582
|
TimeoutError: when server or sockets are not ready
|
|
579
583
|
"""
|
|
580
584
|
if self.backend is None:
|
|
581
|
-
|
|
585
|
+
msg = "Backend is not running."
|
|
586
|
+
raise RuntimeError(msg)
|
|
582
587
|
backend = self.backend
|
|
583
588
|
# check for servers to be initialized
|
|
584
589
|
if not self._poll_for(
|
|
585
590
|
target=lambda: getattr(backend, "servers", False),
|
|
586
591
|
timeout=timeout,
|
|
587
592
|
):
|
|
588
|
-
|
|
593
|
+
msg = "Backend servers are not initialized."
|
|
594
|
+
raise TimeoutError(msg)
|
|
589
595
|
# check for sockets to be listening
|
|
590
596
|
if not self._poll_for(
|
|
591
597
|
target=lambda: getattr(backend.servers[0], "sockets", False),
|
|
592
598
|
timeout=timeout,
|
|
593
599
|
):
|
|
594
|
-
|
|
600
|
+
msg = "Backend is not listening."
|
|
601
|
+
raise TimeoutError(msg)
|
|
595
602
|
return backend.servers[0].sockets[0]
|
|
596
603
|
|
|
597
604
|
def frontend(
|
|
@@ -619,12 +626,14 @@ class AppHarness:
|
|
|
619
626
|
RuntimeError: when selenium is not importable or frontend is not running
|
|
620
627
|
"""
|
|
621
628
|
if not has_selenium:
|
|
622
|
-
|
|
629
|
+
msg = (
|
|
623
630
|
"Frontend functionality requires `selenium` to be installed, "
|
|
624
631
|
"and it could not be imported."
|
|
625
632
|
)
|
|
633
|
+
raise RuntimeError(msg)
|
|
626
634
|
if self.frontend_url is None:
|
|
627
|
-
|
|
635
|
+
msg = "Frontend is not running."
|
|
636
|
+
raise RuntimeError(msg)
|
|
628
637
|
want_headless = False
|
|
629
638
|
if environment.APP_HARNESS_HEADLESS.get():
|
|
630
639
|
want_headless = True
|
|
@@ -650,7 +659,8 @@ class AppHarness:
|
|
|
650
659
|
if want_headless:
|
|
651
660
|
driver_options.add_argument("headless")
|
|
652
661
|
if driver_options is None:
|
|
653
|
-
|
|
662
|
+
msg = f"Could not determine options for {driver_clz}"
|
|
663
|
+
raise RuntimeError(msg)
|
|
654
664
|
if args := environment.APP_HARNESS_DRIVER_ARGS.get():
|
|
655
665
|
for arg in args.split(","):
|
|
656
666
|
driver_options.add_argument(arg)
|
|
@@ -680,7 +690,8 @@ class AppHarness:
|
|
|
680
690
|
RuntimeError: when the app hasn't started running
|
|
681
691
|
"""
|
|
682
692
|
if self.state_manager is None:
|
|
683
|
-
|
|
693
|
+
msg = "state_manager is not set."
|
|
694
|
+
raise RuntimeError(msg)
|
|
684
695
|
try:
|
|
685
696
|
return await self.state_manager.get_state(token)
|
|
686
697
|
finally:
|
|
@@ -698,7 +709,8 @@ class AppHarness:
|
|
|
698
709
|
RuntimeError: when the app hasn't started running
|
|
699
710
|
"""
|
|
700
711
|
if self.state_manager is None:
|
|
701
|
-
|
|
712
|
+
msg = "state_manager is not set."
|
|
713
|
+
raise RuntimeError(msg)
|
|
702
714
|
state = await self.get_state(token)
|
|
703
715
|
for key, value in kwargs.items():
|
|
704
716
|
setattr(state, key, value)
|
|
@@ -722,9 +734,11 @@ class AppHarness:
|
|
|
722
734
|
RuntimeError: when the app hasn't started running
|
|
723
735
|
"""
|
|
724
736
|
if self.state_manager is None:
|
|
725
|
-
|
|
737
|
+
msg = "state_manager is not set."
|
|
738
|
+
raise RuntimeError(msg)
|
|
726
739
|
if self.app_instance is None:
|
|
727
|
-
|
|
740
|
+
msg = "App is not running."
|
|
741
|
+
raise RuntimeError(msg)
|
|
728
742
|
app_state_manager = self.app_instance.state_manager
|
|
729
743
|
if isinstance(self.state_manager, StateManagerRedis):
|
|
730
744
|
# Temporarily replace the app's state manager with our own, since
|
|
@@ -761,9 +775,8 @@ class AppHarness:
|
|
|
761
775
|
target=lambda: element.text != exp_not_equal,
|
|
762
776
|
timeout=timeout,
|
|
763
777
|
):
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
)
|
|
778
|
+
msg = f"{element} content remains {exp_not_equal!r} while polling."
|
|
779
|
+
raise TimeoutError(msg)
|
|
767
780
|
return element.text
|
|
768
781
|
|
|
769
782
|
def poll_for_value(
|
|
@@ -792,9 +805,8 @@ class AppHarness:
|
|
|
792
805
|
target=lambda: element.get_attribute("value") not in exp_not_equal,
|
|
793
806
|
timeout=timeout,
|
|
794
807
|
):
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
)
|
|
808
|
+
msg = f"{element} content remains {exp_not_equal!r} while polling."
|
|
809
|
+
raise TimeoutError(msg)
|
|
798
810
|
return element.get_attribute("value")
|
|
799
811
|
|
|
800
812
|
def poll_for_clients(self, timeout: TimeoutType = None) -> dict[str, BaseState]:
|
|
@@ -812,15 +824,18 @@ class AppHarness:
|
|
|
812
824
|
ValueError: when the state_manager is not a memory state manager
|
|
813
825
|
"""
|
|
814
826
|
if self.app_instance is None:
|
|
815
|
-
|
|
827
|
+
msg = "App is not running."
|
|
828
|
+
raise RuntimeError(msg)
|
|
816
829
|
state_manager = self.app_instance.state_manager
|
|
817
830
|
if not isinstance(state_manager, (StateManagerMemory, StateManagerDisk)):
|
|
818
|
-
|
|
831
|
+
msg = "Only works with memory or disk state manager"
|
|
832
|
+
raise ValueError(msg)
|
|
819
833
|
if not self._poll_for(
|
|
820
834
|
target=lambda: state_manager.states,
|
|
821
835
|
timeout=timeout,
|
|
822
836
|
):
|
|
823
|
-
|
|
837
|
+
msg = "No states were observed while polling."
|
|
838
|
+
raise TimeoutError(msg)
|
|
824
839
|
return state_manager.states
|
|
825
840
|
|
|
826
841
|
|
|
@@ -962,11 +977,13 @@ class AppHarnessProd(AppHarness):
|
|
|
962
977
|
def _wait_frontend(self):
|
|
963
978
|
self._poll_for(lambda: self.frontend_server is not None)
|
|
964
979
|
if self.frontend_server is None or not self.frontend_server.socket.fileno():
|
|
965
|
-
|
|
980
|
+
msg = "Frontend did not start"
|
|
981
|
+
raise RuntimeError(msg)
|
|
966
982
|
|
|
967
983
|
def _start_backend(self):
|
|
968
984
|
if self.app_asgi is None:
|
|
969
|
-
|
|
985
|
+
msg = "App was not initialized."
|
|
986
|
+
raise RuntimeError(msg)
|
|
970
987
|
environment.REFLEX_SKIP_COMPILE.set(True)
|
|
971
988
|
self.backend = uvicorn.Server(
|
|
972
989
|
uvicorn.Config(
|
reflex/utils/build.py
CHANGED
|
@@ -132,7 +132,7 @@ def _zip(
|
|
|
132
132
|
def zip_app(
|
|
133
133
|
frontend: bool = True,
|
|
134
134
|
backend: bool = True,
|
|
135
|
-
zip_dest_dir: str | Path =
|
|
135
|
+
zip_dest_dir: str | Path | None = None,
|
|
136
136
|
upload_db_file: bool = False,
|
|
137
137
|
):
|
|
138
138
|
"""Zip up the app.
|
|
@@ -143,6 +143,7 @@ def zip_app(
|
|
|
143
143
|
zip_dest_dir: The directory to export the zip file to.
|
|
144
144
|
upload_db_file: Whether to upload the database file.
|
|
145
145
|
"""
|
|
146
|
+
zip_dest_dir = zip_dest_dir or Path.cwd()
|
|
146
147
|
zip_dest_dir = Path(zip_dest_dir)
|
|
147
148
|
files_to_exclude = {
|
|
148
149
|
constants.ComponentName.FRONTEND.zip(),
|
reflex/utils/console.py
CHANGED
|
@@ -59,9 +59,8 @@ def set_log_level(log_level: LogLevel | None):
|
|
|
59
59
|
if log_level is None:
|
|
60
60
|
return
|
|
61
61
|
if not isinstance(log_level, LogLevel):
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
)
|
|
62
|
+
msg = f"log_level must be a LogLevel enum value, got {log_level} of type {type(log_level)} instead."
|
|
63
|
+
raise TypeError(msg)
|
|
65
64
|
global _LOG_LEVEL
|
|
66
65
|
if log_level != _LOG_LEVEL:
|
|
67
66
|
# Set the loglevel persistenly for subprocesses.
|
|
@@ -89,8 +88,7 @@ def print(msg: str, dedupe: bool = False, **kwargs):
|
|
|
89
88
|
if dedupe:
|
|
90
89
|
if msg in _EMITTED_PRINTS:
|
|
91
90
|
return
|
|
92
|
-
|
|
93
|
-
_EMITTED_PRINTS.add(msg)
|
|
91
|
+
_EMITTED_PRINTS.add(msg)
|
|
94
92
|
_console.print(msg, **kwargs)
|
|
95
93
|
|
|
96
94
|
|
|
@@ -107,8 +105,7 @@ def debug(msg: str, dedupe: bool = False, **kwargs):
|
|
|
107
105
|
if dedupe:
|
|
108
106
|
if msg_ in _EMITTED_DEBUG:
|
|
109
107
|
return
|
|
110
|
-
|
|
111
|
-
_EMITTED_DEBUG.add(msg_)
|
|
108
|
+
_EMITTED_DEBUG.add(msg_)
|
|
112
109
|
if progress := kwargs.pop("progress", None):
|
|
113
110
|
progress.console.print(msg_, **kwargs)
|
|
114
111
|
else:
|
|
@@ -127,8 +124,7 @@ def info(msg: str, dedupe: bool = False, **kwargs):
|
|
|
127
124
|
if dedupe:
|
|
128
125
|
if msg in _EMITTED_INFO:
|
|
129
126
|
return
|
|
130
|
-
|
|
131
|
-
_EMITTED_INFO.add(msg)
|
|
127
|
+
_EMITTED_INFO.add(msg)
|
|
132
128
|
print(f"[cyan]Info: {msg}[/cyan]", **kwargs)
|
|
133
129
|
|
|
134
130
|
|
|
@@ -144,8 +140,7 @@ def success(msg: str, dedupe: bool = False, **kwargs):
|
|
|
144
140
|
if dedupe:
|
|
145
141
|
if msg in _EMITTED_SUCCESS:
|
|
146
142
|
return
|
|
147
|
-
|
|
148
|
-
_EMITTED_SUCCESS.add(msg)
|
|
143
|
+
_EMITTED_SUCCESS.add(msg)
|
|
149
144
|
print(f"[green]Success: {msg}[/green]", **kwargs)
|
|
150
145
|
|
|
151
146
|
|
|
@@ -161,8 +156,7 @@ def log(msg: str, dedupe: bool = False, **kwargs):
|
|
|
161
156
|
if dedupe:
|
|
162
157
|
if msg in _EMITTED_LOGS:
|
|
163
158
|
return
|
|
164
|
-
|
|
165
|
-
_EMITTED_LOGS.add(msg)
|
|
159
|
+
_EMITTED_LOGS.add(msg)
|
|
166
160
|
_console.log(msg, **kwargs)
|
|
167
161
|
|
|
168
162
|
|
|
@@ -188,8 +182,7 @@ def warn(msg: str, dedupe: bool = False, **kwargs):
|
|
|
188
182
|
if dedupe:
|
|
189
183
|
if msg in _EMIITED_WARNINGS:
|
|
190
184
|
return
|
|
191
|
-
|
|
192
|
-
_EMIITED_WARNINGS.add(msg)
|
|
185
|
+
_EMIITED_WARNINGS.add(msg)
|
|
193
186
|
print(f"[orange1]Warning: {msg}[/orange1]", **kwargs)
|
|
194
187
|
|
|
195
188
|
|
|
@@ -271,8 +264,7 @@ def error(msg: str, dedupe: bool = False, **kwargs):
|
|
|
271
264
|
if dedupe:
|
|
272
265
|
if msg in _EMITTED_ERRORS:
|
|
273
266
|
return
|
|
274
|
-
|
|
275
|
-
_EMITTED_ERRORS.add(msg)
|
|
267
|
+
_EMITTED_ERRORS.add(msg)
|
|
276
268
|
print(f"[red]{msg}[/red]", **kwargs)
|
|
277
269
|
|
|
278
270
|
|
reflex/utils/exec.py
CHANGED
|
@@ -244,14 +244,12 @@ def get_app_file() -> Path:
|
|
|
244
244
|
sys.path.insert(0, current_working_dir)
|
|
245
245
|
module_spec = importlib.util.find_spec(get_app_module())
|
|
246
246
|
if module_spec is None:
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
)
|
|
247
|
+
msg = f"Module {get_app_module()} not found. Make sure the module is installed."
|
|
248
|
+
raise ImportError(msg)
|
|
250
249
|
file_name = module_spec.origin
|
|
251
250
|
if file_name is None:
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
)
|
|
251
|
+
msg = f"Module {get_app_module()} not found. Make sure the module is installed."
|
|
252
|
+
raise ImportError(msg)
|
|
255
253
|
return Path(file_name).resolve()
|
|
256
254
|
|
|
257
255
|
|
|
@@ -300,13 +298,12 @@ def get_reload_paths() -> Sequence[Path]:
|
|
|
300
298
|
The reload paths for the backend.
|
|
301
299
|
"""
|
|
302
300
|
config = get_config()
|
|
303
|
-
reload_paths = [Path(
|
|
304
|
-
if config.
|
|
305
|
-
module_path = Path(
|
|
301
|
+
reload_paths = [Path.cwd()]
|
|
302
|
+
if (spec := importlib.util.find_spec(config.module)) is not None and spec.origin:
|
|
303
|
+
module_path = Path(spec.origin).resolve().parent
|
|
306
304
|
|
|
307
305
|
while module_path.parent.name and any(
|
|
308
|
-
sibling_file.name == "__init__.py"
|
|
309
|
-
for sibling_file in module_path.parent.iterdir()
|
|
306
|
+
sibling_file.name == "__init__.py" for sibling_file in module_path.iterdir()
|
|
310
307
|
):
|
|
311
308
|
# go up a level to find dir without `__init__.py`
|
|
312
309
|
module_path = module_path.parent
|
|
@@ -383,6 +380,7 @@ HOTRELOAD_IGNORE_EXTENSIONS = (
|
|
|
383
380
|
"json",
|
|
384
381
|
"sh",
|
|
385
382
|
"bash",
|
|
383
|
+
"log",
|
|
386
384
|
)
|
|
387
385
|
|
|
388
386
|
HOTRELOAD_IGNORE_PATTERNS = (
|
reflex/utils/format.py
CHANGED
|
@@ -73,7 +73,8 @@ def get_close_char(open: str, close: str | None = None) -> str:
|
|
|
73
73
|
if close is not None:
|
|
74
74
|
return close
|
|
75
75
|
if open not in WRAP_MAP:
|
|
76
|
-
|
|
76
|
+
msg = f"Invalid wrap open: {open}, must be one of {WRAP_MAP.keys()}"
|
|
77
|
+
raise ValueError(msg)
|
|
77
78
|
return WRAP_MAP[open]
|
|
78
79
|
|
|
79
80
|
|
|
@@ -187,8 +188,7 @@ def to_camel_case(text: str, treat_hyphens_as_underscores: bool = True) -> str:
|
|
|
187
188
|
# Capitalize the first letter of each word except the first one
|
|
188
189
|
if len(words) == 1:
|
|
189
190
|
return words[0]
|
|
190
|
-
|
|
191
|
-
return converted_word
|
|
191
|
+
return words[0] + "".join([w.capitalize() for w in words[1:]])
|
|
192
192
|
|
|
193
193
|
|
|
194
194
|
def to_title_case(text: str, sep: str = "") -> str:
|
|
@@ -264,17 +264,13 @@ def _escape_js_string(string: str) -> str:
|
|
|
264
264
|
if segment.startswith("${") and segment.endswith("}"):
|
|
265
265
|
# Return the `${}` segment unchanged
|
|
266
266
|
return segment
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
segment = segment.replace(r"\`", "`")
|
|
270
|
-
segment = segment.replace("`", r"\`")
|
|
271
|
-
return segment
|
|
267
|
+
# Escape backticks in the segment
|
|
268
|
+
return segment.replace(r"\`", "`").replace("`", r"\`")
|
|
272
269
|
|
|
273
270
|
# Split the string into parts, keeping the `${}` segments
|
|
274
271
|
parts = re.split(r"(\$\{.*?\})", string)
|
|
275
272
|
escaped_parts = [escape_outside_segments(part) for part in parts]
|
|
276
|
-
|
|
277
|
-
return escaped_string
|
|
273
|
+
return "".join(escaped_parts)
|
|
278
274
|
|
|
279
275
|
|
|
280
276
|
def _wrap_js_string(string: str) -> str:
|
|
@@ -287,8 +283,7 @@ def _wrap_js_string(string: str) -> str:
|
|
|
287
283
|
The wrapped string.
|
|
288
284
|
"""
|
|
289
285
|
string = wrap(string, "`")
|
|
290
|
-
|
|
291
|
-
return string
|
|
286
|
+
return wrap(string, "{")
|
|
292
287
|
|
|
293
288
|
|
|
294
289
|
def format_string(string: str) -> str:
|
|
@@ -402,13 +397,13 @@ def format_prop(
|
|
|
402
397
|
return str(Var.create(prop))
|
|
403
398
|
|
|
404
399
|
# Handle other types.
|
|
405
|
-
|
|
400
|
+
if isinstance(prop, str):
|
|
406
401
|
if is_wrapped(prop, "{"):
|
|
407
402
|
return prop
|
|
408
403
|
return json_dumps(prop)
|
|
409
404
|
|
|
410
405
|
# For dictionaries, convert any properties to strings.
|
|
411
|
-
|
|
406
|
+
if isinstance(prop, dict):
|
|
412
407
|
prop = serializers.serialize_dict(prop) # pyright: ignore [reportAttributeAccessIssue]
|
|
413
408
|
|
|
414
409
|
else:
|
|
@@ -417,11 +412,13 @@ def format_prop(
|
|
|
417
412
|
except exceptions.InvalidStylePropError:
|
|
418
413
|
raise
|
|
419
414
|
except TypeError as e:
|
|
420
|
-
|
|
415
|
+
msg = f"Could not format prop: {prop} of type {type(prop)}"
|
|
416
|
+
raise TypeError(msg) from e
|
|
421
417
|
|
|
422
418
|
# Wrap the variable in braces.
|
|
423
419
|
if not isinstance(prop, str):
|
|
424
|
-
|
|
420
|
+
msg = f"Invalid prop: {prop}. Expected a string."
|
|
421
|
+
raise ValueError(msg)
|
|
425
422
|
return wrap(prop, "{", check_first=False)
|
|
426
423
|
|
|
427
424
|
|
|
@@ -591,9 +588,8 @@ def format_queue_events(
|
|
|
591
588
|
elif isinstance(spec, type(lambda: None)):
|
|
592
589
|
specs = call_event_fn(spec, args_spec or _default_args_spec) # pyright: ignore [reportAssignmentType, reportArgumentType]
|
|
593
590
|
if isinstance(specs, Var):
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
)
|
|
591
|
+
msg = f"Invalid event spec: {specs}. Expected a list of EventSpecs."
|
|
592
|
+
raise ValueError(msg)
|
|
597
593
|
payloads.extend(format_event(s) for s in specs)
|
|
598
594
|
|
|
599
595
|
# Return the final code snippet, expecting queueEvents, processEvent, and socket to be in scope.
|
|
@@ -662,12 +658,14 @@ def format_library_name(library_fullname: str | dict[str, Any]) -> str:
|
|
|
662
658
|
# If input is a dictionary, extract the 'name' key
|
|
663
659
|
if isinstance(library_fullname, dict):
|
|
664
660
|
if "name" not in library_fullname:
|
|
665
|
-
|
|
661
|
+
msg = "Dictionary input must contain a 'name' key"
|
|
662
|
+
raise KeyError(msg)
|
|
666
663
|
library_fullname = library_fullname["name"]
|
|
667
664
|
|
|
668
665
|
# Process the library name as a string
|
|
669
666
|
if not isinstance(library_fullname, str):
|
|
670
|
-
|
|
667
|
+
msg = "Library name must be a string"
|
|
668
|
+
raise TypeError(msg)
|
|
671
669
|
|
|
672
670
|
if library_fullname.startswith("https://"):
|
|
673
671
|
return library_fullname
|
|
@@ -764,9 +762,8 @@ def format_data_editor_column(col: str | dict):
|
|
|
764
762
|
if isinstance(col, Var):
|
|
765
763
|
return col
|
|
766
764
|
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
)
|
|
765
|
+
msg = f"unexpected type ({(type(col).__name__)}: {col}) for column header in data_editor"
|
|
766
|
+
raise ValueError(msg)
|
|
770
767
|
|
|
771
768
|
|
|
772
769
|
def format_data_editor_cell(cell: Any):
|
reflex/utils/imports.py
CHANGED
|
@@ -127,10 +127,11 @@ class ImportVar:
|
|
|
127
127
|
"""
|
|
128
128
|
if self.alias:
|
|
129
129
|
return (
|
|
130
|
-
self.alias
|
|
130
|
+
self.alias
|
|
131
|
+
if self.is_default
|
|
132
|
+
else (self.tag + " as " + self.alias if self.tag else self.alias)
|
|
131
133
|
)
|
|
132
|
-
|
|
133
|
-
return self.tag or ""
|
|
134
|
+
return self.tag or ""
|
|
134
135
|
|
|
135
136
|
|
|
136
137
|
ImportTypes = str | ImportVar | list[str | ImportVar] | list[ImportVar]
|
reflex/utils/lazy_loader.py
CHANGED
|
@@ -65,7 +65,7 @@ def attach(
|
|
|
65
65
|
def __getattr__(name: str): # noqa: N807
|
|
66
66
|
if name in submodules:
|
|
67
67
|
return importlib.import_module(f"{package_name}.{name}")
|
|
68
|
-
|
|
68
|
+
if name in attr_to_modules:
|
|
69
69
|
submod_path = f"{package_name}.{attr_to_modules[name]}"
|
|
70
70
|
submod = importlib.import_module(submod_path)
|
|
71
71
|
attr = getattr(submod, name)
|
|
@@ -78,8 +78,8 @@ def attach(
|
|
|
78
78
|
pkg.__dict__[name] = attr
|
|
79
79
|
|
|
80
80
|
return attr
|
|
81
|
-
|
|
82
|
-
|
|
81
|
+
msg = f"No {package_name} attribute {name}"
|
|
82
|
+
raise AttributeError(msg)
|
|
83
83
|
|
|
84
84
|
def __dir__(): # noqa: N807
|
|
85
85
|
return __all__
|
reflex/utils/misc.py
CHANGED
|
@@ -20,5 +20,6 @@ async def run_in_thread(func: Callable) -> Any:
|
|
|
20
20
|
Any: The return value of the function.
|
|
21
21
|
"""
|
|
22
22
|
if asyncio.coroutines.iscoroutinefunction(func):
|
|
23
|
-
|
|
23
|
+
msg = "func must be a non-async function"
|
|
24
|
+
raise ValueError(msg)
|
|
24
25
|
return await asyncio.get_event_loop().run_in_executor(None, func)
|
reflex/utils/net.py
CHANGED
|
@@ -19,7 +19,7 @@ def _httpx_verify_kwarg() -> bool:
|
|
|
19
19
|
Returns:
|
|
20
20
|
True if SSL verification is enabled, False otherwise
|
|
21
21
|
"""
|
|
22
|
-
from
|
|
22
|
+
from reflex.config import environment
|
|
23
23
|
|
|
24
24
|
return not environment.SSL_NO_VERIFY.get()
|
|
25
25
|
|
|
@@ -131,7 +131,7 @@ def _httpx_local_address_kwarg() -> str:
|
|
|
131
131
|
Returns:
|
|
132
132
|
The local address to bind to
|
|
133
133
|
"""
|
|
134
|
-
from
|
|
134
|
+
from reflex.config import environment
|
|
135
135
|
|
|
136
136
|
return environment.REFLEX_HTTP_CLIENT_BIND_ADDRESS.get() or (
|
|
137
137
|
"::" if _should_use_ipv6() else "0.0.0.0"
|
reflex/utils/path_ops.py
CHANGED
|
@@ -300,7 +300,8 @@ def update_directory_tree(src: Path, dest: Path):
|
|
|
300
300
|
ValueError: If the source is not a directory
|
|
301
301
|
"""
|
|
302
302
|
if not src.is_dir():
|
|
303
|
-
|
|
303
|
+
msg = f"Source {src} is not a directory"
|
|
304
|
+
raise ValueError(msg)
|
|
304
305
|
|
|
305
306
|
# Ensure the destination directory exists
|
|
306
307
|
dest.mkdir(parents=True, exist_ok=True)
|