reflex 0.8.13a1__py3-none-any.whl → 0.8.14a2__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/compiler/templates.py +4 -0
- reflex/components/core/upload.py +9 -13
- reflex/components/core/upload.pyi +27 -9
- reflex/components/plotly/plotly.py +9 -9
- reflex/components/radix/primitives/__init__.py +1 -1
- reflex/components/radix/primitives/__init__.pyi +2 -1
- reflex/components/radix/primitives/base.py +31 -0
- reflex/components/radix/primitives/base.pyi +44 -0
- reflex/components/radix/primitives/dialog.py +148 -0
- reflex/components/radix/primitives/dialog.pyi +749 -0
- 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/event.py +1 -1
- 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 +43 -33
- 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/base.py +3 -6
- reflex/vars/color.py +2 -68
- reflex/vars/object.py +1 -3
- reflex/vars/sequence.py +2 -2
- {reflex-0.8.13a1.dist-info → reflex-0.8.14a2.dist-info}/METADATA +1 -1
- {reflex-0.8.13a1.dist-info → reflex-0.8.14a2.dist-info}/RECORD +43 -41
- {reflex-0.8.13a1.dist-info → reflex-0.8.14a2.dist-info}/WHEEL +0 -0
- {reflex-0.8.13a1.dist-info → reflex-0.8.14a2.dist-info}/entry_points.txt +0 -0
- {reflex-0.8.13a1.dist-info → reflex-0.8.14a2.dist-info}/licenses/LICENSE +0 -0
|
@@ -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/event.py
CHANGED
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
|
|
reflex/utils/js_runtimes.py
CHANGED
|
@@ -6,7 +6,6 @@ import tempfile
|
|
|
6
6
|
from collections.abc import Sequence
|
|
7
7
|
from pathlib import Path
|
|
8
8
|
|
|
9
|
-
import click
|
|
10
9
|
from packaging import version
|
|
11
10
|
|
|
12
11
|
from reflex import constants
|
|
@@ -30,22 +29,45 @@ def check_node_version() -> bool:
|
|
|
30
29
|
)
|
|
31
30
|
|
|
32
31
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
32
|
+
def _get_version_of_executable(
|
|
33
|
+
executable_path: Path | None, version_arg: str = "--version"
|
|
34
|
+
) -> version.Version | None:
|
|
35
|
+
"""Get the version of an executable.
|
|
36
|
+
|
|
37
|
+
Args:
|
|
38
|
+
executable_path: The path to the executable.
|
|
39
|
+
version_arg: The argument to pass to the executable to get its version.
|
|
36
40
|
|
|
37
41
|
Returns:
|
|
38
|
-
The version of
|
|
42
|
+
The version of the executable.
|
|
39
43
|
"""
|
|
40
|
-
|
|
41
|
-
if node_path is None:
|
|
44
|
+
if executable_path is None:
|
|
42
45
|
return None
|
|
43
46
|
try:
|
|
44
|
-
result = processes.new_process([
|
|
45
|
-
|
|
46
|
-
|
|
47
|
+
result = processes.new_process([executable_path, version_arg], run=True)
|
|
48
|
+
if result.returncode != 0:
|
|
49
|
+
console.error(
|
|
50
|
+
f"Failed to run {executable_path} {version_arg} to get version. Return code: {result.returncode}. Standard error: {result.stderr!r}."
|
|
51
|
+
)
|
|
52
|
+
return None
|
|
53
|
+
return version.parse(result.stdout.strip())
|
|
47
54
|
except (FileNotFoundError, TypeError):
|
|
48
55
|
return None
|
|
56
|
+
except version.InvalidVersion as e:
|
|
57
|
+
console.warn(
|
|
58
|
+
f"The detected version of {executable_path} ({e.args[0]}) is not valid. Defaulting to None."
|
|
59
|
+
)
|
|
60
|
+
return None
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
@once
|
|
64
|
+
def get_node_version() -> version.Version | None:
|
|
65
|
+
"""Get the version of node.
|
|
66
|
+
|
|
67
|
+
Returns:
|
|
68
|
+
The version of node.
|
|
69
|
+
"""
|
|
70
|
+
return _get_version_of_executable(path_ops.get_node_path())
|
|
49
71
|
|
|
50
72
|
|
|
51
73
|
def get_bun_version(bun_path: Path | None = None) -> version.Version | None:
|
|
@@ -57,20 +79,7 @@ def get_bun_version(bun_path: Path | None = None) -> version.Version | None:
|
|
|
57
79
|
Returns:
|
|
58
80
|
The version of bun.
|
|
59
81
|
"""
|
|
60
|
-
|
|
61
|
-
if bun_path is None:
|
|
62
|
-
return None
|
|
63
|
-
try:
|
|
64
|
-
# Run the bun -v command and capture the output
|
|
65
|
-
result = processes.new_process([str(bun_path), "-v"], run=True)
|
|
66
|
-
return version.parse(str(result.stdout))
|
|
67
|
-
except FileNotFoundError:
|
|
68
|
-
return None
|
|
69
|
-
except version.InvalidVersion as e:
|
|
70
|
-
console.warn(
|
|
71
|
-
f"The detected bun version ({e.args[0]}) is not valid. Defaulting to None."
|
|
72
|
-
)
|
|
73
|
-
return None
|
|
82
|
+
return _get_version_of_executable(bun_path or path_ops.get_bun_path())
|
|
74
83
|
|
|
75
84
|
|
|
76
85
|
def npm_escape_hatch() -> bool:
|
|
@@ -193,7 +202,7 @@ def download_and_run(url: str, *args, show_status: bool = False, **env):
|
|
|
193
202
|
env: The environment variables to use.
|
|
194
203
|
|
|
195
204
|
Raises:
|
|
196
|
-
|
|
205
|
+
SystemExit: If the script fails to download.
|
|
197
206
|
"""
|
|
198
207
|
import httpx
|
|
199
208
|
|
|
@@ -206,7 +215,7 @@ def download_and_run(url: str, *args, show_status: bool = False, **env):
|
|
|
206
215
|
console.error(
|
|
207
216
|
f"Failed to download bun install script. You can install or update bun manually from https://bun.com \n{e}"
|
|
208
217
|
)
|
|
209
|
-
raise
|
|
218
|
+
raise SystemExit(1) from None
|
|
210
219
|
|
|
211
220
|
# Save the script to a temporary file.
|
|
212
221
|
with tempfile.NamedTemporaryFile() as tempfile_file:
|
|
@@ -226,7 +235,7 @@ def install_bun():
|
|
|
226
235
|
|
|
227
236
|
Raises:
|
|
228
237
|
SystemPackageMissingError: If "unzip" is missing.
|
|
229
|
-
|
|
238
|
+
SystemExit: If REFLEX_USE_NPM is set but Node.js is not installed.
|
|
230
239
|
"""
|
|
231
240
|
if npm_escape_hatch():
|
|
232
241
|
if get_node_version() is not None:
|
|
@@ -237,7 +246,7 @@ def install_bun():
|
|
|
237
246
|
console.error(
|
|
238
247
|
"REFLEX_USE_NPM is set, but Node.js is not installed. Please install Node.js to use npm."
|
|
239
248
|
)
|
|
240
|
-
raise
|
|
249
|
+
raise SystemExit(1)
|
|
241
250
|
|
|
242
251
|
bun_path = path_ops.get_bun_path()
|
|
243
252
|
|
|
@@ -290,7 +299,7 @@ def validate_bun(bun_path: Path | None = None):
|
|
|
290
299
|
bun_path: The path to the bun executable. If None, the default bun path is used.
|
|
291
300
|
|
|
292
301
|
Raises:
|
|
293
|
-
|
|
302
|
+
SystemExit: If custom specified bun does not exist or does not meet requirements.
|
|
294
303
|
"""
|
|
295
304
|
bun_path = bun_path or path_ops.get_bun_path()
|
|
296
305
|
|
|
@@ -304,7 +313,7 @@ def validate_bun(bun_path: Path | None = None):
|
|
|
304
313
|
console.error(
|
|
305
314
|
"Failed to obtain bun version. Make sure the specified bun path in your config is correct."
|
|
306
315
|
)
|
|
307
|
-
raise
|
|
316
|
+
raise SystemExit(1)
|
|
308
317
|
if bun_version < version.parse(constants.Bun.MIN_VERSION):
|
|
309
318
|
console.warn(
|
|
310
319
|
f"Reflex requires bun version {constants.Bun.MIN_VERSION} or higher to run, but the detected version is "
|
|
@@ -320,20 +329,21 @@ def validate_frontend_dependencies(init: bool = True):
|
|
|
320
329
|
init: whether running `reflex init`
|
|
321
330
|
|
|
322
331
|
Raises:
|
|
323
|
-
|
|
332
|
+
SystemExit: If the package manager is invalid.
|
|
324
333
|
"""
|
|
325
334
|
if not init:
|
|
326
335
|
try:
|
|
327
336
|
get_js_package_executor(raise_on_none=True)
|
|
328
337
|
except FileNotFoundError as e:
|
|
329
|
-
|
|
338
|
+
console.error(f"Failed to find a valid package manager due to {e}.")
|
|
339
|
+
raise SystemExit(1) from None
|
|
330
340
|
|
|
331
341
|
if prefer_npm_over_bun() and not check_node_version():
|
|
332
342
|
node_version = get_node_version()
|
|
333
343
|
console.error(
|
|
334
344
|
f"Reflex requires node version {constants.Node.MIN_VERSION} or higher to run, but the detected version is {node_version}",
|
|
335
345
|
)
|
|
336
|
-
raise
|
|
346
|
+
raise SystemExit(1)
|
|
337
347
|
|
|
338
348
|
|
|
339
349
|
def remove_existing_bun_installation():
|
reflex/utils/prerequisites.py
CHANGED
|
@@ -15,7 +15,6 @@ from pathlib import Path
|
|
|
15
15
|
from types import ModuleType
|
|
16
16
|
from typing import NamedTuple
|
|
17
17
|
|
|
18
|
-
import click
|
|
19
18
|
from alembic.util.exc import CommandError
|
|
20
19
|
from packaging import version
|
|
21
20
|
from redis import Redis as RedisSync
|
|
@@ -444,7 +443,7 @@ def validate_app_name(app_name: str | None = None) -> str:
|
|
|
444
443
|
The app name after validation.
|
|
445
444
|
|
|
446
445
|
Raises:
|
|
447
|
-
|
|
446
|
+
SystemExit: if the app directory name is reflex or if the name is not standard for a python package name.
|
|
448
447
|
"""
|
|
449
448
|
app_name = app_name if app_name else Path.cwd().name.replace("-", "_")
|
|
450
449
|
# Make sure the app is not named "reflex".
|
|
@@ -452,14 +451,14 @@ def validate_app_name(app_name: str | None = None) -> str:
|
|
|
452
451
|
console.error(
|
|
453
452
|
f"The app directory cannot be named [bold]{constants.Reflex.MODULE_NAME}[/bold]."
|
|
454
453
|
)
|
|
455
|
-
raise
|
|
454
|
+
raise SystemExit(1)
|
|
456
455
|
|
|
457
456
|
# Make sure the app name is standard for a python package name.
|
|
458
457
|
if not re.match(r"^[a-zA-Z][a-zA-Z0-9_]*$", app_name):
|
|
459
458
|
console.error(
|
|
460
459
|
"The app directory name must start with a letter and can contain letters, numbers, and underscores."
|
|
461
460
|
)
|
|
462
|
-
raise
|
|
461
|
+
raise SystemExit(1)
|
|
463
462
|
|
|
464
463
|
return app_name
|
|
465
464
|
|
|
@@ -499,13 +498,13 @@ def assert_in_reflex_dir():
|
|
|
499
498
|
"""Assert that the current working directory is the reflex directory.
|
|
500
499
|
|
|
501
500
|
Raises:
|
|
502
|
-
|
|
501
|
+
SystemExit: If the current working directory is not the reflex directory.
|
|
503
502
|
"""
|
|
504
503
|
if not constants.Config.FILE.exists():
|
|
505
504
|
console.error(
|
|
506
505
|
f"[cyan]{constants.Config.FILE}[/cyan] not found. Move to the root folder of your project, or run [bold]{constants.Reflex.MODULE_NAME} init[/bold] to start a new project."
|
|
507
506
|
)
|
|
508
|
-
raise
|
|
507
|
+
raise SystemExit(1)
|
|
509
508
|
|
|
510
509
|
|
|
511
510
|
def needs_reinit() -> bool:
|