reflex 0.8.13a1__py3-none-any.whl → 0.8.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/app.py +25 -5
- reflex/components/core/upload.py +9 -13
- reflex/components/plotly/plotly.py +9 -9
- reflex/components/radix/primitives/slider.py +3 -17
- reflex/components/radix/primitives/slider.pyi +2 -4
- reflex/components/radix/themes/components/slider.py +1 -2
- reflex/components/radix/themes/components/slider.pyi +3 -6
- reflex/components/react_player/audio.pyi +23 -46
- reflex/components/react_player/react_player.pyi +40 -45
- reflex/components/react_player/video.pyi +23 -46
- reflex/constants/colors.py +1 -3
- reflex/constants/installer.py +5 -5
- reflex/custom_components/custom_components.py +18 -18
- reflex/environment.py +3 -0
- reflex/plugins/shared_tailwind.py +1 -1
- reflex/reflex.py +62 -24
- reflex/state.py +3 -2
- reflex/utils/exec.py +23 -4
- reflex/utils/frontend_skeleton.py +3 -5
- reflex/utils/js_runtimes.py +10 -10
- reflex/utils/prerequisites.py +5 -6
- reflex/utils/processes.py +10 -11
- reflex/utils/rename.py +3 -5
- reflex/utils/serializers.py +3 -7
- reflex/utils/templates.py +20 -22
- reflex/vars/color.py +2 -68
- {reflex-0.8.13a1.dist-info → reflex-0.8.14a1.dist-info}/METADATA +1 -1
- {reflex-0.8.13a1.dist-info → reflex-0.8.14a1.dist-info}/RECORD +31 -31
- {reflex-0.8.13a1.dist-info → reflex-0.8.14a1.dist-info}/WHEEL +0 -0
- {reflex-0.8.13a1.dist-info → reflex-0.8.14a1.dist-info}/entry_points.txt +0 -0
- {reflex-0.8.13a1.dist-info → reflex-0.8.14a1.dist-info}/licenses/LICENSE +0 -0
|
@@ -6,7 +6,6 @@
|
|
|
6
6
|
from collections.abc import Mapping, Sequence
|
|
7
7
|
from typing import Any
|
|
8
8
|
|
|
9
|
-
import reflex
|
|
10
9
|
from reflex.components.core.breakpoints import Breakpoints
|
|
11
10
|
from reflex.components.react_player.react_player import ReactPlayer
|
|
12
11
|
from reflex.event import EventType, PointerEventInfo
|
|
@@ -17,13 +16,18 @@ class Video(ReactPlayer):
|
|
|
17
16
|
def create(
|
|
18
17
|
cls,
|
|
19
18
|
*children,
|
|
20
|
-
|
|
19
|
+
src: Var[list[dict[str, str]] | list[str] | str]
|
|
20
|
+
| list[dict[str, str]]
|
|
21
|
+
| list[str]
|
|
22
|
+
| str
|
|
23
|
+
| None = None,
|
|
21
24
|
playing: Var[bool] | bool | None = None,
|
|
22
25
|
loop: Var[bool] | bool | None = None,
|
|
23
26
|
controls: Var[bool] | bool | None = None,
|
|
24
27
|
light: Var[bool] | bool | None = None,
|
|
25
28
|
volume: Var[float] | float | None = None,
|
|
26
29
|
muted: Var[bool] | bool | None = None,
|
|
30
|
+
config: Var[dict[str, Any]] | dict[str, Any] | None = None,
|
|
27
31
|
style: Sequence[Mapping[str, Any]]
|
|
28
32
|
| Mapping[str, Any]
|
|
29
33
|
| Var[Mapping[str, Any]]
|
|
@@ -35,18 +39,16 @@ class Video(ReactPlayer):
|
|
|
35
39
|
class_name: Any | None = None,
|
|
36
40
|
custom_attrs: dict[str, Var | Any] | None = None,
|
|
37
41
|
on_blur: EventType[()] | None = None,
|
|
38
|
-
on_buffer: EventType[()] | None = None,
|
|
39
|
-
on_buffer_end: EventType[()] | None = None,
|
|
40
42
|
on_click: EventType[()] | EventType[PointerEventInfo] | None = None,
|
|
41
43
|
on_click_preview: EventType[()] | None = None,
|
|
42
44
|
on_context_menu: EventType[()] | EventType[PointerEventInfo] | None = None,
|
|
43
|
-
on_disable_pip: EventType[()] | None = None,
|
|
44
45
|
on_double_click: EventType[()] | EventType[PointerEventInfo] | None = None,
|
|
45
|
-
|
|
46
|
-
on_enable_pip: EventType[()] | None = None,
|
|
46
|
+
on_duration_change: EventType[Any] | None = None,
|
|
47
47
|
on_ended: EventType[()] | None = None,
|
|
48
|
+
on_enter_picture_in_picture: EventType[()] | None = None,
|
|
48
49
|
on_error: EventType[()] | None = None,
|
|
49
50
|
on_focus: EventType[()] | None = None,
|
|
51
|
+
on_leave_picture_in_picture: EventType[()] | None = None,
|
|
50
52
|
on_mount: EventType[()] | None = None,
|
|
51
53
|
on_mouse_down: EventType[()] | None = None,
|
|
52
54
|
on_mouse_enter: EventType[()] | None = None,
|
|
@@ -57,54 +59,29 @@ class Video(ReactPlayer):
|
|
|
57
59
|
on_mouse_up: EventType[()] | None = None,
|
|
58
60
|
on_pause: EventType[()] | None = None,
|
|
59
61
|
on_play: EventType[()] | None = None,
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
| EventType[reflex.components.react_player.react_player.Progress]
|
|
64
|
-
| None = None,
|
|
62
|
+
on_playing: EventType[()] | None = None,
|
|
63
|
+
on_progress: EventType[Any] | None = None,
|
|
64
|
+
on_rate_change: EventType[Any] | None = None,
|
|
65
65
|
on_ready: EventType[()] | None = None,
|
|
66
66
|
on_scroll: EventType[()] | None = None,
|
|
67
67
|
on_scroll_end: EventType[()] | None = None,
|
|
68
|
-
|
|
68
|
+
on_seeked: EventType[Any] | None = None,
|
|
69
|
+
on_seeking: EventType[()] | None = None,
|
|
69
70
|
on_start: EventType[()] | None = None,
|
|
71
|
+
on_time_update: EventType[Any] | None = None,
|
|
70
72
|
on_unmount: EventType[()] | None = None,
|
|
73
|
+
on_waiting: EventType[()] | None = None,
|
|
71
74
|
**props,
|
|
72
75
|
) -> Video:
|
|
73
|
-
"""Create
|
|
76
|
+
"""Create a component.
|
|
74
77
|
|
|
75
78
|
Args:
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
playing: Set to true or false to pause or play the media
|
|
79
|
-
loop: Set to true or false to loop the media
|
|
80
|
-
controls: Set to true or false to display native player controls.
|
|
81
|
-
light: Set to true to show just the video thumbnail, which loads the full player on click
|
|
82
|
-
volume: Set the volume of the player, between 0 and 1
|
|
83
|
-
muted: Mutes the player
|
|
84
|
-
on_ready: Called when media is loaded and ready to play. If playing is set to true, media will play immediately.
|
|
85
|
-
on_start: Called when media starts playing.
|
|
86
|
-
on_play: Called when media starts or resumes playing after pausing or buffering.
|
|
87
|
-
on_progress: Callback containing played and loaded progress as a fraction, and playedSeconds and loadedSeconds in seconds. eg { played: 0.12, playedSeconds: 11.3, loaded: 0.34, loadedSeconds: 16.7 }
|
|
88
|
-
on_duration: Callback containing duration of the media, in seconds.
|
|
89
|
-
on_pause: Called when media is paused.
|
|
90
|
-
on_buffer: Called when media starts buffering.
|
|
91
|
-
on_buffer_end: Called when media has finished buffering. Works for files, YouTube and Facebook.
|
|
92
|
-
on_seek: Called when media seeks with seconds parameter.
|
|
93
|
-
on_playback_rate_change: Called when playback rate of the player changed. Only supported by YouTube, Vimeo (if enabled), Wistia, and file paths.
|
|
94
|
-
on_playback_quality_change: Called when playback quality of the player changed. Only supported by YouTube (if enabled).
|
|
95
|
-
on_ended: Called when media finishes playing. Does not fire when loop is set to true.
|
|
96
|
-
on_error: Called when an error occurs whilst attempting to play media.
|
|
97
|
-
on_click_preview: Called when user clicks the light mode preview.
|
|
98
|
-
on_enable_pip: Called when picture-in-picture mode is enabled.
|
|
99
|
-
on_disable_pip: Called when picture-in-picture mode is disabled.
|
|
100
|
-
style: The style of the component.
|
|
101
|
-
key: A unique key for the component.
|
|
102
|
-
id: The id for the component.
|
|
103
|
-
ref: The Var to pass as the ref to the component.
|
|
104
|
-
class_name: The class name for the component.
|
|
105
|
-
custom_attrs: custom attribute
|
|
106
|
-
**props: The props of the component.
|
|
79
|
+
children: The children of the component.
|
|
80
|
+
props: The props of the component.
|
|
107
81
|
|
|
108
82
|
Returns:
|
|
109
|
-
The component.
|
|
83
|
+
The created component.
|
|
84
|
+
|
|
85
|
+
Raises:
|
|
86
|
+
ValueError: If both a deprecated prop and its replacement are both passed.
|
|
110
87
|
"""
|
reflex/constants/colors.py
CHANGED
reflex/constants/installer.py
CHANGED
|
@@ -14,7 +14,7 @@ class Bun(SimpleNamespace):
|
|
|
14
14
|
"""Bun constants."""
|
|
15
15
|
|
|
16
16
|
# The Bun version.
|
|
17
|
-
VERSION = "1.2.
|
|
17
|
+
VERSION = "1.2.23"
|
|
18
18
|
|
|
19
19
|
# Min Bun Version
|
|
20
20
|
MIN_VERSION = "1.2.17"
|
|
@@ -75,7 +75,7 @@ fetch-retries=0
|
|
|
75
75
|
|
|
76
76
|
|
|
77
77
|
def _determine_react_router_version() -> str:
|
|
78
|
-
default_version = "7.9.
|
|
78
|
+
default_version = "7.9.3"
|
|
79
79
|
if (version := os.getenv("REACT_ROUTER_VERSION")) and version != default_version:
|
|
80
80
|
from reflex.utils import console
|
|
81
81
|
|
|
@@ -131,7 +131,7 @@ class PackageJson(SimpleNamespace):
|
|
|
131
131
|
"react": cls._react_version,
|
|
132
132
|
"react-helmet": "6.1.0",
|
|
133
133
|
"react-dom": cls._react_version,
|
|
134
|
-
"isbot": "5.1.
|
|
134
|
+
"isbot": "5.1.31",
|
|
135
135
|
"socket.io-client": "4.8.1",
|
|
136
136
|
"universal-cookie": "7.2.2",
|
|
137
137
|
}
|
|
@@ -143,11 +143,11 @@ class PackageJson(SimpleNamespace):
|
|
|
143
143
|
"postcss-import": "16.1.1",
|
|
144
144
|
"@react-router/dev": _react_router_version,
|
|
145
145
|
"@react-router/fs-routes": _react_router_version,
|
|
146
|
-
"vite": "npm:rolldown-vite@7.1.
|
|
146
|
+
"vite": "npm:rolldown-vite@7.1.13",
|
|
147
147
|
}
|
|
148
148
|
OVERRIDES = {
|
|
149
149
|
# This should always match the `react` version in DEPENDENCIES for recharts compatibility.
|
|
150
150
|
"react-is": _react_version,
|
|
151
151
|
"cookie": "1.0.2",
|
|
152
|
-
"vite": "npm:rolldown-vite@7.1.
|
|
152
|
+
"vite": "npm:rolldown-vite@7.1.13",
|
|
153
153
|
}
|
|
@@ -359,7 +359,7 @@ def _get_default_library_name_parts() -> list[str]:
|
|
|
359
359
|
"""Get the default library name. Based on the current directory name, remove any non-alphanumeric characters.
|
|
360
360
|
|
|
361
361
|
Raises:
|
|
362
|
-
|
|
362
|
+
SystemExit: If the current directory name is not suitable for python projects, and we cannot find a valid library name based off it.
|
|
363
363
|
|
|
364
364
|
Returns:
|
|
365
365
|
The parts of default library name.
|
|
@@ -377,13 +377,13 @@ def _get_default_library_name_parts() -> list[str]:
|
|
|
377
377
|
console.error(
|
|
378
378
|
f"Based on current directory name {current_dir_name}, the library name is {constants.Reflex.MODULE_NAME}. This package already exists. Please use --library-name to specify a different name."
|
|
379
379
|
)
|
|
380
|
-
raise
|
|
380
|
+
raise SystemExit(1)
|
|
381
381
|
if not parts:
|
|
382
382
|
# The folder likely has a name not suitable for python paths.
|
|
383
383
|
console.error(
|
|
384
384
|
f"Could not find a valid library name based on the current directory: got {current_dir_name}."
|
|
385
385
|
)
|
|
386
|
-
raise
|
|
386
|
+
raise SystemExit(1)
|
|
387
387
|
return parts
|
|
388
388
|
|
|
389
389
|
|
|
@@ -408,7 +408,7 @@ def _validate_library_name(library_name: str | None) -> NameVariants:
|
|
|
408
408
|
library_name: The name of the library if picked otherwise None.
|
|
409
409
|
|
|
410
410
|
Raises:
|
|
411
|
-
|
|
411
|
+
SystemExit: If the library name is not suitable for python projects.
|
|
412
412
|
|
|
413
413
|
Returns:
|
|
414
414
|
A tuple containing the various names such as package name, class name, etc., needed for the project.
|
|
@@ -419,7 +419,7 @@ def _validate_library_name(library_name: str | None) -> NameVariants:
|
|
|
419
419
|
console.error(
|
|
420
420
|
f"Please use only alphanumeric characters or dashes: got {library_name}"
|
|
421
421
|
)
|
|
422
|
-
raise
|
|
422
|
+
raise SystemExit(1)
|
|
423
423
|
|
|
424
424
|
# If not specified, use the current directory name to form the module name.
|
|
425
425
|
name_parts = (
|
|
@@ -513,13 +513,13 @@ def init(
|
|
|
513
513
|
install: Whether to install package from this local custom component in editable mode.
|
|
514
514
|
|
|
515
515
|
Raises:
|
|
516
|
-
|
|
516
|
+
SystemExit: If the pyproject.toml already exists.
|
|
517
517
|
"""
|
|
518
518
|
from reflex.utils import exec
|
|
519
519
|
|
|
520
520
|
if CustomComponents.PYPROJECT_TOML.exists():
|
|
521
521
|
console.error(f"A {CustomComponents.PYPROJECT_TOML} already exists. Aborting.")
|
|
522
|
-
|
|
522
|
+
raise SystemExit(1)
|
|
523
523
|
|
|
524
524
|
# Show system info.
|
|
525
525
|
exec.output_system_info()
|
|
@@ -544,7 +544,7 @@ def init(
|
|
|
544
544
|
if _pip_install_on_demand(package_name=".", install_args=["-e"]):
|
|
545
545
|
console.info(f"Package {package_name} installed!")
|
|
546
546
|
else:
|
|
547
|
-
raise
|
|
547
|
+
raise SystemExit(1)
|
|
548
548
|
|
|
549
549
|
console.print("[bold]Custom component initialized successfully!")
|
|
550
550
|
console.rule("[bold]Project Summary")
|
|
@@ -627,7 +627,7 @@ def _run_build():
|
|
|
627
627
|
"""Run the build command.
|
|
628
628
|
|
|
629
629
|
Raises:
|
|
630
|
-
|
|
630
|
+
SystemExit: If the build fails.
|
|
631
631
|
"""
|
|
632
632
|
console.print("Building custom component...")
|
|
633
633
|
|
|
@@ -637,7 +637,7 @@ def _run_build():
|
|
|
637
637
|
if _run_commands_in_subprocess(cmds):
|
|
638
638
|
console.info("Custom component built successfully!")
|
|
639
639
|
else:
|
|
640
|
-
raise
|
|
640
|
+
raise SystemExit(1)
|
|
641
641
|
|
|
642
642
|
|
|
643
643
|
@custom_components_cli.command(name="build")
|
|
@@ -651,7 +651,7 @@ def _collect_details_for_gallery():
|
|
|
651
651
|
"""Helper to collect details on the custom component to be included in the gallery.
|
|
652
652
|
|
|
653
653
|
Raises:
|
|
654
|
-
|
|
654
|
+
SystemExit: If pyproject.toml file is ill-formed or the request to the backend services fails.
|
|
655
655
|
"""
|
|
656
656
|
import httpx
|
|
657
657
|
from reflex_cli.utils import hosting
|
|
@@ -664,7 +664,7 @@ def _collect_details_for_gallery():
|
|
|
664
664
|
console.error(
|
|
665
665
|
"Unable to authenticate with Reflex backend services. Make sure you are logged in."
|
|
666
666
|
)
|
|
667
|
-
raise
|
|
667
|
+
raise SystemExit(1)
|
|
668
668
|
|
|
669
669
|
console.rule("[bold]Custom Component Information")
|
|
670
670
|
params = {}
|
|
@@ -694,11 +694,11 @@ def _collect_details_for_gallery():
|
|
|
694
694
|
console.error(
|
|
695
695
|
f"{package_name} is owned by another user. Unable to update the information for it."
|
|
696
696
|
)
|
|
697
|
-
raise
|
|
697
|
+
raise SystemExit(1)
|
|
698
698
|
response.raise_for_status()
|
|
699
699
|
except httpx.HTTPError as he:
|
|
700
700
|
console.error(f"Unable to complete request due to {he}.")
|
|
701
|
-
raise
|
|
701
|
+
raise SystemExit(1) from None
|
|
702
702
|
|
|
703
703
|
files = []
|
|
704
704
|
if (image_file_and_extension := _get_file_from_prompt_in_loop()) is not None:
|
|
@@ -733,7 +733,7 @@ def _collect_details_for_gallery():
|
|
|
733
733
|
|
|
734
734
|
except httpx.HTTPError as he:
|
|
735
735
|
console.error(f"Unable to complete request due to {he}.")
|
|
736
|
-
raise
|
|
736
|
+
raise SystemExit(1) from None
|
|
737
737
|
|
|
738
738
|
console.info("Custom component information successfully shared!")
|
|
739
739
|
|
|
@@ -769,7 +769,7 @@ def _get_file_from_prompt_in_loop() -> tuple[bytes, str] | None:
|
|
|
769
769
|
image_file = image_file_path.read_bytes()
|
|
770
770
|
except OSError as ose:
|
|
771
771
|
console.error(f"Unable to read the {file_extension} file due to {ose}")
|
|
772
|
-
raise
|
|
772
|
+
raise SystemExit(1) from None
|
|
773
773
|
else:
|
|
774
774
|
return image_file, file_extension
|
|
775
775
|
|
|
@@ -790,9 +790,9 @@ def install():
|
|
|
790
790
|
"""Install package from this local custom component in editable mode.
|
|
791
791
|
|
|
792
792
|
Raises:
|
|
793
|
-
|
|
793
|
+
SystemExit: If unable to install the current directory in editable mode.
|
|
794
794
|
"""
|
|
795
795
|
if _pip_install_on_demand(package_name=".", install_args=["-e"]):
|
|
796
796
|
console.info("Package installed successfully!")
|
|
797
797
|
else:
|
|
798
|
-
raise
|
|
798
|
+
raise SystemExit(1)
|
reflex/environment.py
CHANGED
|
@@ -660,6 +660,9 @@ class EnvironmentVariables:
|
|
|
660
660
|
# Whether to enable SSR for the frontend.
|
|
661
661
|
REFLEX_SSR: EnvVar[bool] = env_var(True)
|
|
662
662
|
|
|
663
|
+
# Whether to mount the compiled frontend app in the backend server in production.
|
|
664
|
+
REFLEX_MOUNT_FRONTEND_COMPILED_APP: EnvVar[bool] = env_var(False, internal=True)
|
|
665
|
+
|
|
663
666
|
|
|
664
667
|
environment = EnvironmentVariables()
|
|
665
668
|
|
reflex/reflex.py
CHANGED
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
-
import atexit
|
|
6
5
|
from importlib.util import find_spec
|
|
7
6
|
from pathlib import Path
|
|
8
7
|
from typing import TYPE_CHECKING
|
|
@@ -132,8 +131,11 @@ def _run(
|
|
|
132
131
|
frontend_port: int | None = None,
|
|
133
132
|
backend_port: int | None = None,
|
|
134
133
|
backend_host: str | None = None,
|
|
134
|
+
single_port: bool = False,
|
|
135
135
|
):
|
|
136
136
|
"""Run the app in the given directory."""
|
|
137
|
+
import atexit
|
|
138
|
+
|
|
137
139
|
from reflex.utils import build, exec, prerequisites, processes
|
|
138
140
|
|
|
139
141
|
config = get_config()
|
|
@@ -173,7 +175,9 @@ def _run(
|
|
|
173
175
|
auto_increment=auto_increment_frontend,
|
|
174
176
|
)
|
|
175
177
|
|
|
176
|
-
if
|
|
178
|
+
if single_port:
|
|
179
|
+
backend_port = frontend_port
|
|
180
|
+
elif backend:
|
|
177
181
|
auto_increment_backend = not bool(backend_port or config.backend_port)
|
|
178
182
|
|
|
179
183
|
backend_port = processes.handle_port(
|
|
@@ -223,23 +227,23 @@ def _run(
|
|
|
223
227
|
if not return_result:
|
|
224
228
|
raise SystemExit(1)
|
|
225
229
|
|
|
230
|
+
if env != constants.Env.PROD and env != constants.Env.DEV:
|
|
231
|
+
msg = f"Invalid env: {env}. Must be DEV or PROD."
|
|
232
|
+
raise ValueError(msg)
|
|
233
|
+
|
|
226
234
|
# Get the frontend and backend commands, based on the environment.
|
|
227
|
-
setup_frontend = frontend_cmd = backend_cmd = None
|
|
228
235
|
if env == constants.Env.DEV:
|
|
229
236
|
setup_frontend, frontend_cmd, backend_cmd = (
|
|
230
237
|
build.setup_frontend,
|
|
231
238
|
exec.run_frontend,
|
|
232
239
|
exec.run_backend,
|
|
233
240
|
)
|
|
234
|
-
|
|
241
|
+
elif env == constants.Env.PROD:
|
|
235
242
|
setup_frontend, frontend_cmd, backend_cmd = (
|
|
236
243
|
build.setup_frontend_prod,
|
|
237
244
|
exec.run_frontend_prod,
|
|
238
245
|
exec.run_backend_prod,
|
|
239
246
|
)
|
|
240
|
-
if not setup_frontend or not frontend_cmd or not backend_cmd:
|
|
241
|
-
msg = f"Invalid env: {env}. Must be DEV or PROD."
|
|
242
|
-
raise ValueError(msg)
|
|
243
247
|
|
|
244
248
|
# Post a telemetry event.
|
|
245
249
|
telemetry.send(f"run-{env.value}")
|
|
@@ -251,7 +255,7 @@ def _run(
|
|
|
251
255
|
commands = []
|
|
252
256
|
|
|
253
257
|
# Run the frontend on a separate thread.
|
|
254
|
-
if frontend:
|
|
258
|
+
if frontend and not single_port:
|
|
255
259
|
setup_frontend(Path.cwd())
|
|
256
260
|
commands.append((frontend_cmd, Path.cwd(), frontend_port, backend))
|
|
257
261
|
|
|
@@ -267,21 +271,30 @@ def _run(
|
|
|
267
271
|
)
|
|
268
272
|
)
|
|
269
273
|
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
#
|
|
282
|
-
if
|
|
283
|
-
|
|
284
|
-
|
|
274
|
+
if single_port:
|
|
275
|
+
setup_frontend(Path.cwd())
|
|
276
|
+
backend_function, *args = commands[0]
|
|
277
|
+
exec.notify_app_running()
|
|
278
|
+
exec.notify_frontend(
|
|
279
|
+
f"http://0.0.0.0:{get_config().frontend_port}", backend_present=True
|
|
280
|
+
)
|
|
281
|
+
backend_function(*args, mount_frontend_compiled_app=True)
|
|
282
|
+
else:
|
|
283
|
+
# Start the frontend and backend.
|
|
284
|
+
with processes.run_concurrently_context(*commands):
|
|
285
|
+
# In dev mode, run the backend on the main thread.
|
|
286
|
+
if backend and backend_port and env == constants.Env.DEV:
|
|
287
|
+
backend_cmd(
|
|
288
|
+
backend_host,
|
|
289
|
+
int(backend_port),
|
|
290
|
+
config.loglevel.subprocess_level(),
|
|
291
|
+
frontend,
|
|
292
|
+
)
|
|
293
|
+
# The windows uvicorn bug workaround
|
|
294
|
+
# https://github.com/reflex-dev/reflex/issues/2335
|
|
295
|
+
if constants.IS_WINDOWS and exec.frontend_process:
|
|
296
|
+
# Sends SIGTERM in windows
|
|
297
|
+
exec.kill(exec.frontend_process.pid)
|
|
285
298
|
|
|
286
299
|
|
|
287
300
|
@cli.command()
|
|
@@ -322,6 +335,12 @@ def _run(
|
|
|
322
335
|
"--backend-host",
|
|
323
336
|
help="Specify the backend host.",
|
|
324
337
|
)
|
|
338
|
+
@click.option(
|
|
339
|
+
"--single-port",
|
|
340
|
+
is_flag=True,
|
|
341
|
+
help="Run both frontend and backend on the same port.",
|
|
342
|
+
default=False,
|
|
343
|
+
)
|
|
325
344
|
def run(
|
|
326
345
|
env: LITERAL_ENV,
|
|
327
346
|
frontend_only: bool,
|
|
@@ -329,11 +348,29 @@ def run(
|
|
|
329
348
|
frontend_port: int | None,
|
|
330
349
|
backend_port: int | None,
|
|
331
350
|
backend_host: str | None,
|
|
351
|
+
single_port: bool,
|
|
332
352
|
):
|
|
333
353
|
"""Run the app in the current directory."""
|
|
334
354
|
if frontend_only and backend_only:
|
|
335
355
|
console.error("Cannot use both --frontend-only and --backend-only options.")
|
|
336
|
-
raise
|
|
356
|
+
raise SystemExit(1)
|
|
357
|
+
|
|
358
|
+
if single_port:
|
|
359
|
+
if env != constants.Env.PROD.value:
|
|
360
|
+
console.error("--single-port can only be used with --env=PROD.")
|
|
361
|
+
raise click.exceptions.Exit(1)
|
|
362
|
+
if frontend_only or backend_only:
|
|
363
|
+
console.error(
|
|
364
|
+
"Cannot use --single-port with --frontend-only or --backend-only options."
|
|
365
|
+
)
|
|
366
|
+
raise click.exceptions.Exit(1)
|
|
367
|
+
if backend_port and frontend_port and backend_port != frontend_port:
|
|
368
|
+
console.error(
|
|
369
|
+
"When using --single-port, --backend-port and --frontend-port must be the same."
|
|
370
|
+
)
|
|
371
|
+
raise click.exceptions.Exit(1)
|
|
372
|
+
elif frontend_port and backend_port and frontend_port == backend_port:
|
|
373
|
+
single_port = True
|
|
337
374
|
|
|
338
375
|
config = get_config()
|
|
339
376
|
|
|
@@ -352,6 +389,7 @@ def run(
|
|
|
352
389
|
frontend_port,
|
|
353
390
|
backend_port,
|
|
354
391
|
backend_host,
|
|
392
|
+
single_port,
|
|
355
393
|
)
|
|
356
394
|
|
|
357
395
|
|
reflex/state.py
CHANGED
|
@@ -533,7 +533,7 @@ class BaseState(EvenMoreBasicBaseState):
|
|
|
533
533
|
cls._check_overridden_computed_vars()
|
|
534
534
|
|
|
535
535
|
new_backend_vars = {
|
|
536
|
-
name: value
|
|
536
|
+
name: value if not isinstance(value, Field) else value.default_value()
|
|
537
537
|
for name, value in list(cls.__dict__.items())
|
|
538
538
|
if types.is_backend_base_variable(name, cls)
|
|
539
539
|
}
|
|
@@ -1207,7 +1207,8 @@ class BaseState(EvenMoreBasicBaseState):
|
|
|
1207
1207
|
The default value of the var or None.
|
|
1208
1208
|
"""
|
|
1209
1209
|
try:
|
|
1210
|
-
|
|
1210
|
+
value = getattr(cls, name)
|
|
1211
|
+
return value if not isinstance(value, Field) else value.default_value()
|
|
1211
1212
|
except AttributeError:
|
|
1212
1213
|
try:
|
|
1213
1214
|
return types.get_default_value_for_type(annotation_value)
|
reflex/utils/exec.py
CHANGED
|
@@ -145,6 +145,18 @@ def kill(proc_pid: int):
|
|
|
145
145
|
process.kill()
|
|
146
146
|
|
|
147
147
|
|
|
148
|
+
def notify_frontend(url: str, backend_present: bool):
|
|
149
|
+
"""Output a string notifying where the frontend is running.
|
|
150
|
+
|
|
151
|
+
Args:
|
|
152
|
+
url: The URL where the frontend is running.
|
|
153
|
+
backend_present: Whether the backend is present.
|
|
154
|
+
"""
|
|
155
|
+
console.print(
|
|
156
|
+
f"App running at: [bold green]{url.rstrip('/')}/[/bold green]{' (Frontend-only mode)' if not backend_present else ''}"
|
|
157
|
+
)
|
|
158
|
+
|
|
159
|
+
|
|
148
160
|
def notify_backend():
|
|
149
161
|
"""Output a string notifying where the backend is running."""
|
|
150
162
|
console.print(
|
|
@@ -210,9 +222,7 @@ def run_process_and_launch_url(
|
|
|
210
222
|
if get_config().frontend_path != "":
|
|
211
223
|
url = urljoin(url, get_config().frontend_path)
|
|
212
224
|
|
|
213
|
-
|
|
214
|
-
f"App running at: [bold green]{url}[/bold green]{' (Frontend-only mode)' if not backend_present else ''}"
|
|
215
|
-
)
|
|
225
|
+
notify_frontend(url, backend_present)
|
|
216
226
|
if backend_present:
|
|
217
227
|
notify_backend()
|
|
218
228
|
first_run = False
|
|
@@ -249,6 +259,11 @@ def run_frontend(root: Path, port: str, backend_present: bool = True):
|
|
|
249
259
|
)
|
|
250
260
|
|
|
251
261
|
|
|
262
|
+
def notify_app_running():
|
|
263
|
+
"""Notify that the app is running."""
|
|
264
|
+
console.rule("[bold green]App Running")
|
|
265
|
+
|
|
266
|
+
|
|
252
267
|
def run_frontend_prod(root: Path, port: str, backend_present: bool = True):
|
|
253
268
|
"""Run the frontend.
|
|
254
269
|
|
|
@@ -264,7 +279,7 @@ def run_frontend_prod(root: Path, port: str, backend_present: bool = True):
|
|
|
264
279
|
# validate dependencies before run
|
|
265
280
|
js_runtimes.validate_frontend_dependencies(init=False)
|
|
266
281
|
# Run the frontend in production mode.
|
|
267
|
-
|
|
282
|
+
notify_app_running()
|
|
268
283
|
run_process_and_launch_url(
|
|
269
284
|
[*js_runtimes.get_js_package_executor(raise_on_none=True)[0], "run", "prod"],
|
|
270
285
|
backend_present,
|
|
@@ -552,6 +567,7 @@ def run_backend_prod(
|
|
|
552
567
|
port: int,
|
|
553
568
|
loglevel: constants.LogLevel = constants.LogLevel.ERROR,
|
|
554
569
|
frontend_present: bool = False,
|
|
570
|
+
mount_frontend_compiled_app: bool = False,
|
|
555
571
|
):
|
|
556
572
|
"""Run the backend.
|
|
557
573
|
|
|
@@ -560,10 +576,13 @@ def run_backend_prod(
|
|
|
560
576
|
port: The app port
|
|
561
577
|
loglevel: The log level.
|
|
562
578
|
frontend_present: Whether the frontend is present.
|
|
579
|
+
mount_frontend_compiled_app: Whether to mount the compiled frontend app with the backend.
|
|
563
580
|
"""
|
|
564
581
|
if not frontend_present:
|
|
565
582
|
notify_backend()
|
|
566
583
|
|
|
584
|
+
environment.REFLEX_MOUNT_FRONTEND_COMPILED_APP.set(mount_frontend_compiled_app)
|
|
585
|
+
|
|
567
586
|
if should_use_granian():
|
|
568
587
|
run_granian_backend_prod(host, port, loglevel)
|
|
569
588
|
else:
|
|
@@ -5,8 +5,6 @@ import random
|
|
|
5
5
|
import re
|
|
6
6
|
from pathlib import Path
|
|
7
7
|
|
|
8
|
-
import click
|
|
9
|
-
|
|
10
8
|
from reflex import constants
|
|
11
9
|
from reflex.compiler import templates
|
|
12
10
|
from reflex.config import Config, get_config
|
|
@@ -54,7 +52,7 @@ def initialize_requirements_txt() -> bool:
|
|
|
54
52
|
True if the user has to update the requirements.txt file.
|
|
55
53
|
|
|
56
54
|
Raises:
|
|
57
|
-
|
|
55
|
+
SystemExit: If the requirements.txt file cannot be read or written to.
|
|
58
56
|
"""
|
|
59
57
|
requirements_file_path = Path(constants.RequirementsTxt.FILE)
|
|
60
58
|
if (
|
|
@@ -72,8 +70,8 @@ def initialize_requirements_txt() -> bool:
|
|
|
72
70
|
except UnicodeDecodeError:
|
|
73
71
|
continue
|
|
74
72
|
except Exception as e:
|
|
75
|
-
console.error(f"Failed to read {requirements_file_path}.")
|
|
76
|
-
raise
|
|
73
|
+
console.error(f"Failed to read {requirements_file_path} due to {e}.")
|
|
74
|
+
raise SystemExit(1) from None
|
|
77
75
|
else:
|
|
78
76
|
return True
|
|
79
77
|
|