reflex 0.4.7a2__py3-none-any.whl → 0.4.8__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/web/utils/state.js +7 -1
- reflex/app.py +15 -1
- reflex/compiler/utils.py +1 -1
- reflex/components/base/body.pyi +0 -3
- reflex/components/base/document.pyi +0 -15
- reflex/components/base/fragment.pyi +0 -3
- reflex/components/base/head.pyi +0 -3
- reflex/components/base/link.pyi +0 -6
- reflex/components/base/meta.pyi +0 -12
- reflex/components/chakra/base.pyi +0 -6
- reflex/components/chakra/datadisplay/badge.pyi +0 -3
- reflex/components/chakra/datadisplay/code.pyi +0 -3
- reflex/components/chakra/datadisplay/divider.pyi +0 -3
- reflex/components/chakra/datadisplay/keyboard_key.pyi +0 -3
- reflex/components/chakra/datadisplay/list.pyi +0 -3
- reflex/components/chakra/datadisplay/stat.pyi +0 -15
- reflex/components/chakra/datadisplay/table.pyi +0 -12
- reflex/components/chakra/datadisplay/tag.pyi +0 -12
- reflex/components/chakra/disclosure/accordion.pyi +0 -12
- reflex/components/chakra/disclosure/tabs.pyi +0 -12
- reflex/components/chakra/disclosure/transition.pyi +0 -18
- reflex/components/chakra/disclosure/visuallyhidden.pyi +0 -3
- reflex/components/chakra/feedback/alert.pyi +0 -9
- reflex/components/chakra/feedback/circularprogress.pyi +0 -3
- reflex/components/chakra/feedback/progress.pyi +0 -3
- reflex/components/chakra/feedback/skeleton.pyi +0 -9
- reflex/components/chakra/feedback/spinner.pyi +0 -3
- reflex/components/chakra/forms/button.pyi +0 -6
- reflex/components/chakra/forms/checkbox.pyi +0 -6
- reflex/components/chakra/forms/colormodeswitch.pyi +0 -3
- reflex/components/chakra/forms/editable.pyi +0 -12
- reflex/components/chakra/forms/form.pyi +0 -9
- reflex/components/chakra/forms/iconbutton.pyi +0 -3
- reflex/components/chakra/forms/input.pyi +0 -15
- reflex/components/chakra/forms/numberinput.pyi +0 -12
- reflex/components/chakra/forms/pininput.py +1 -1
- reflex/components/chakra/forms/pininput.pyi +1 -4
- reflex/components/chakra/forms/radio.py +1 -1
- reflex/components/chakra/forms/radio.pyi +1 -1
- reflex/components/chakra/forms/rangeslider.py +1 -1
- reflex/components/chakra/forms/rangeslider.pyi +1 -10
- reflex/components/chakra/forms/slider.pyi +0 -12
- reflex/components/chakra/forms/switch.pyi +0 -3
- reflex/components/chakra/layout/aspect_ratio.pyi +0 -3
- reflex/components/chakra/layout/box.pyi +0 -3
- reflex/components/chakra/layout/card.pyi +0 -9
- reflex/components/chakra/layout/center.pyi +0 -9
- reflex/components/chakra/layout/container.pyi +0 -3
- reflex/components/chakra/layout/flex.pyi +0 -3
- reflex/components/chakra/layout/grid.pyi +0 -9
- reflex/components/chakra/layout/spacer.pyi +0 -3
- reflex/components/chakra/layout/stack.pyi +0 -9
- reflex/components/chakra/layout/wrap.pyi +0 -3
- reflex/components/chakra/media/avatar.pyi +0 -9
- reflex/components/chakra/media/icon.pyi +0 -3
- reflex/components/chakra/navigation/breadcrumb.pyi +0 -3
- reflex/components/chakra/navigation/linkoverlay.pyi +0 -6
- reflex/components/chakra/navigation/stepper.pyi +0 -24
- reflex/components/chakra/overlay/alertdialog.pyi +0 -18
- reflex/components/chakra/overlay/drawer.pyi +0 -18
- reflex/components/chakra/overlay/menu.pyi +0 -18
- reflex/components/chakra/overlay/modal.pyi +0 -18
- reflex/components/chakra/overlay/popover.pyi +0 -24
- reflex/components/chakra/overlay/tooltip.pyi +0 -3
- reflex/components/chakra/typography/heading.pyi +0 -3
- reflex/components/chakra/typography/highlight.pyi +0 -3
- reflex/components/chakra/typography/span.pyi +0 -3
- reflex/components/chakra/typography/text.pyi +0 -3
- reflex/components/component.py +61 -22
- reflex/components/core/client_side_routing.pyi +0 -6
- reflex/components/core/upload.py +3 -1
- reflex/components/core/upload.pyi +0 -3
- reflex/components/el/element.pyi +0 -3
- reflex/components/el/elements/base.pyi +0 -3
- reflex/components/el/elements/forms.pyi +0 -39
- reflex/components/el/elements/inline.pyi +0 -84
- reflex/components/el/elements/media.pyi +0 -42
- reflex/components/el/elements/metadata.pyi +0 -15
- reflex/components/el/elements/other.pyi +0 -21
- reflex/components/el/elements/scripts.pyi +0 -9
- reflex/components/el/elements/sectioning.pyi +0 -45
- reflex/components/el/elements/tables.pyi +0 -30
- reflex/components/el/elements/typography.pyi +0 -45
- reflex/components/gridjs/datatable.pyi +0 -3
- reflex/components/lucide/icon.pyi +0 -3
- reflex/components/next/base.pyi +0 -3
- reflex/components/next/link.pyi +0 -3
- reflex/components/plotly/plotly.pyi +0 -6
- reflex/components/radix/primitives/accordion.pyi +0 -3
- reflex/components/radix/primitives/base.pyi +0 -6
- reflex/components/radix/primitives/drawer.pyi +0 -21
- reflex/components/radix/primitives/form.pyi +0 -18
- reflex/components/radix/primitives/progress.pyi +0 -9
- reflex/components/radix/primitives/slider.pyi +0 -15
- reflex/components/radix/themes/base.pyi +0 -6
- reflex/components/react_player/audio.pyi +0 -3
- reflex/components/react_player/react_player.pyi +0 -3
- reflex/components/react_player/video.pyi +0 -3
- reflex/components/recharts/cartesian.pyi +0 -57
- reflex/components/recharts/general.pyi +0 -12
- reflex/components/recharts/polar.pyi +0 -18
- reflex/components/recharts/recharts.pyi +0 -3
- reflex/constants/__init__.py +2 -0
- reflex/constants/base.py +5 -0
- reflex/constants/compiler.py +2 -0
- reflex/constants/installer.py +4 -2
- reflex/custom_components/custom_components.py +28 -34
- reflex/event.py +7 -6
- reflex/experimental/__init__.py +2 -0
- reflex/experimental/misc.py +12 -0
- reflex/model.py +1 -1
- reflex/reflex.py +0 -1
- reflex/utils/compat.py +43 -0
- reflex/utils/console.py +10 -1
- reflex/utils/export.py +1 -3
- reflex/utils/imports.py +14 -1
- reflex/utils/prerequisites.py +71 -45
- reflex/utils/processes.py +41 -4
- reflex/utils/serializers.py +14 -0
- reflex/utils/types.py +4 -3
- {reflex-0.4.7a2.dist-info → reflex-0.4.8.dist-info}/METADATA +1 -1
- {reflex-0.4.7a2.dist-info → reflex-0.4.8.dist-info}/RECORD +125 -123
- {reflex-0.4.7a2.dist-info → reflex-0.4.8.dist-info}/WHEEL +1 -1
- {reflex-0.4.7a2.dist-info → reflex-0.4.8.dist-info}/LICENSE +0 -0
- {reflex-0.4.7a2.dist-info → reflex-0.4.8.dist-info}/entry_points.txt +0 -0
reflex/utils/prerequisites.py
CHANGED
|
@@ -19,7 +19,7 @@ from datetime import datetime
|
|
|
19
19
|
from fileinput import FileInput
|
|
20
20
|
from pathlib import Path
|
|
21
21
|
from types import ModuleType
|
|
22
|
-
from typing import Callable, Optional
|
|
22
|
+
from typing import Callable, List, Optional
|
|
23
23
|
|
|
24
24
|
import httpx
|
|
25
25
|
import pkg_resources
|
|
@@ -35,6 +35,7 @@ from reflex.base import Base
|
|
|
35
35
|
from reflex.compiler import templates
|
|
36
36
|
from reflex.config import Config, get_config
|
|
37
37
|
from reflex.utils import console, path_ops, processes
|
|
38
|
+
from reflex.utils.format import format_library_name
|
|
38
39
|
|
|
39
40
|
CURRENTLY_INSTALLING_NODE = False
|
|
40
41
|
|
|
@@ -166,16 +167,13 @@ def get_bun_version() -> version.Version | None:
|
|
|
166
167
|
|
|
167
168
|
def get_install_package_manager() -> str | None:
|
|
168
169
|
"""Get the package manager executable for installation.
|
|
169
|
-
Currently
|
|
170
|
+
Currently, bun is used for installation only.
|
|
170
171
|
|
|
171
172
|
Returns:
|
|
172
173
|
The path to the package manager.
|
|
173
174
|
"""
|
|
174
|
-
|
|
175
|
-
if constants.IS_WINDOWS:
|
|
175
|
+
if constants.IS_WINDOWS and not constants.IS_WINDOWS_BUN_SUPPORTED_MACHINE:
|
|
176
176
|
return get_package_manager()
|
|
177
|
-
|
|
178
|
-
# On other platforms, we use bun.
|
|
179
177
|
return get_config().bun_path
|
|
180
178
|
|
|
181
179
|
|
|
@@ -227,11 +225,12 @@ def get_app(reload: bool = False) -> ModuleType:
|
|
|
227
225
|
return app
|
|
228
226
|
|
|
229
227
|
|
|
230
|
-
def get_compiled_app(reload: bool = False) -> ModuleType:
|
|
228
|
+
def get_compiled_app(reload: bool = False, export: bool = False) -> ModuleType:
|
|
231
229
|
"""Get the app module based on the default config after first compiling it.
|
|
232
230
|
|
|
233
231
|
Args:
|
|
234
232
|
reload: Re-import the app module from disk
|
|
233
|
+
export: Compile the app for export
|
|
235
234
|
|
|
236
235
|
Returns:
|
|
237
236
|
The compiled app based on the default config.
|
|
@@ -241,7 +240,7 @@ def get_compiled_app(reload: bool = False) -> ModuleType:
|
|
|
241
240
|
# For py3.8 and py3.9 compatibility when redis is used, we MUST add any decorator pages
|
|
242
241
|
# before compiling the app in a thread to avoid event loop error (REF-2172).
|
|
243
242
|
app._apply_decorated_pages()
|
|
244
|
-
app.compile_()
|
|
243
|
+
app.compile_(export=export)
|
|
245
244
|
return app_module
|
|
246
245
|
|
|
247
246
|
|
|
@@ -562,28 +561,39 @@ def init_reflex_json(project_hash: int | None):
|
|
|
562
561
|
path_ops.update_json_file(constants.Reflex.JSON, reflex_json)
|
|
563
562
|
|
|
564
563
|
|
|
565
|
-
def update_next_config(export=False):
|
|
564
|
+
def update_next_config(export=False, transpile_packages: Optional[List[str]] = None):
|
|
566
565
|
"""Update Next.js config from Reflex config.
|
|
567
566
|
|
|
568
567
|
Args:
|
|
569
568
|
export: if the method run during reflex export.
|
|
569
|
+
transpile_packages: list of packages to transpile via next.config.js.
|
|
570
570
|
"""
|
|
571
|
-
next_config_file =
|
|
571
|
+
next_config_file = Path(constants.Dirs.WEB, constants.Next.CONFIG_FILE)
|
|
572
572
|
|
|
573
|
-
next_config = _update_next_config(
|
|
573
|
+
next_config = _update_next_config(
|
|
574
|
+
get_config(), export=export, transpile_packages=transpile_packages
|
|
575
|
+
)
|
|
574
576
|
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
577
|
+
# Overwriting the next.config.js triggers a full server reload, so make sure
|
|
578
|
+
# there is actually a diff.
|
|
579
|
+
orig_next_config = next_config_file.read_text() if next_config_file.exists() else ""
|
|
580
|
+
if orig_next_config != next_config:
|
|
581
|
+
next_config_file.write_text(next_config)
|
|
578
582
|
|
|
579
583
|
|
|
580
|
-
def _update_next_config(
|
|
584
|
+
def _update_next_config(
|
|
585
|
+
config: Config, export: bool = False, transpile_packages: Optional[List[str]] = None
|
|
586
|
+
):
|
|
581
587
|
next_config = {
|
|
582
588
|
"basePath": config.frontend_path or "",
|
|
583
589
|
"compress": config.next_compression,
|
|
584
590
|
"reactStrictMode": True,
|
|
585
591
|
"trailingSlash": True,
|
|
586
592
|
}
|
|
593
|
+
if transpile_packages:
|
|
594
|
+
next_config["transpilePackages"] = list(
|
|
595
|
+
set((format_library_name(p) for p in transpile_packages))
|
|
596
|
+
)
|
|
587
597
|
if export:
|
|
588
598
|
next_config["output"] = "export"
|
|
589
599
|
next_config["distDir"] = constants.Dirs.STATIC
|
|
@@ -718,10 +728,10 @@ def install_bun():
|
|
|
718
728
|
Raises:
|
|
719
729
|
FileNotFoundError: If required packages are not found.
|
|
720
730
|
"""
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
731
|
+
if constants.IS_WINDOWS and not constants.IS_WINDOWS_BUN_SUPPORTED_MACHINE:
|
|
732
|
+
console.warn(
|
|
733
|
+
"Bun for Windows is currently only available for x86 64-bit Windows. Installation will fall back on npm."
|
|
734
|
+
)
|
|
725
735
|
|
|
726
736
|
# Skip if bun is already installed.
|
|
727
737
|
if os.path.exists(get_config().bun_path) and get_bun_version() == version.parse(
|
|
@@ -731,16 +741,25 @@ def install_bun():
|
|
|
731
741
|
return
|
|
732
742
|
|
|
733
743
|
# if unzip is installed
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
+
if constants.IS_WINDOWS:
|
|
745
|
+
processes.new_process(
|
|
746
|
+
["powershell", "-c", f"irm {constants.Bun.INSTALL_URL}.ps1|iex"],
|
|
747
|
+
env={"BUN_INSTALL": constants.Bun.ROOT_PATH},
|
|
748
|
+
shell=True,
|
|
749
|
+
run=True,
|
|
750
|
+
show_logs=console.is_debug(),
|
|
751
|
+
)
|
|
752
|
+
else:
|
|
753
|
+
unzip_path = path_ops.which("unzip")
|
|
754
|
+
if unzip_path is None:
|
|
755
|
+
raise FileNotFoundError("Reflex requires unzip to be installed.")
|
|
756
|
+
|
|
757
|
+
# Run the bun install script.
|
|
758
|
+
download_and_run(
|
|
759
|
+
constants.Bun.INSTALL_URL,
|
|
760
|
+
f"bun-v{constants.Bun.VERSION}",
|
|
761
|
+
BUN_INSTALL=constants.Bun.ROOT_PATH,
|
|
762
|
+
)
|
|
744
763
|
|
|
745
764
|
|
|
746
765
|
def _write_cached_procedure_file(payload: str, cache_file: str):
|
|
@@ -802,18 +821,22 @@ def install_frontend_packages(packages: set[str], config: Config):
|
|
|
802
821
|
Example:
|
|
803
822
|
>>> install_frontend_packages(["react", "react-dom"], get_config())
|
|
804
823
|
"""
|
|
805
|
-
#
|
|
806
|
-
|
|
824
|
+
# unsupported archs will use npm anyway. so we dont have to run npm twice
|
|
825
|
+
fallback_command = (
|
|
826
|
+
get_package_manager()
|
|
827
|
+
if constants.IS_WINDOWS and constants.IS_WINDOWS_BUN_SUPPORTED_MACHINE
|
|
828
|
+
else None
|
|
829
|
+
)
|
|
830
|
+
processes.run_process_with_fallback(
|
|
807
831
|
[get_install_package_manager(), "install", "--loglevel", "silly"],
|
|
832
|
+
fallback=fallback_command,
|
|
833
|
+
show_status_message="Installing base frontend packages",
|
|
808
834
|
cwd=constants.Dirs.WEB,
|
|
809
835
|
shell=constants.IS_WINDOWS,
|
|
810
836
|
)
|
|
811
837
|
|
|
812
|
-
processes.show_status("Installing base frontend packages", process)
|
|
813
|
-
|
|
814
838
|
if config.tailwind is not None:
|
|
815
|
-
|
|
816
|
-
process = processes.new_process(
|
|
839
|
+
processes.run_process_with_fallback(
|
|
817
840
|
[
|
|
818
841
|
get_install_package_manager(),
|
|
819
842
|
"add",
|
|
@@ -821,21 +844,21 @@ def install_frontend_packages(packages: set[str], config: Config):
|
|
|
821
844
|
constants.Tailwind.VERSION,
|
|
822
845
|
*((config.tailwind or {}).get("plugins", [])),
|
|
823
846
|
],
|
|
847
|
+
fallback=fallback_command,
|
|
848
|
+
show_status_message="Installing tailwind",
|
|
824
849
|
cwd=constants.Dirs.WEB,
|
|
825
850
|
shell=constants.IS_WINDOWS,
|
|
826
851
|
)
|
|
827
|
-
processes.show_status("Installing tailwind", process)
|
|
828
852
|
|
|
829
853
|
# Install custom packages defined in frontend_packages
|
|
830
854
|
if len(packages) > 0:
|
|
831
|
-
|
|
855
|
+
processes.run_process_with_fallback(
|
|
832
856
|
[get_install_package_manager(), "add", *packages],
|
|
857
|
+
fallback=fallback_command,
|
|
858
|
+
show_status_message="Installing frontend packages from config and components",
|
|
833
859
|
cwd=constants.Dirs.WEB,
|
|
834
860
|
shell=constants.IS_WINDOWS,
|
|
835
861
|
)
|
|
836
|
-
processes.show_status(
|
|
837
|
-
"Installing frontend packages from config and components", process
|
|
838
|
-
)
|
|
839
862
|
|
|
840
863
|
|
|
841
864
|
def needs_reinit(frontend: bool = True) -> bool:
|
|
@@ -856,12 +879,16 @@ def needs_reinit(frontend: bool = True) -> bool:
|
|
|
856
879
|
)
|
|
857
880
|
raise typer.Exit(1)
|
|
858
881
|
|
|
882
|
+
# Don't need to reinit if not running in frontend mode.
|
|
883
|
+
if not frontend:
|
|
884
|
+
return False
|
|
885
|
+
|
|
859
886
|
# Make sure the .reflex directory exists.
|
|
860
887
|
if not os.path.exists(constants.Reflex.DIR):
|
|
861
888
|
return True
|
|
862
889
|
|
|
863
890
|
# Make sure the .web directory exists in frontend mode.
|
|
864
|
-
if
|
|
891
|
+
if not os.path.exists(constants.Dirs.WEB):
|
|
865
892
|
return True
|
|
866
893
|
|
|
867
894
|
if constants.IS_WINDOWS:
|
|
@@ -938,9 +965,6 @@ def validate_frontend_dependencies(init=True):
|
|
|
938
965
|
)
|
|
939
966
|
raise typer.Exit(1)
|
|
940
967
|
|
|
941
|
-
if constants.IS_WINDOWS:
|
|
942
|
-
return
|
|
943
|
-
|
|
944
968
|
if init:
|
|
945
969
|
# we only need bun for package install on `reflex init`.
|
|
946
970
|
validate_bun()
|
|
@@ -1369,7 +1393,9 @@ def initialize_app(app_name: str, template: str | None = None):
|
|
|
1369
1393
|
else:
|
|
1370
1394
|
# Check if the template is a github repo.
|
|
1371
1395
|
if template.startswith("https://github.com"):
|
|
1372
|
-
template_url =
|
|
1396
|
+
template_url = (
|
|
1397
|
+
f"{template.strip('/').replace('.git', '')}/archive/main.zip"
|
|
1398
|
+
)
|
|
1373
1399
|
else:
|
|
1374
1400
|
console.error(f"Template `{template}` not found.")
|
|
1375
1401
|
raise typer.Exit(1)
|
reflex/utils/processes.py
CHANGED
|
@@ -202,13 +202,19 @@ def run_concurrently(*fns: Union[Callable, Tuple]) -> None:
|
|
|
202
202
|
pass
|
|
203
203
|
|
|
204
204
|
|
|
205
|
-
def stream_logs(
|
|
205
|
+
def stream_logs(
|
|
206
|
+
message: str,
|
|
207
|
+
process: subprocess.Popen,
|
|
208
|
+
progress=None,
|
|
209
|
+
suppress_errors: bool = False,
|
|
210
|
+
):
|
|
206
211
|
"""Stream the logs for a process.
|
|
207
212
|
|
|
208
213
|
Args:
|
|
209
214
|
message: The message to display.
|
|
210
215
|
process: The process.
|
|
211
216
|
progress: The ongoing progress bar if one is being used.
|
|
217
|
+
suppress_errors: If True, do not exit if errors are encountered (for fallback).
|
|
212
218
|
|
|
213
219
|
Yields:
|
|
214
220
|
The lines of the process output.
|
|
@@ -232,7 +238,7 @@ def stream_logs(message: str, process: subprocess.Popen, progress=None):
|
|
|
232
238
|
# Windows uvicorn bug
|
|
233
239
|
# https://github.com/reflex-dev/reflex/issues/2335
|
|
234
240
|
accepted_return_codes = [0, -2, 15] if constants.IS_WINDOWS else [0, -2]
|
|
235
|
-
if process.returncode not in accepted_return_codes:
|
|
241
|
+
if process.returncode not in accepted_return_codes and not suppress_errors:
|
|
236
242
|
console.error(f"{message} failed with exit code {process.returncode}")
|
|
237
243
|
for line in logs:
|
|
238
244
|
console.error(line, end="")
|
|
@@ -251,15 +257,16 @@ def show_logs(message: str, process: subprocess.Popen):
|
|
|
251
257
|
pass
|
|
252
258
|
|
|
253
259
|
|
|
254
|
-
def show_status(message: str, process: subprocess.Popen):
|
|
260
|
+
def show_status(message: str, process: subprocess.Popen, suppress_errors: bool = False):
|
|
255
261
|
"""Show the status of a process.
|
|
256
262
|
|
|
257
263
|
Args:
|
|
258
264
|
message: The initial message to display.
|
|
259
265
|
process: The process.
|
|
266
|
+
suppress_errors: If True, do not exit if errors are encountered (for fallback).
|
|
260
267
|
"""
|
|
261
268
|
with console.status(message) as status:
|
|
262
|
-
for line in stream_logs(message, process):
|
|
269
|
+
for line in stream_logs(message, process, suppress_errors=suppress_errors):
|
|
263
270
|
status.update(f"{message} {line}")
|
|
264
271
|
|
|
265
272
|
|
|
@@ -287,3 +294,33 @@ def show_progress(message: str, process: subprocess.Popen, checkpoints: List[str
|
|
|
287
294
|
def atexit_handler():
|
|
288
295
|
"""Display a custom message with the current time when exiting an app."""
|
|
289
296
|
console.log("Reflex app stopped.")
|
|
297
|
+
|
|
298
|
+
|
|
299
|
+
def run_process_with_fallback(args, *, show_status_message, fallback=None, **kwargs):
|
|
300
|
+
"""Run subprocess and retry using fallback command if initial command fails.
|
|
301
|
+
|
|
302
|
+
Args:
|
|
303
|
+
args: A string, or a sequence of program arguments.
|
|
304
|
+
show_status_message: The status message to be displayed in the console.
|
|
305
|
+
fallback: The fallback command to run.
|
|
306
|
+
kwargs: Kwargs to pass to new_process function.
|
|
307
|
+
"""
|
|
308
|
+
process = new_process(args, **kwargs)
|
|
309
|
+
if fallback is None:
|
|
310
|
+
# No fallback given, or this _is_ the fallback command.
|
|
311
|
+
show_status(show_status_message, process)
|
|
312
|
+
else:
|
|
313
|
+
# Suppress errors for initial command, because we will try to fallback
|
|
314
|
+
show_status(show_status_message, process, suppress_errors=True)
|
|
315
|
+
if process.returncode != 0:
|
|
316
|
+
# retry with fallback command.
|
|
317
|
+
fallback_args = [fallback, *args[1:]]
|
|
318
|
+
console.warn(
|
|
319
|
+
f"There was an error running command: {args}. Falling back to: {fallback_args}."
|
|
320
|
+
)
|
|
321
|
+
run_process_with_fallback(
|
|
322
|
+
fallback_args,
|
|
323
|
+
show_status_message=show_status_message,
|
|
324
|
+
fallback=None,
|
|
325
|
+
**kwargs,
|
|
326
|
+
)
|
reflex/utils/serializers.py
CHANGED
|
@@ -6,6 +6,7 @@ import json
|
|
|
6
6
|
import types as builtin_types
|
|
7
7
|
import warnings
|
|
8
8
|
from datetime import date, datetime, time, timedelta
|
|
9
|
+
from enum import Enum
|
|
9
10
|
from typing import Any, Callable, Dict, List, Set, Tuple, Type, Union, get_type_hints
|
|
10
11
|
|
|
11
12
|
from reflex.base import Base
|
|
@@ -232,6 +233,19 @@ def serialize_datetime(dt: Union[date, datetime, time, timedelta]) -> str:
|
|
|
232
233
|
return str(dt)
|
|
233
234
|
|
|
234
235
|
|
|
236
|
+
@serializer
|
|
237
|
+
def serialize_enum(en: Enum) -> str:
|
|
238
|
+
"""Serialize a enum to a JSON string.
|
|
239
|
+
|
|
240
|
+
Args:
|
|
241
|
+
en: The enum to serialize.
|
|
242
|
+
|
|
243
|
+
Returns:
|
|
244
|
+
The serialized enum.
|
|
245
|
+
"""
|
|
246
|
+
return en.value
|
|
247
|
+
|
|
248
|
+
|
|
235
249
|
@serializer
|
|
236
250
|
def serialize_color(color: Color) -> str:
|
|
237
251
|
"""Serialize a color.
|
reflex/utils/types.py
CHANGED
|
@@ -29,7 +29,7 @@ try:
|
|
|
29
29
|
# reflex-hosting-cli tools are compatible with pydantic v2
|
|
30
30
|
|
|
31
31
|
if not TYPE_CHECKING:
|
|
32
|
-
|
|
32
|
+
from pydantic.v1.fields import ModelField
|
|
33
33
|
else:
|
|
34
34
|
raise ModuleNotFoundError
|
|
35
35
|
except ModuleNotFoundError:
|
|
@@ -416,11 +416,12 @@ def validate_literal(key: str, value: Any, expected_type: Type, comp_name: str):
|
|
|
416
416
|
):
|
|
417
417
|
allowed_values = expected_type.__args__
|
|
418
418
|
if value not in allowed_values:
|
|
419
|
-
|
|
419
|
+
allowed_value_str = ",".join(
|
|
420
420
|
[str(v) if not isinstance(v, str) else f"'{v}'" for v in allowed_values]
|
|
421
421
|
)
|
|
422
|
+
value_str = f"'{value}'" if isinstance(value, str) else value
|
|
422
423
|
raise ValueError(
|
|
423
|
-
f"prop value for {str(key)} of the `{comp_name}` component should be one of the following: {
|
|
424
|
+
f"prop value for {str(key)} of the `{comp_name}` component should be one of the following: {allowed_value_str}. Got {value_str} instead"
|
|
424
425
|
)
|
|
425
426
|
|
|
426
427
|
|