reflex 0.6.8a1__py3-none-any.whl → 0.7.0a1__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/jinja/custom_components/pyproject.toml.jinja2 +1 -1
- reflex/.templates/jinja/web/pages/_app.js.jinja2 +7 -7
- reflex/.templates/jinja/web/pages/utils.js.jinja2 +2 -2
- reflex/.templates/web/components/reflex/radix_themes_color_mode_provider.js +1 -4
- reflex/.templates/web/utils/state.js +65 -36
- reflex/__init__.py +4 -17
- reflex/__init__.pyi +1 -2
- reflex/app.py +244 -115
- reflex/app_mixins/lifespan.py +9 -9
- reflex/app_mixins/middleware.py +6 -6
- reflex/app_module_for_backend.py +3 -7
- reflex/base.py +7 -7
- reflex/compiler/compiler.py +8 -0
- reflex/compiler/utils.py +35 -6
- reflex/components/base/bare.py +1 -1
- reflex/components/base/error_boundary.py +2 -1
- reflex/components/base/error_boundary.pyi +2 -1
- reflex/components/base/meta.py +2 -2
- reflex/components/base/strict_mode.py +10 -0
- reflex/components/base/strict_mode.pyi +57 -0
- reflex/components/component.py +38 -77
- reflex/components/core/banner.py +83 -4
- reflex/components/core/banner.pyi +86 -0
- reflex/components/core/breakpoints.py +3 -1
- reflex/components/core/client_side_routing.py +1 -1
- reflex/components/core/client_side_routing.pyi +1 -1
- reflex/components/core/cond.py +9 -10
- reflex/components/core/debounce.py +1 -1
- reflex/components/core/foreach.py +23 -3
- reflex/components/core/html.py +1 -1
- reflex/components/core/match.py +5 -5
- reflex/components/core/sticky.py +160 -0
- reflex/components/core/sticky.pyi +449 -0
- reflex/components/core/upload.py +2 -2
- reflex/components/datadisplay/code.py +5 -14
- reflex/components/datadisplay/dataeditor.py +7 -4
- reflex/components/datadisplay/logo.py +13 -8
- reflex/components/datadisplay/shiki_code_block.py +14 -9
- reflex/components/dynamic.py +22 -3
- reflex/components/el/constants/reflex.py +1 -1
- reflex/components/el/element.py +1 -1
- reflex/components/el/elements/forms.py +4 -4
- reflex/components/el/elements/forms.pyi +4 -4
- reflex/components/lucide/icon.py +46 -8
- reflex/components/lucide/icon.pyi +54 -0
- reflex/components/markdown/markdown.py +10 -8
- reflex/components/moment/moment.py +2 -2
- reflex/components/next/image.py +16 -4
- reflex/components/next/image.pyi +4 -2
- reflex/components/next/link.py +1 -1
- reflex/components/plotly/plotly.py +5 -5
- reflex/components/props.py +3 -3
- reflex/components/radix/__init__.pyi +1 -1
- reflex/components/radix/primitives/accordion.py +9 -5
- reflex/components/radix/primitives/accordion.pyi +3 -1
- reflex/components/radix/primitives/drawer.py +5 -2
- reflex/components/radix/primitives/drawer.pyi +4 -4
- reflex/components/radix/primitives/form.pyi +6 -6
- reflex/components/radix/primitives/progress.py +1 -1
- reflex/components/radix/primitives/slider.py +1 -1
- reflex/components/radix/themes/color_mode.py +11 -9
- reflex/components/radix/themes/components/alert_dialog.py +3 -0
- reflex/components/radix/themes/components/card.py +1 -1
- reflex/components/radix/themes/components/card.pyi +1 -1
- reflex/components/radix/themes/components/context_menu.py +5 -0
- reflex/components/radix/themes/components/dialog.py +3 -0
- reflex/components/radix/themes/components/dropdown_menu.py +5 -0
- reflex/components/radix/themes/components/hover_card.py +3 -0
- reflex/components/radix/themes/components/icon_button.py +2 -2
- reflex/components/radix/themes/components/icon_button.pyi +1 -0
- reflex/components/radix/themes/components/popover.py +3 -0
- reflex/components/radix/themes/components/radio_cards.py +2 -0
- reflex/components/radix/themes/components/radio_group.py +1 -1
- reflex/components/radix/themes/components/select.py +3 -0
- reflex/components/radix/themes/components/tabs.py +3 -0
- reflex/components/radix/themes/components/text_area.py +12 -0
- reflex/components/radix/themes/components/text_area.pyi +2 -0
- reflex/components/radix/themes/components/text_field.py +1 -1
- reflex/components/radix/themes/components/tooltip.py +3 -1
- reflex/components/radix/themes/components/tooltip.pyi +1 -0
- reflex/components/radix/themes/layout/__init__.pyi +1 -1
- reflex/components/radix/themes/layout/list.py +2 -2
- reflex/components/radix/themes/layout/stack.py +2 -2
- reflex/components/radix/themes/typography/link.py +1 -1
- reflex/components/radix/themes/typography/text.py +2 -2
- reflex/components/react_player/react_player.py +1 -1
- reflex/components/recharts/__init__.py +2 -0
- reflex/components/recharts/__init__.pyi +2 -0
- reflex/components/recharts/charts.py +15 -15
- reflex/components/recharts/general.py +19 -4
- reflex/components/recharts/general.pyi +55 -4
- reflex/components/recharts/polar.py +2 -2
- reflex/components/recharts/recharts.py +4 -4
- reflex/components/sonner/toast.py +15 -13
- reflex/components/sonner/toast.pyi +6 -6
- reflex/components/suneditor/editor.py +6 -4
- reflex/components/suneditor/editor.pyi +2 -2
- reflex/components/tags/iter_tag.py +3 -3
- reflex/components/tags/tag.py +25 -3
- reflex/config.py +48 -20
- reflex/constants/__init__.py +1 -0
- reflex/constants/base.py +4 -1
- reflex/constants/compiler.py +5 -2
- reflex/constants/config.py +8 -1
- reflex/constants/installer.py +9 -9
- reflex/constants/style.py +1 -1
- reflex/custom_components/custom_components.py +9 -7
- reflex/event.py +137 -163
- reflex/experimental/__init__.py +19 -11
- reflex/experimental/client_state.py +53 -28
- reflex/experimental/hooks.py +5 -5
- reflex/experimental/layout.py +8 -5
- reflex/experimental/layout.pyi +1 -1
- reflex/experimental/misc.py +3 -3
- reflex/istate/wrappers.py +1 -1
- reflex/middleware/hydrate_middleware.py +2 -2
- reflex/model.py +11 -6
- reflex/page.py +3 -3
- reflex/reflex.py +90 -19
- reflex/route.py +1 -1
- reflex/state.py +358 -401
- reflex/style.py +27 -3
- reflex/testing.py +34 -39
- reflex/utils/build.py +6 -2
- reflex/utils/codespaces.py +1 -4
- reflex/utils/compat.py +6 -5
- reflex/utils/console.py +52 -21
- reflex/utils/exceptions.py +76 -26
- reflex/utils/exec.py +69 -74
- reflex/utils/export.py +6 -1
- reflex/utils/format.py +7 -39
- reflex/utils/imports.py +2 -2
- reflex/utils/lazy_loader.py +7 -1
- reflex/utils/path_ops.py +28 -14
- reflex/utils/prerequisites.py +324 -65
- reflex/utils/processes.py +45 -32
- reflex/utils/pyi_generator.py +30 -25
- reflex/utils/registry.py +4 -4
- reflex/utils/serializers.py +1 -1
- reflex/utils/telemetry.py +5 -4
- reflex/utils/types.py +42 -18
- reflex/vars/base.py +650 -333
- reflex/vars/datetime.py +6 -7
- reflex/vars/dep_tracking.py +344 -0
- reflex/vars/function.py +11 -5
- reflex/vars/number.py +31 -43
- reflex/vars/object.py +63 -62
- reflex/vars/sequence.py +79 -67
- {reflex-0.6.8a1.dist-info → reflex-0.7.0a1.dist-info}/METADATA +7 -10
- {reflex-0.6.8a1.dist-info → reflex-0.7.0a1.dist-info}/RECORD +153 -150
- {reflex-0.6.8a1.dist-info → reflex-0.7.0a1.dist-info}/WHEEL +1 -1
- reflex/experimental/assets.py +0 -37
- reflex/proxy.py +0 -119
- {reflex-0.6.8a1.dist-info → reflex-0.7.0a1.dist-info}/LICENSE +0 -0
- {reflex-0.6.8a1.dist-info → reflex-0.7.0a1.dist-info}/entry_points.txt +0 -0
reflex/utils/exec.py
CHANGED
|
@@ -71,7 +71,9 @@ def notify_backend():
|
|
|
71
71
|
# run_process_and_launch_url is assumed to be used
|
|
72
72
|
# only to launch the frontend
|
|
73
73
|
# If this is not the case, might have to change the logic
|
|
74
|
-
def run_process_and_launch_url(
|
|
74
|
+
def run_process_and_launch_url(
|
|
75
|
+
run_command: list[str | None], backend_present: bool = True
|
|
76
|
+
):
|
|
75
77
|
"""Run the process and launch the URL.
|
|
76
78
|
|
|
77
79
|
Args:
|
|
@@ -89,7 +91,7 @@ def run_process_and_launch_url(run_command: list[str], backend_present=True):
|
|
|
89
91
|
if process is None:
|
|
90
92
|
kwargs = {}
|
|
91
93
|
if constants.IS_WINDOWS and backend_present:
|
|
92
|
-
kwargs["creationflags"] = subprocess.CREATE_NEW_PROCESS_GROUP #
|
|
94
|
+
kwargs["creationflags"] = subprocess.CREATE_NEW_PROCESS_GROUP # pyright: ignore [reportAttributeAccessIssue]
|
|
93
95
|
process = processes.new_process(
|
|
94
96
|
run_command,
|
|
95
97
|
cwd=get_web_dir(),
|
|
@@ -134,7 +136,7 @@ def run_process_and_launch_url(run_command: list[str], backend_present=True):
|
|
|
134
136
|
break # while True
|
|
135
137
|
|
|
136
138
|
|
|
137
|
-
def run_frontend(root: Path, port: str, backend_present=True):
|
|
139
|
+
def run_frontend(root: Path, port: str, backend_present: bool = True):
|
|
138
140
|
"""Run the frontend.
|
|
139
141
|
|
|
140
142
|
Args:
|
|
@@ -151,12 +153,12 @@ def run_frontend(root: Path, port: str, backend_present=True):
|
|
|
151
153
|
console.rule("[bold green]App Running")
|
|
152
154
|
os.environ["PORT"] = str(get_config().frontend_port if port is None else port)
|
|
153
155
|
run_process_and_launch_url(
|
|
154
|
-
[prerequisites.get_package_manager(), "run", "dev"],
|
|
156
|
+
[prerequisites.get_package_manager(), "run", "dev"],
|
|
155
157
|
backend_present,
|
|
156
158
|
)
|
|
157
159
|
|
|
158
160
|
|
|
159
|
-
def run_frontend_prod(root: Path, port: str, backend_present=True):
|
|
161
|
+
def run_frontend_prod(root: Path, port: str, backend_present: bool = True):
|
|
160
162
|
"""Run the frontend.
|
|
161
163
|
|
|
162
164
|
Args:
|
|
@@ -173,7 +175,7 @@ def run_frontend_prod(root: Path, port: str, backend_present=True):
|
|
|
173
175
|
# Run the frontend in production mode.
|
|
174
176
|
console.rule("[bold green]App Running")
|
|
175
177
|
run_process_and_launch_url(
|
|
176
|
-
[prerequisites.get_package_manager(), "run", "prod"],
|
|
178
|
+
[prerequisites.get_package_manager(), "run", "prod"],
|
|
177
179
|
backend_present,
|
|
178
180
|
)
|
|
179
181
|
|
|
@@ -240,7 +242,32 @@ def run_backend(
|
|
|
240
242
|
run_uvicorn_backend(host, port, loglevel)
|
|
241
243
|
|
|
242
244
|
|
|
243
|
-
def
|
|
245
|
+
def get_reload_dirs() -> list[Path]:
|
|
246
|
+
"""Get the reload directories for the backend.
|
|
247
|
+
|
|
248
|
+
Returns:
|
|
249
|
+
The reload directories for the backend.
|
|
250
|
+
"""
|
|
251
|
+
config = get_config()
|
|
252
|
+
reload_dirs = [Path(config.app_name)]
|
|
253
|
+
if config.app_module is not None and config.app_module.__file__:
|
|
254
|
+
module_path = Path(config.app_module.__file__).resolve().parent
|
|
255
|
+
|
|
256
|
+
while module_path.parent.name:
|
|
257
|
+
if any(
|
|
258
|
+
sibling_file.name == "__init__.py"
|
|
259
|
+
for sibling_file in module_path.parent.iterdir()
|
|
260
|
+
):
|
|
261
|
+
# go up a level to find dir without `__init__.py`
|
|
262
|
+
module_path = module_path.parent
|
|
263
|
+
else:
|
|
264
|
+
break
|
|
265
|
+
|
|
266
|
+
reload_dirs = [module_path]
|
|
267
|
+
return reload_dirs
|
|
268
|
+
|
|
269
|
+
|
|
270
|
+
def run_uvicorn_backend(host: str, port: int, loglevel: LogLevel):
|
|
244
271
|
"""Run the backend in development mode using Uvicorn.
|
|
245
272
|
|
|
246
273
|
Args:
|
|
@@ -256,11 +283,11 @@ def run_uvicorn_backend(host, port, loglevel: LogLevel):
|
|
|
256
283
|
port=port,
|
|
257
284
|
log_level=loglevel.value,
|
|
258
285
|
reload=True,
|
|
259
|
-
reload_dirs=
|
|
286
|
+
reload_dirs=list(map(str, get_reload_dirs())),
|
|
260
287
|
)
|
|
261
288
|
|
|
262
289
|
|
|
263
|
-
def run_granian_backend(host, port, loglevel: LogLevel):
|
|
290
|
+
def run_granian_backend(host: str, port: int, loglevel: LogLevel):
|
|
264
291
|
"""Run the backend in development mode using Granian.
|
|
265
292
|
|
|
266
293
|
Args:
|
|
@@ -270,9 +297,11 @@ def run_granian_backend(host, port, loglevel: LogLevel):
|
|
|
270
297
|
"""
|
|
271
298
|
console.debug("Using Granian for backend")
|
|
272
299
|
try:
|
|
273
|
-
from granian import Granian #
|
|
274
|
-
from granian.constants import
|
|
275
|
-
|
|
300
|
+
from granian import Granian # pyright: ignore [reportMissingImports]
|
|
301
|
+
from granian.constants import ( # pyright: ignore [reportMissingImports]
|
|
302
|
+
Interfaces,
|
|
303
|
+
)
|
|
304
|
+
from granian.log import LogLevels # pyright: ignore [reportMissingImports]
|
|
276
305
|
|
|
277
306
|
Granian(
|
|
278
307
|
target=get_granian_target(),
|
|
@@ -281,8 +310,8 @@ def run_granian_backend(host, port, loglevel: LogLevel):
|
|
|
281
310
|
interface=Interfaces.ASGI,
|
|
282
311
|
log_level=LogLevels(loglevel.value),
|
|
283
312
|
reload=True,
|
|
284
|
-
reload_paths=
|
|
285
|
-
reload_ignore_dirs=[".web"],
|
|
313
|
+
reload_paths=get_reload_dirs(),
|
|
314
|
+
reload_ignore_dirs=[".web", ".states"],
|
|
286
315
|
).serve()
|
|
287
316
|
except ImportError:
|
|
288
317
|
console.error(
|
|
@@ -325,7 +354,7 @@ def run_backend_prod(
|
|
|
325
354
|
run_uvicorn_backend_prod(host, port, loglevel)
|
|
326
355
|
|
|
327
356
|
|
|
328
|
-
def run_uvicorn_backend_prod(host, port, loglevel):
|
|
357
|
+
def run_uvicorn_backend_prod(host: str, port: int, loglevel: LogLevel):
|
|
329
358
|
"""Run the backend in production mode using Uvicorn.
|
|
330
359
|
|
|
331
360
|
Args:
|
|
@@ -339,11 +368,11 @@ def run_uvicorn_backend_prod(host, port, loglevel):
|
|
|
339
368
|
|
|
340
369
|
app_module = get_app_module()
|
|
341
370
|
|
|
342
|
-
|
|
343
|
-
|
|
371
|
+
run_backend_prod = f"gunicorn --worker-class {config.gunicorn_worker_class} --max-requests {config.gunicorn_max_requests} --max-requests-jitter {config.gunicorn_max_requests_jitter} --preload --timeout {config.timeout} --log-level critical".split()
|
|
372
|
+
run_backend_prod_windows = f"uvicorn --limit-max-requests {config.gunicorn_max_requests} --timeout-keep-alive {config.timeout}".split()
|
|
344
373
|
command = (
|
|
345
374
|
[
|
|
346
|
-
*
|
|
375
|
+
*run_backend_prod_windows,
|
|
347
376
|
"--host",
|
|
348
377
|
host,
|
|
349
378
|
"--port",
|
|
@@ -352,7 +381,7 @@ def run_uvicorn_backend_prod(host, port, loglevel):
|
|
|
352
381
|
]
|
|
353
382
|
if constants.IS_WINDOWS
|
|
354
383
|
else [
|
|
355
|
-
*
|
|
384
|
+
*run_backend_prod,
|
|
356
385
|
"--bind",
|
|
357
386
|
f"{host}:{port}",
|
|
358
387
|
"--threads",
|
|
@@ -377,7 +406,7 @@ def run_uvicorn_backend_prod(host, port, loglevel):
|
|
|
377
406
|
)
|
|
378
407
|
|
|
379
408
|
|
|
380
|
-
def run_granian_backend_prod(host, port, loglevel):
|
|
409
|
+
def run_granian_backend_prod(host: str, port: int, loglevel: LogLevel):
|
|
381
410
|
"""Run the backend in production mode using Granian.
|
|
382
411
|
|
|
383
412
|
Args:
|
|
@@ -388,7 +417,9 @@ def run_granian_backend_prod(host, port, loglevel):
|
|
|
388
417
|
from reflex.utils import processes
|
|
389
418
|
|
|
390
419
|
try:
|
|
391
|
-
from granian.constants import
|
|
420
|
+
from granian.constants import ( # pyright: ignore [reportMissingImports]
|
|
421
|
+
Interfaces,
|
|
422
|
+
)
|
|
392
423
|
|
|
393
424
|
command = [
|
|
394
425
|
"granian",
|
|
@@ -442,22 +473,22 @@ def output_system_info():
|
|
|
442
473
|
|
|
443
474
|
system = platform.system()
|
|
444
475
|
|
|
476
|
+
fnm_info = f"[FNM {prerequisites.get_fnm_version()} (Expected: {constants.Fnm.VERSION}) (PATH: {constants.Fnm.EXE})]"
|
|
477
|
+
|
|
445
478
|
if system != "Windows" or (
|
|
446
479
|
system == "Windows" and prerequisites.is_windows_bun_supported()
|
|
447
480
|
):
|
|
448
481
|
dependencies.extend(
|
|
449
482
|
[
|
|
450
|
-
|
|
451
|
-
f"[Bun {prerequisites.get_bun_version()} (Expected: {constants.Bun.VERSION}) (PATH: {
|
|
483
|
+
fnm_info,
|
|
484
|
+
f"[Bun {prerequisites.get_bun_version()} (Expected: {constants.Bun.VERSION}) (PATH: {path_ops.get_bun_path()})]",
|
|
452
485
|
],
|
|
453
486
|
)
|
|
454
487
|
else:
|
|
455
|
-
dependencies.append(
|
|
456
|
-
f"[FNM {prerequisites.get_fnm_version()} (Expected: {constants.Fnm.VERSION}) (PATH: {constants.Fnm.EXE})]",
|
|
457
|
-
)
|
|
488
|
+
dependencies.append(fnm_info)
|
|
458
489
|
|
|
459
490
|
if system == "Linux":
|
|
460
|
-
import distro #
|
|
491
|
+
import distro # pyright: ignore[reportMissingImports]
|
|
461
492
|
|
|
462
493
|
os_version = distro.name(pretty=True)
|
|
463
494
|
else:
|
|
@@ -469,11 +500,11 @@ def output_system_info():
|
|
|
469
500
|
console.debug(f"{dep}")
|
|
470
501
|
|
|
471
502
|
console.debug(
|
|
472
|
-
f"Using package installer at: {prerequisites.get_install_package_manager(on_failure_return_none=True)}"
|
|
503
|
+
f"Using package installer at: {prerequisites.get_install_package_manager(on_failure_return_none=True)}"
|
|
473
504
|
)
|
|
474
505
|
console.debug(
|
|
475
506
|
f"Using package executer at: {prerequisites.get_package_manager(on_failure_return_none=True)}"
|
|
476
|
-
)
|
|
507
|
+
)
|
|
477
508
|
if system != "Windows":
|
|
478
509
|
console.debug(f"Unzip path: {path_ops.which('unzip')}")
|
|
479
510
|
|
|
@@ -487,56 +518,20 @@ def is_testing_env() -> bool:
|
|
|
487
518
|
return constants.PYTEST_CURRENT_TEST in os.environ
|
|
488
519
|
|
|
489
520
|
|
|
490
|
-
def
|
|
491
|
-
"""
|
|
521
|
+
def is_in_app_harness() -> bool:
|
|
522
|
+
"""Whether the app is running in the app harness.
|
|
492
523
|
|
|
493
524
|
Returns:
|
|
494
|
-
True if the app is running in
|
|
525
|
+
True if the app is running in the app harness.
|
|
495
526
|
"""
|
|
496
|
-
|
|
497
|
-
return current_mode == constants.Env.PROD
|
|
527
|
+
return constants.APP_HARNESS_FLAG in os.environ
|
|
498
528
|
|
|
499
529
|
|
|
500
|
-
def
|
|
501
|
-
"""Check if the app is running in
|
|
502
|
-
|
|
503
|
-
Returns:
|
|
504
|
-
True if the app is running in frontend-only mode.
|
|
505
|
-
"""
|
|
506
|
-
console.deprecate(
|
|
507
|
-
"is_frontend_only() is deprecated and will be removed in a future release.",
|
|
508
|
-
reason="Use `environment.REFLEX_FRONTEND_ONLY.get()` instead.",
|
|
509
|
-
deprecation_version="0.6.5",
|
|
510
|
-
removal_version="0.7.0",
|
|
511
|
-
)
|
|
512
|
-
return environment.REFLEX_FRONTEND_ONLY.get()
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
def is_backend_only() -> bool:
|
|
516
|
-
"""Check if the app is running in backend-only mode.
|
|
517
|
-
|
|
518
|
-
Returns:
|
|
519
|
-
True if the app is running in backend-only mode.
|
|
520
|
-
"""
|
|
521
|
-
console.deprecate(
|
|
522
|
-
"is_backend_only() is deprecated and will be removed in a future release.",
|
|
523
|
-
reason="Use `environment.REFLEX_BACKEND_ONLY.get()` instead.",
|
|
524
|
-
deprecation_version="0.6.5",
|
|
525
|
-
removal_version="0.7.0",
|
|
526
|
-
)
|
|
527
|
-
return environment.REFLEX_BACKEND_ONLY.get()
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
def should_skip_compile() -> bool:
|
|
531
|
-
"""Whether the app should skip compile.
|
|
530
|
+
def is_prod_mode() -> bool:
|
|
531
|
+
"""Check if the app is running in production mode.
|
|
532
532
|
|
|
533
533
|
Returns:
|
|
534
|
-
True if the app
|
|
534
|
+
True if the app is running in production mode or False if running in dev mode.
|
|
535
535
|
"""
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
reason="Use `environment.REFLEX_SKIP_COMPILE.get()` instead.",
|
|
539
|
-
deprecation_version="0.6.5",
|
|
540
|
-
removal_version="0.7.0",
|
|
541
|
-
)
|
|
542
|
-
return environment.REFLEX_SKIP_COMPILE.get()
|
|
536
|
+
current_mode = environment.REFLEX_ENV_MODE.get()
|
|
537
|
+
return current_mode == constants.Env.PROD
|
reflex/utils/export.py
CHANGED
|
@@ -4,7 +4,7 @@ from pathlib import Path
|
|
|
4
4
|
from typing import Optional
|
|
5
5
|
|
|
6
6
|
from reflex import constants
|
|
7
|
-
from reflex.config import get_config
|
|
7
|
+
from reflex.config import environment, get_config
|
|
8
8
|
from reflex.utils import build, console, exec, prerequisites, telemetry
|
|
9
9
|
|
|
10
10
|
config = get_config()
|
|
@@ -18,6 +18,7 @@ def export(
|
|
|
18
18
|
upload_db_file: bool = False,
|
|
19
19
|
api_url: Optional[str] = None,
|
|
20
20
|
deploy_url: Optional[str] = None,
|
|
21
|
+
env: constants.Env = constants.Env.PROD,
|
|
21
22
|
loglevel: constants.LogLevel = console._LOG_LEVEL,
|
|
22
23
|
):
|
|
23
24
|
"""Export the app to a zip file.
|
|
@@ -30,11 +31,15 @@ def export(
|
|
|
30
31
|
upload_db_file: Whether to upload the database file. Defaults to False.
|
|
31
32
|
api_url: The API URL to use. Defaults to None.
|
|
32
33
|
deploy_url: The deploy URL to use. Defaults to None.
|
|
34
|
+
env: The environment to use. Defaults to constants.Env.PROD.
|
|
33
35
|
loglevel: The log level to use. Defaults to console._LOG_LEVEL.
|
|
34
36
|
"""
|
|
35
37
|
# Set the log level.
|
|
36
38
|
console.set_log_level(loglevel)
|
|
37
39
|
|
|
40
|
+
# Set env mode in the environment
|
|
41
|
+
environment.REFLEX_ENV_MODE.set(env)
|
|
42
|
+
|
|
38
43
|
# Override the config url values if provided.
|
|
39
44
|
if api_url is not None:
|
|
40
45
|
config.api_url = str(api_url)
|
reflex/utils/format.py
CHANGED
|
@@ -11,7 +11,6 @@ from typing import TYPE_CHECKING, Any, List, Optional, Union
|
|
|
11
11
|
from reflex import constants
|
|
12
12
|
from reflex.constants.state import FRONTEND_EVENT_STATE
|
|
13
13
|
from reflex.utils import exceptions
|
|
14
|
-
from reflex.utils.console import deprecate
|
|
15
14
|
|
|
16
15
|
if TYPE_CHECKING:
|
|
17
16
|
from reflex.components.component import ComponentStyle
|
|
@@ -221,7 +220,7 @@ def _escape_js_string(string: str) -> str:
|
|
|
221
220
|
"""
|
|
222
221
|
|
|
223
222
|
# TODO: we may need to re-vist this logic after new Var API is implemented.
|
|
224
|
-
def escape_outside_segments(segment):
|
|
223
|
+
def escape_outside_segments(segment: str):
|
|
225
224
|
"""Escape backticks in segments outside of `${}`.
|
|
226
225
|
|
|
227
226
|
Args:
|
|
@@ -284,7 +283,7 @@ def format_var(var: Var) -> str:
|
|
|
284
283
|
return str(var)
|
|
285
284
|
|
|
286
285
|
|
|
287
|
-
def format_route(route: str, format_case=True) -> str:
|
|
286
|
+
def format_route(route: str, format_case: bool = True) -> str:
|
|
288
287
|
"""Format the given route.
|
|
289
288
|
|
|
290
289
|
Args:
|
|
@@ -378,7 +377,7 @@ def format_prop(
|
|
|
378
377
|
|
|
379
378
|
# For dictionaries, convert any properties to strings.
|
|
380
379
|
elif isinstance(prop, dict):
|
|
381
|
-
prop = serializers.serialize_dict(prop) #
|
|
380
|
+
prop = serializers.serialize_dict(prop) # pyright: ignore [reportAttributeAccessIssue]
|
|
382
381
|
|
|
383
382
|
else:
|
|
384
383
|
# Dump the prop as JSON.
|
|
@@ -502,37 +501,6 @@ if TYPE_CHECKING:
|
|
|
502
501
|
from reflex.vars import Var
|
|
503
502
|
|
|
504
503
|
|
|
505
|
-
def format_event_chain(
|
|
506
|
-
event_chain: EventChain | Var[EventChain],
|
|
507
|
-
event_arg: Var | None = None,
|
|
508
|
-
) -> str:
|
|
509
|
-
"""DEPRECATED: format an event chain as a javascript invocation.
|
|
510
|
-
|
|
511
|
-
Use str(rx.Var.create(event_chain)) instead.
|
|
512
|
-
|
|
513
|
-
Args:
|
|
514
|
-
event_chain: The event chain to format.
|
|
515
|
-
event_arg: this argument is ignored.
|
|
516
|
-
|
|
517
|
-
Returns:
|
|
518
|
-
Compiled javascript code to queue the given event chain on the frontend.
|
|
519
|
-
"""
|
|
520
|
-
deprecate(
|
|
521
|
-
feature_name="format_event_chain",
|
|
522
|
-
reason="Use str(rx.Var.create(event_chain)) instead",
|
|
523
|
-
deprecation_version="0.6.0",
|
|
524
|
-
removal_version="0.7.0",
|
|
525
|
-
)
|
|
526
|
-
|
|
527
|
-
from reflex.vars import Var
|
|
528
|
-
from reflex.vars.function import ArgsFunctionOperation
|
|
529
|
-
|
|
530
|
-
result = Var.create(event_chain)
|
|
531
|
-
if isinstance(result, ArgsFunctionOperation):
|
|
532
|
-
result = result._return_expr
|
|
533
|
-
return str(result)
|
|
534
|
-
|
|
535
|
-
|
|
536
504
|
def format_queue_events(
|
|
537
505
|
events: EventType | None = None,
|
|
538
506
|
args_spec: Optional[ArgsSpec] = None,
|
|
@@ -565,14 +533,14 @@ def format_queue_events(
|
|
|
565
533
|
from reflex.vars import FunctionVar, Var
|
|
566
534
|
|
|
567
535
|
if not events:
|
|
568
|
-
return Var("(() => null)").to(FunctionVar, EventChain)
|
|
536
|
+
return Var("(() => null)").to(FunctionVar, EventChain)
|
|
569
537
|
|
|
570
538
|
# If no spec is provided, the function will take no arguments.
|
|
571
539
|
def _default_args_spec():
|
|
572
540
|
return []
|
|
573
541
|
|
|
574
542
|
# Construct the arguments that the function accepts.
|
|
575
|
-
sig = inspect.signature(args_spec or _default_args_spec)
|
|
543
|
+
sig = inspect.signature(args_spec or _default_args_spec)
|
|
576
544
|
if sig.parameters:
|
|
577
545
|
arg_def = ",".join(f"_{p}" for p in sig.parameters)
|
|
578
546
|
arg_def = f"({arg_def})"
|
|
@@ -589,7 +557,7 @@ def format_queue_events(
|
|
|
589
557
|
if isinstance(spec, (EventHandler, EventSpec)):
|
|
590
558
|
specs = [call_event_handler(spec, args_spec or _default_args_spec)]
|
|
591
559
|
elif isinstance(spec, type(lambda: None)):
|
|
592
|
-
specs = call_event_fn(spec, args_spec or _default_args_spec) #
|
|
560
|
+
specs = call_event_fn(spec, args_spec or _default_args_spec) # pyright: ignore [reportAssignmentType, reportArgumentType]
|
|
593
561
|
if isinstance(specs, Var):
|
|
594
562
|
raise ValueError(
|
|
595
563
|
f"Invalid event spec: {specs}. Expected a list of EventSpecs."
|
|
@@ -601,7 +569,7 @@ def format_queue_events(
|
|
|
601
569
|
return Var(
|
|
602
570
|
f"{arg_def} => {{queueEvents([{','.join(payloads)}], {constants.CompileVars.SOCKET}); "
|
|
603
571
|
f"processEvent({constants.CompileVars.SOCKET})}}",
|
|
604
|
-
).to(FunctionVar, EventChain)
|
|
572
|
+
).to(FunctionVar, EventChain)
|
|
605
573
|
|
|
606
574
|
|
|
607
575
|
def format_query_params(router_data: dict[str, Any]) -> dict[str, str]:
|
reflex/utils/imports.py
CHANGED
|
@@ -90,7 +90,7 @@ def collapse_imports(
|
|
|
90
90
|
}
|
|
91
91
|
|
|
92
92
|
|
|
93
|
-
@dataclasses.dataclass(
|
|
93
|
+
@dataclasses.dataclass(frozen=True)
|
|
94
94
|
class ImportVar:
|
|
95
95
|
"""An import var."""
|
|
96
96
|
|
|
@@ -122,7 +122,7 @@ class ImportVar:
|
|
|
122
122
|
"""
|
|
123
123
|
if self.alias:
|
|
124
124
|
return (
|
|
125
|
-
self.alias if self.is_default else " as ".join([self.tag, self.alias]) #
|
|
125
|
+
self.alias if self.is_default else " as ".join([self.tag, self.alias]) # pyright: ignore [reportCallIssue,reportArgumentType]
|
|
126
126
|
)
|
|
127
127
|
else:
|
|
128
128
|
return self.tag or ""
|
reflex/utils/lazy_loader.py
CHANGED
|
@@ -1,11 +1,17 @@
|
|
|
1
1
|
"""Module to implement lazy loading in reflex."""
|
|
2
2
|
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
3
5
|
import copy
|
|
4
6
|
|
|
5
7
|
import lazy_loader as lazy
|
|
6
8
|
|
|
7
9
|
|
|
8
|
-
def attach(
|
|
10
|
+
def attach(
|
|
11
|
+
package_name: str,
|
|
12
|
+
submodules: set | None = None,
|
|
13
|
+
submod_attrs: dict | None = None,
|
|
14
|
+
):
|
|
9
15
|
"""Replaces a package's __getattr__, __dir__, and __all__ attributes using lazy.attach.
|
|
10
16
|
The lazy loader __getattr__ doesn't support tuples as list values. We needed to add
|
|
11
17
|
this functionality (tuples) in Reflex to support 'import as _' statements. This function
|
reflex/utils/path_ops.py
CHANGED
|
@@ -9,7 +9,7 @@ import shutil
|
|
|
9
9
|
from pathlib import Path
|
|
10
10
|
|
|
11
11
|
from reflex import constants
|
|
12
|
-
from reflex.config import environment
|
|
12
|
+
from reflex.config import environment, get_config
|
|
13
13
|
|
|
14
14
|
# Shorthand for join.
|
|
15
15
|
join = os.linesep.join
|
|
@@ -118,7 +118,7 @@ def ln(src: str | Path, dest: str | Path, overwrite: bool = False) -> bool:
|
|
|
118
118
|
return True
|
|
119
119
|
|
|
120
120
|
|
|
121
|
-
def which(program: str | Path) ->
|
|
121
|
+
def which(program: str | Path) -> Path | None:
|
|
122
122
|
"""Find the path to an executable.
|
|
123
123
|
|
|
124
124
|
Args:
|
|
@@ -127,7 +127,8 @@ def which(program: str | Path) -> str | Path | None:
|
|
|
127
127
|
Returns:
|
|
128
128
|
The path to the executable.
|
|
129
129
|
"""
|
|
130
|
-
|
|
130
|
+
which_result = shutil.which(program)
|
|
131
|
+
return Path(which_result) if which_result else None
|
|
131
132
|
|
|
132
133
|
|
|
133
134
|
def use_system_node() -> bool:
|
|
@@ -156,12 +157,12 @@ def get_node_bin_path() -> Path | None:
|
|
|
156
157
|
"""
|
|
157
158
|
bin_path = Path(constants.Node.BIN_PATH)
|
|
158
159
|
if not bin_path.exists():
|
|
159
|
-
|
|
160
|
-
return
|
|
161
|
-
return bin_path.
|
|
160
|
+
path = which("node")
|
|
161
|
+
return path.parent.absolute() if path else None
|
|
162
|
+
return bin_path.absolute()
|
|
162
163
|
|
|
163
164
|
|
|
164
|
-
def get_node_path() ->
|
|
165
|
+
def get_node_path() -> Path | None:
|
|
165
166
|
"""Get the node binary path.
|
|
166
167
|
|
|
167
168
|
Returns:
|
|
@@ -169,12 +170,11 @@ def get_node_path() -> str | None:
|
|
|
169
170
|
"""
|
|
170
171
|
node_path = Path(constants.Node.PATH)
|
|
171
172
|
if use_system_node() or not node_path.exists():
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
return str(node_path)
|
|
173
|
+
node_path = which("node")
|
|
174
|
+
return node_path
|
|
175
175
|
|
|
176
176
|
|
|
177
|
-
def get_npm_path() ->
|
|
177
|
+
def get_npm_path() -> Path | None:
|
|
178
178
|
"""Get npm binary path.
|
|
179
179
|
|
|
180
180
|
Returns:
|
|
@@ -182,9 +182,20 @@ def get_npm_path() -> str | None:
|
|
|
182
182
|
"""
|
|
183
183
|
npm_path = Path(constants.Node.NPM_PATH)
|
|
184
184
|
if use_system_node() or not npm_path.exists():
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
185
|
+
npm_path = which("npm")
|
|
186
|
+
return npm_path.absolute() if npm_path else None
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
def get_bun_path() -> Path | None:
|
|
190
|
+
"""Get bun binary path.
|
|
191
|
+
|
|
192
|
+
Returns:
|
|
193
|
+
The path to the bun binary file.
|
|
194
|
+
"""
|
|
195
|
+
bun_path = get_config().bun_path
|
|
196
|
+
if use_system_bun() or not bun_path.exists():
|
|
197
|
+
bun_path = which("bun")
|
|
198
|
+
return bun_path.absolute() if bun_path else None
|
|
188
199
|
|
|
189
200
|
|
|
190
201
|
def update_json_file(file_path: str | Path, update_dict: dict[str, int | str]):
|
|
@@ -196,6 +207,9 @@ def update_json_file(file_path: str | Path, update_dict: dict[str, int | str]):
|
|
|
196
207
|
"""
|
|
197
208
|
fp = Path(file_path)
|
|
198
209
|
|
|
210
|
+
# Create the parent directory if it doesn't exist.
|
|
211
|
+
fp.parent.mkdir(parents=True, exist_ok=True)
|
|
212
|
+
|
|
199
213
|
# Create the file if it doesn't exist.
|
|
200
214
|
fp.touch(exist_ok=True)
|
|
201
215
|
|