reflex 0.7.14a6__py3-none-any.whl → 0.8.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/app/rxconfig.py.jinja2 +4 -1
- reflex/.templates/jinja/web/package.json.jinja2 +1 -1
- reflex/.templates/jinja/web/pages/_app.js.jinja2 +16 -10
- reflex/.templates/jinja/web/pages/_document.js.jinja2 +1 -1
- reflex/.templates/jinja/web/pages/base_page.js.jinja2 +0 -1
- reflex/.templates/jinja/web/utils/context.js.jinja2 +25 -6
- reflex/.templates/web/app/entry.client.js +8 -0
- reflex/.templates/web/app/routes.js +10 -0
- reflex/.templates/web/components/reflex/radix_themes_color_mode_provider.js +12 -32
- reflex/.templates/web/postcss.config.js +1 -1
- reflex/.templates/web/react-router.config.js +6 -0
- reflex/.templates/web/utils/client_side_routing.js +21 -19
- reflex/.templates/web/utils/react-theme.js +89 -0
- reflex/.templates/web/utils/state.js +155 -67
- reflex/.templates/web/vite.config.js +32 -0
- reflex/__init__.py +1 -6
- reflex/__init__.pyi +0 -4
- reflex/app.py +52 -115
- reflex/base.py +1 -87
- reflex/compiler/compiler.py +40 -3
- reflex/compiler/utils.py +54 -28
- reflex/components/__init__.py +0 -2
- reflex/components/__init__.pyi +0 -3
- reflex/components/base/__init__.py +1 -5
- reflex/components/base/__init__.pyi +4 -6
- reflex/components/base/app_wrap.pyi +5 -4
- reflex/components/base/body.pyi +5 -4
- reflex/components/base/document.py +18 -14
- reflex/components/base/document.pyi +83 -27
- reflex/components/base/error_boundary.pyi +5 -4
- reflex/components/base/fragment.pyi +5 -4
- reflex/components/base/link.pyi +9 -7
- reflex/components/base/meta.pyi +17 -13
- reflex/components/base/script.py +60 -58
- reflex/components/base/script.pyi +246 -31
- reflex/components/base/strict_mode.pyi +5 -4
- reflex/components/component.py +109 -194
- reflex/components/core/__init__.py +1 -0
- reflex/components/core/__init__.pyi +1 -0
- reflex/components/core/auto_scroll.pyi +5 -4
- reflex/components/core/banner.pyi +25 -19
- reflex/components/core/client_side_routing.py +7 -6
- reflex/components/core/client_side_routing.pyi +6 -56
- reflex/components/core/clipboard.pyi +5 -4
- reflex/components/core/debounce.py +1 -0
- reflex/components/core/debounce.pyi +5 -4
- reflex/components/core/foreach.py +3 -2
- reflex/components/core/helmet.py +14 -0
- reflex/components/{next/base.pyi → core/helmet.pyi} +10 -7
- reflex/components/core/html.pyi +5 -4
- reflex/components/core/sticky.pyi +17 -13
- reflex/components/core/upload.py +2 -1
- reflex/components/core/upload.pyi +21 -16
- reflex/components/datadisplay/code.pyi +9 -7
- reflex/components/datadisplay/dataeditor.pyi +5 -4
- reflex/components/datadisplay/shiki_code_block.pyi +13 -10
- reflex/components/dynamic.py +4 -5
- reflex/components/el/element.pyi +5 -4
- reflex/components/el/elements/base.pyi +5 -4
- reflex/components/el/elements/forms.pyi +69 -52
- reflex/components/el/elements/inline.pyi +113 -85
- reflex/components/el/elements/media.pyi +105 -79
- reflex/components/el/elements/metadata.pyi +25 -19
- reflex/components/el/elements/other.pyi +29 -22
- reflex/components/el/elements/scripts.pyi +13 -10
- reflex/components/el/elements/sectioning.pyi +61 -46
- reflex/components/el/elements/tables.pyi +41 -31
- reflex/components/el/elements/typography.pyi +61 -46
- reflex/components/field.py +175 -0
- reflex/components/gridjs/datatable.py +2 -2
- reflex/components/gridjs/datatable.pyi +11 -9
- reflex/components/lucide/icon.py +6 -2
- reflex/components/lucide/icon.pyi +15 -10
- reflex/components/markdown/markdown.pyi +5 -4
- reflex/components/moment/moment.pyi +5 -4
- reflex/components/plotly/plotly.pyi +19 -10
- reflex/components/props.py +376 -27
- reflex/components/radix/primitives/accordion.py +8 -1
- reflex/components/radix/primitives/accordion.pyi +29 -22
- reflex/components/radix/primitives/base.pyi +9 -7
- reflex/components/radix/primitives/drawer.pyi +45 -34
- reflex/components/radix/primitives/form.pyi +41 -31
- reflex/components/radix/primitives/progress.pyi +21 -16
- reflex/components/radix/primitives/slider.pyi +21 -16
- reflex/components/radix/themes/base.py +3 -3
- reflex/components/radix/themes/base.pyi +33 -25
- reflex/components/radix/themes/color_mode.pyi +13 -10
- reflex/components/radix/themes/components/alert_dialog.pyi +29 -22
- reflex/components/radix/themes/components/aspect_ratio.pyi +5 -4
- reflex/components/radix/themes/components/avatar.pyi +5 -4
- reflex/components/radix/themes/components/badge.pyi +5 -4
- reflex/components/radix/themes/components/button.pyi +5 -4
- reflex/components/radix/themes/components/callout.pyi +21 -16
- reflex/components/radix/themes/components/card.pyi +5 -4
- reflex/components/radix/themes/components/checkbox.pyi +13 -10
- reflex/components/radix/themes/components/checkbox_cards.pyi +9 -7
- reflex/components/radix/themes/components/checkbox_group.pyi +9 -7
- reflex/components/radix/themes/components/context_menu.pyi +53 -40
- reflex/components/radix/themes/components/data_list.pyi +17 -13
- reflex/components/radix/themes/components/dialog.pyi +29 -22
- reflex/components/radix/themes/components/dropdown_menu.pyi +33 -25
- reflex/components/radix/themes/components/hover_card.pyi +17 -13
- reflex/components/radix/themes/components/icon_button.pyi +5 -4
- reflex/components/radix/themes/components/inset.pyi +5 -4
- reflex/components/radix/themes/components/popover.pyi +17 -13
- reflex/components/radix/themes/components/progress.pyi +5 -4
- reflex/components/radix/themes/components/radio.pyi +5 -4
- reflex/components/radix/themes/components/radio_cards.pyi +9 -7
- reflex/components/radix/themes/components/radio_group.pyi +17 -13
- reflex/components/radix/themes/components/scroll_area.pyi +5 -4
- reflex/components/radix/themes/components/segmented_control.pyi +9 -7
- reflex/components/radix/themes/components/select.pyi +37 -28
- reflex/components/radix/themes/components/separator.pyi +5 -4
- reflex/components/radix/themes/components/skeleton.pyi +5 -4
- reflex/components/radix/themes/components/slider.pyi +5 -4
- reflex/components/radix/themes/components/spinner.pyi +5 -4
- reflex/components/radix/themes/components/switch.pyi +5 -4
- reflex/components/radix/themes/components/table.pyi +29 -22
- reflex/components/radix/themes/components/tabs.pyi +21 -16
- reflex/components/radix/themes/components/text_area.pyi +5 -4
- reflex/components/radix/themes/components/text_field.pyi +13 -10
- reflex/components/radix/themes/components/tooltip.pyi +5 -4
- reflex/components/radix/themes/layout/base.pyi +5 -4
- reflex/components/radix/themes/layout/box.pyi +5 -4
- reflex/components/radix/themes/layout/center.pyi +5 -4
- reflex/components/radix/themes/layout/container.pyi +5 -4
- reflex/components/radix/themes/layout/flex.pyi +5 -4
- reflex/components/radix/themes/layout/grid.pyi +5 -4
- reflex/components/radix/themes/layout/list.pyi +21 -16
- reflex/components/radix/themes/layout/section.pyi +5 -4
- reflex/components/radix/themes/layout/spacer.pyi +5 -4
- reflex/components/radix/themes/layout/stack.pyi +13 -10
- reflex/components/radix/themes/typography/blockquote.pyi +5 -4
- reflex/components/radix/themes/typography/code.pyi +5 -4
- reflex/components/radix/themes/typography/heading.pyi +5 -4
- reflex/components/radix/themes/typography/link.py +42 -9
- reflex/components/radix/themes/typography/link.pyi +311 -6
- reflex/components/radix/themes/typography/text.pyi +29 -22
- reflex/components/react_player/audio.pyi +5 -4
- reflex/components/react_player/react_player.pyi +5 -4
- reflex/components/react_player/video.pyi +5 -4
- reflex/components/recharts/cartesian.py +2 -1
- reflex/components/recharts/cartesian.pyi +65 -46
- reflex/components/recharts/charts.py +4 -2
- reflex/components/recharts/charts.pyi +36 -24
- reflex/components/recharts/general.pyi +24 -18
- reflex/components/recharts/polar.py +8 -4
- reflex/components/recharts/polar.pyi +16 -10
- reflex/components/recharts/recharts.pyi +9 -7
- reflex/components/sonner/toast.py +2 -2
- reflex/components/sonner/toast.pyi +7 -6
- reflex/config.py +3 -77
- reflex/constants/__init__.py +1 -0
- reflex/constants/base.py +38 -8
- reflex/constants/compiler.py +4 -2
- reflex/constants/event.py +1 -0
- reflex/constants/installer.py +23 -16
- reflex/constants/state.py +2 -0
- reflex/custom_components/custom_components.py +0 -14
- reflex/environment.py +1 -1
- reflex/event.py +178 -81
- reflex/experimental/__init__.py +0 -30
- reflex/istate/proxy.py +5 -3
- reflex/page.py +0 -27
- reflex/plugins/__init__.py +3 -2
- reflex/plugins/base.py +5 -1
- reflex/plugins/shared_tailwind.py +158 -0
- reflex/plugins/sitemap.py +206 -0
- reflex/plugins/tailwind_v3.py +13 -106
- reflex/plugins/tailwind_v4.py +15 -108
- reflex/reflex.py +1 -0
- reflex/state.py +134 -140
- reflex/testing.py +57 -9
- reflex/utils/build.py +9 -69
- reflex/utils/exec.py +59 -161
- reflex/utils/export.py +1 -1
- reflex/utils/imports.py +0 -4
- reflex/utils/misc.py +28 -0
- reflex/utils/prerequisites.py +62 -59
- reflex/utils/processes.py +6 -6
- reflex/utils/pyi_generator.py +21 -9
- reflex/utils/serializers.py +14 -1
- reflex/utils/types.py +196 -61
- reflex/vars/__init__.py +2 -0
- reflex/vars/base.py +367 -134
- {reflex-0.7.14a6.dist-info → reflex-0.8.0a1.dist-info}/METADATA +12 -5
- {reflex-0.7.14a6.dist-info → reflex-0.8.0a1.dist-info}/RECORD +190 -197
- reflex/.templates/web/next.config.js +0 -7
- reflex/components/base/head.py +0 -20
- reflex/components/base/head.pyi +0 -116
- reflex/components/next/__init__.py +0 -10
- reflex/components/next/base.py +0 -7
- reflex/components/next/image.py +0 -117
- reflex/components/next/image.pyi +0 -94
- reflex/components/next/link.py +0 -20
- reflex/components/next/link.pyi +0 -67
- reflex/components/next/video.py +0 -38
- reflex/components/next/video.pyi +0 -68
- reflex/components/suneditor/__init__.py +0 -5
- reflex/components/suneditor/editor.py +0 -269
- reflex/components/suneditor/editor.pyi +0 -199
- reflex/experimental/layout.py +0 -254
- reflex/experimental/layout.pyi +0 -814
- {reflex-0.7.14a6.dist-info → reflex-0.8.0a1.dist-info}/WHEEL +0 -0
- {reflex-0.7.14a6.dist-info → reflex-0.8.0a1.dist-info}/entry_points.txt +0 -0
- {reflex-0.7.14a6.dist-info → reflex-0.8.0a1.dist-info}/licenses/LICENSE +0 -0
reflex/utils/prerequisites.py
CHANGED
|
@@ -39,9 +39,7 @@ from reflex.compiler import templates
|
|
|
39
39
|
from reflex.config import Config, get_config
|
|
40
40
|
from reflex.environment import environment
|
|
41
41
|
from reflex.utils import console, net, path_ops, processes, redir
|
|
42
|
-
from reflex.utils.decorator import once
|
|
43
42
|
from reflex.utils.exceptions import SystemPackageMissingError
|
|
44
|
-
from reflex.utils.format import format_library_name
|
|
45
43
|
from reflex.utils.registry import get_npm_registry
|
|
46
44
|
|
|
47
45
|
if typing.TYPE_CHECKING:
|
|
@@ -74,7 +72,7 @@ class CpuInfo:
|
|
|
74
72
|
|
|
75
73
|
|
|
76
74
|
def get_web_dir() -> Path:
|
|
77
|
-
"""Get the working directory for the
|
|
75
|
+
"""Get the working directory for the frontend.
|
|
78
76
|
|
|
79
77
|
Can be overridden with REFLEX_WEB_WORKDIR.
|
|
80
78
|
|
|
@@ -334,13 +332,14 @@ def npm_escape_hatch() -> bool:
|
|
|
334
332
|
|
|
335
333
|
|
|
336
334
|
def _check_app_name(config: Config):
|
|
337
|
-
"""Check if the app name is
|
|
335
|
+
"""Check if the app name is valid and matches the folder structure.
|
|
338
336
|
|
|
339
337
|
Args:
|
|
340
338
|
config: The config object.
|
|
341
339
|
|
|
342
340
|
Raises:
|
|
343
|
-
RuntimeError: If the app name is not set
|
|
341
|
+
RuntimeError: If the app name is not set, folder doesn't exist, or doesn't match config.
|
|
342
|
+
ModuleNotFoundError: If the app_name is not importable (i.e., not a valid Python package, folder structure being wrong).
|
|
344
343
|
"""
|
|
345
344
|
if not config.app_name:
|
|
346
345
|
msg = (
|
|
@@ -349,6 +348,21 @@ def _check_app_name(config: Config):
|
|
|
349
348
|
)
|
|
350
349
|
raise RuntimeError(msg)
|
|
351
350
|
|
|
351
|
+
from reflex.utils.misc import with_cwd_in_syspath
|
|
352
|
+
|
|
353
|
+
with with_cwd_in_syspath():
|
|
354
|
+
try:
|
|
355
|
+
mod_spec = importlib.util.find_spec(config.module)
|
|
356
|
+
except ModuleNotFoundError:
|
|
357
|
+
mod_spec = None
|
|
358
|
+
if mod_spec is None:
|
|
359
|
+
msg = f"Module {config.module} not found. "
|
|
360
|
+
if config.app_module_import is not None:
|
|
361
|
+
msg += f"Ensure app_module_import='{config.app_module_import}' in rxconfig.py matches your folder structure."
|
|
362
|
+
else:
|
|
363
|
+
msg += f"Ensure app_name='{config.app_name}' in rxconfig.py matches your folder structure."
|
|
364
|
+
raise ModuleNotFoundError(msg)
|
|
365
|
+
|
|
352
366
|
|
|
353
367
|
def get_app(reload: bool = False) -> ModuleType:
|
|
354
368
|
"""Get the app module based on the default config.
|
|
@@ -439,7 +453,7 @@ def validate_app(
|
|
|
439
453
|
|
|
440
454
|
def get_compiled_app(
|
|
441
455
|
reload: bool = False,
|
|
442
|
-
|
|
456
|
+
prerender_routes: bool = False,
|
|
443
457
|
dry_run: bool = False,
|
|
444
458
|
check_if_schema_up_to_date: bool = False,
|
|
445
459
|
) -> ModuleType:
|
|
@@ -447,7 +461,7 @@ def get_compiled_app(
|
|
|
447
461
|
|
|
448
462
|
Args:
|
|
449
463
|
reload: Re-import the app module from disk
|
|
450
|
-
|
|
464
|
+
prerender_routes: Whether to prerender routes.
|
|
451
465
|
dry_run: If True, do not write the compiled app to disk.
|
|
452
466
|
check_if_schema_up_to_date: If True, check if the schema is up to date.
|
|
453
467
|
|
|
@@ -460,13 +474,13 @@ def get_compiled_app(
|
|
|
460
474
|
# For py3.9 compatibility when redis is used, we MUST add any decorator pages
|
|
461
475
|
# before compiling the app in a thread to avoid event loop error (REF-2172).
|
|
462
476
|
app._apply_decorated_pages()
|
|
463
|
-
app._compile(
|
|
477
|
+
app._compile(prerender_routes=prerender_routes, dry_run=dry_run)
|
|
464
478
|
return app_module
|
|
465
479
|
|
|
466
480
|
|
|
467
481
|
def compile_app(
|
|
468
482
|
reload: bool = False,
|
|
469
|
-
|
|
483
|
+
prerender_routes: bool = False,
|
|
470
484
|
dry_run: bool = False,
|
|
471
485
|
check_if_schema_up_to_date: bool = False,
|
|
472
486
|
) -> None:
|
|
@@ -474,13 +488,13 @@ def compile_app(
|
|
|
474
488
|
|
|
475
489
|
Args:
|
|
476
490
|
reload: Re-import the app module from disk
|
|
477
|
-
|
|
491
|
+
prerender_routes: Whether to prerender routes.
|
|
478
492
|
dry_run: If True, do not write the compiled app to disk.
|
|
479
493
|
check_if_schema_up_to_date: If True, check if the schema is up to date.
|
|
480
494
|
"""
|
|
481
495
|
get_compiled_app(
|
|
482
496
|
reload=reload,
|
|
483
|
-
|
|
497
|
+
prerender_routes=prerender_routes,
|
|
484
498
|
dry_run=dry_run,
|
|
485
499
|
check_if_schema_up_to_date=check_if_schema_up_to_date,
|
|
486
500
|
)
|
|
@@ -529,20 +543,26 @@ def _can_colorize() -> bool:
|
|
|
529
543
|
|
|
530
544
|
|
|
531
545
|
def compile_or_validate_app(
|
|
532
|
-
compile: bool = False,
|
|
546
|
+
compile: bool = False,
|
|
547
|
+
check_if_schema_up_to_date: bool = False,
|
|
548
|
+
prerender_routes: bool = False,
|
|
533
549
|
) -> bool:
|
|
534
550
|
"""Compile or validate the app module based on the default config.
|
|
535
551
|
|
|
536
552
|
Args:
|
|
537
553
|
compile: Whether to compile the app.
|
|
538
554
|
check_if_schema_up_to_date: If True, check if the schema is up to date.
|
|
555
|
+
prerender_routes: Whether to prerender routes.
|
|
539
556
|
|
|
540
557
|
Returns:
|
|
541
558
|
If the app is compiled successfully.
|
|
542
559
|
"""
|
|
543
560
|
try:
|
|
544
561
|
if compile:
|
|
545
|
-
compile_app(
|
|
562
|
+
compile_app(
|
|
563
|
+
check_if_schema_up_to_date=check_if_schema_up_to_date,
|
|
564
|
+
prerender_routes=prerender_routes,
|
|
565
|
+
)
|
|
546
566
|
else:
|
|
547
567
|
validate_app(check_if_schema_up_to_date=check_if_schema_up_to_date)
|
|
548
568
|
except Exception as e:
|
|
@@ -1017,29 +1037,19 @@ def initialize_web_directory():
|
|
|
1017
1037
|
console.debug("Initializing the public directory.")
|
|
1018
1038
|
path_ops.mkdir(get_web_dir() / constants.Dirs.PUBLIC)
|
|
1019
1039
|
|
|
1020
|
-
console.debug("Initializing the
|
|
1021
|
-
|
|
1040
|
+
console.debug("Initializing the react-router.config.js file.")
|
|
1041
|
+
update_react_router_config()
|
|
1022
1042
|
|
|
1023
1043
|
console.debug("Initializing the reflex.json file.")
|
|
1024
1044
|
# Initialize the reflex json file.
|
|
1025
1045
|
init_reflex_json(project_hash=project_hash)
|
|
1026
1046
|
|
|
1027
1047
|
|
|
1028
|
-
@once
|
|
1029
|
-
def _turbopack_flag() -> str:
|
|
1030
|
-
return " --turbopack" if environment.REFLEX_USE_TURBOPACK.get() else ""
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
1048
|
def _compile_package_json():
|
|
1034
1049
|
return templates.PACKAGE_JSON.render(
|
|
1035
1050
|
scripts={
|
|
1036
|
-
"dev": constants.PackageJson.Commands.DEV
|
|
1037
|
-
"export": constants.PackageJson.Commands.EXPORT
|
|
1038
|
-
flags=_turbopack_flag()
|
|
1039
|
-
),
|
|
1040
|
-
"export_sitemap": constants.PackageJson.Commands.EXPORT_SITEMAP.format(
|
|
1041
|
-
flags=_turbopack_flag()
|
|
1042
|
-
),
|
|
1051
|
+
"dev": constants.PackageJson.Commands.DEV,
|
|
1052
|
+
"export": constants.PackageJson.Commands.EXPORT,
|
|
1043
1053
|
"prod": constants.PackageJson.Commands.PROD,
|
|
1044
1054
|
},
|
|
1045
1055
|
dependencies=constants.PackageJson.DEPENDENCIES,
|
|
@@ -1107,50 +1117,43 @@ def init_reflex_json(project_hash: int | None):
|
|
|
1107
1117
|
path_ops.update_json_file(get_web_dir() / constants.Reflex.JSON, reflex_json)
|
|
1108
1118
|
|
|
1109
1119
|
|
|
1110
|
-
def
|
|
1111
|
-
|
|
1112
|
-
):
|
|
1113
|
-
"""Update Next.js config from Reflex config.
|
|
1120
|
+
def update_react_router_config(prerender_routes: bool = False):
|
|
1121
|
+
"""Update react-router.config.js config from Reflex config.
|
|
1114
1122
|
|
|
1115
1123
|
Args:
|
|
1116
|
-
|
|
1117
|
-
transpile_packages: list of packages to transpile via next.config.js.
|
|
1124
|
+
prerender_routes: Whether to enable prerendering of routes.
|
|
1118
1125
|
"""
|
|
1119
|
-
|
|
1126
|
+
react_router_config_file_path = get_web_dir() / constants.ReactRouter.CONFIG_FILE
|
|
1120
1127
|
|
|
1121
|
-
|
|
1122
|
-
get_config(),
|
|
1128
|
+
react_router_config = _update_react_router_config(
|
|
1129
|
+
get_config(), prerender_routes=prerender_routes
|
|
1123
1130
|
)
|
|
1124
1131
|
|
|
1125
|
-
# Overwriting the
|
|
1132
|
+
# Overwriting the config file triggers a full server reload, so make sure
|
|
1126
1133
|
# there is actually a diff.
|
|
1127
|
-
orig_next_config =
|
|
1128
|
-
|
|
1129
|
-
|
|
1134
|
+
orig_next_config = (
|
|
1135
|
+
react_router_config_file_path.read_text()
|
|
1136
|
+
if react_router_config_file_path.exists()
|
|
1137
|
+
else ""
|
|
1138
|
+
)
|
|
1139
|
+
if orig_next_config != react_router_config:
|
|
1140
|
+
react_router_config_file_path.write_text(react_router_config)
|
|
1130
1141
|
|
|
1131
1142
|
|
|
1132
|
-
def
|
|
1133
|
-
|
|
1134
|
-
)
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
"
|
|
1139
|
-
"staticPageGenerationTimeout": config.static_page_generation_timeout,
|
|
1143
|
+
def _update_react_router_config(config: Config, prerender_routes: bool = False):
|
|
1144
|
+
react_router_config = {
|
|
1145
|
+
"basename": "/" + (config.frontend_path or "").removeprefix("/"),
|
|
1146
|
+
"future": {
|
|
1147
|
+
"unstable_optimizeDeps": True,
|
|
1148
|
+
},
|
|
1149
|
+
"ssr": False,
|
|
1140
1150
|
}
|
|
1141
|
-
if not config.next_dev_indicators:
|
|
1142
|
-
next_config["devIndicators"] = False
|
|
1143
1151
|
|
|
1144
|
-
if
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
)
|
|
1148
|
-
if export:
|
|
1149
|
-
next_config["output"] = "export"
|
|
1150
|
-
next_config["distDir"] = constants.Dirs.STATIC
|
|
1152
|
+
if prerender_routes:
|
|
1153
|
+
react_router_config["prerender"] = True
|
|
1154
|
+
react_router_config["build"] = constants.Dirs.BUILD_DIR
|
|
1151
1155
|
|
|
1152
|
-
|
|
1153
|
-
return f"module.exports = {next_config_json};"
|
|
1156
|
+
return f"export default {json.dumps(react_router_config)};"
|
|
1154
1157
|
|
|
1155
1158
|
|
|
1156
1159
|
def remove_existing_bun_installation():
|
reflex/utils/processes.py
CHANGED
|
@@ -412,12 +412,12 @@ def show_progress(message: str, process: subprocess.Popen, checkpoints: list[str
|
|
|
412
412
|
task = progress.add_task(f"{message}: ", total=len(checkpoints))
|
|
413
413
|
for line in stream_logs(message, process, progress=progress):
|
|
414
414
|
# Check for special strings and update the progress bar.
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
415
|
+
special_string = checkpoints[0]
|
|
416
|
+
if special_string in line:
|
|
417
|
+
progress.update(task, advance=1)
|
|
418
|
+
checkpoints.pop(0)
|
|
419
|
+
if not checkpoints:
|
|
420
|
+
break
|
|
421
421
|
|
|
422
422
|
|
|
423
423
|
def atexit_handler():
|
reflex/utils/pyi_generator.py
CHANGED
|
@@ -90,6 +90,7 @@ DEFAULT_IMPORTS = {
|
|
|
90
90
|
"EventSpec",
|
|
91
91
|
"EventType",
|
|
92
92
|
"KeyInputInfo",
|
|
93
|
+
"PointerEventInfo",
|
|
93
94
|
],
|
|
94
95
|
"reflex.style": ["Style"],
|
|
95
96
|
"reflex.vars.base": ["Var"],
|
|
@@ -366,7 +367,7 @@ def _extract_class_props_as_ast_nodes(
|
|
|
366
367
|
all_props = []
|
|
367
368
|
kwargs = []
|
|
368
369
|
for target_class in clzs:
|
|
369
|
-
event_triggers = target_class.
|
|
370
|
+
event_triggers = target_class.get_event_triggers()
|
|
370
371
|
# Import from the target class to ensure type hints are resolvable.
|
|
371
372
|
exec(f"from {target_class.__module__} import *", type_hint_globals)
|
|
372
373
|
for name, value in target_class.__annotations__.items():
|
|
@@ -409,7 +410,7 @@ def _extract_class_props_as_ast_nodes(
|
|
|
409
410
|
)
|
|
410
411
|
),
|
|
411
412
|
),
|
|
412
|
-
ast.Constant(value=default),
|
|
413
|
+
ast.Constant(value=default), # pyright: ignore [reportArgumentType]
|
|
413
414
|
)
|
|
414
415
|
)
|
|
415
416
|
return kwargs
|
|
@@ -444,7 +445,11 @@ def type_to_ast(typ: Any, cls: type) -> ast.expr:
|
|
|
444
445
|
|
|
445
446
|
if all(a == b for a, b in zipped) and len(typ_parts) == len(cls_parts):
|
|
446
447
|
return ast.Name(id=typ.__name__)
|
|
447
|
-
|
|
448
|
+
if (
|
|
449
|
+
typ.__module__ in DEFAULT_IMPORTS
|
|
450
|
+
and typ.__name__ in DEFAULT_IMPORTS[typ.__module__]
|
|
451
|
+
):
|
|
452
|
+
return ast.Name(id=typ.__name__)
|
|
448
453
|
return ast.Name(id=typ.__module__ + "." + typ.__name__)
|
|
449
454
|
return ast.Name(id=typ.__name__)
|
|
450
455
|
if hasattr(typ, "_name"):
|
|
@@ -607,7 +612,7 @@ def _generate_component_create_functiondef(
|
|
|
607
612
|
return ast.Name(id=f"{' | '.join(map(ast.unparse, all_count_args_type))}")
|
|
608
613
|
return ast.Name(id="EventType[Any]")
|
|
609
614
|
|
|
610
|
-
event_triggers = clz.
|
|
615
|
+
event_triggers = clz.get_event_triggers()
|
|
611
616
|
|
|
612
617
|
# event handler kwargs
|
|
613
618
|
kwargs.extend(
|
|
@@ -1337,12 +1342,19 @@ class PyiGenerator:
|
|
|
1337
1342
|
|
|
1338
1343
|
|
|
1339
1344
|
if __name__ == "__main__":
|
|
1345
|
+
import argparse
|
|
1346
|
+
|
|
1347
|
+
parser = argparse.ArgumentParser(description="Generate .pyi stub files")
|
|
1348
|
+
parser.add_argument(
|
|
1349
|
+
"targets",
|
|
1350
|
+
nargs="*",
|
|
1351
|
+
default=["reflex/components", "reflex/experimental", "reflex/__init__.py"],
|
|
1352
|
+
help="Target directories/files to process",
|
|
1353
|
+
)
|
|
1354
|
+
args = parser.parse_args()
|
|
1355
|
+
|
|
1340
1356
|
logging.basicConfig(level=logging.INFO)
|
|
1341
1357
|
logging.getLogger("blib2to3.pgen2.driver").setLevel(logging.INFO)
|
|
1342
1358
|
|
|
1343
1359
|
gen = PyiGenerator()
|
|
1344
|
-
gen.scan_all(
|
|
1345
|
-
["reflex/components", "reflex/experimental", "reflex/__init__.py"],
|
|
1346
|
-
None,
|
|
1347
|
-
use_json=True,
|
|
1348
|
-
)
|
|
1360
|
+
gen.scan_all(args.targets, None, use_json=True)
|
reflex/utils/serializers.py
CHANGED
|
@@ -9,7 +9,7 @@ import functools
|
|
|
9
9
|
import inspect
|
|
10
10
|
import json
|
|
11
11
|
import warnings
|
|
12
|
-
from collections.abc import Callable, Sequence
|
|
12
|
+
from collections.abc import Callable, Mapping, Sequence
|
|
13
13
|
from datetime import date, datetime, time, timedelta
|
|
14
14
|
from enum import Enum
|
|
15
15
|
from pathlib import Path
|
|
@@ -335,6 +335,19 @@ def serialize_sequence(value: Sequence) -> list:
|
|
|
335
335
|
return list(value)
|
|
336
336
|
|
|
337
337
|
|
|
338
|
+
@serializer(to=dict)
|
|
339
|
+
def serialize_mapping(value: Mapping) -> dict:
|
|
340
|
+
"""Serialize a mapping type to a dictionary.
|
|
341
|
+
|
|
342
|
+
Args:
|
|
343
|
+
value: The mapping instance to serialize.
|
|
344
|
+
|
|
345
|
+
Returns:
|
|
346
|
+
A new dictionary containing the same key-value pairs as the input mapping.
|
|
347
|
+
"""
|
|
348
|
+
return {**value}
|
|
349
|
+
|
|
350
|
+
|
|
338
351
|
@serializer(to=str)
|
|
339
352
|
def serialize_datetime(dt: date | datetime | time | timedelta) -> str:
|
|
340
353
|
"""Serialize a datetime to a JSON string.
|
reflex/utils/types.py
CHANGED
|
@@ -3,10 +3,10 @@
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
5
|
import dataclasses
|
|
6
|
-
import
|
|
6
|
+
import sys
|
|
7
7
|
import types
|
|
8
8
|
from collections.abc import Callable, Iterable, Mapping, Sequence
|
|
9
|
-
from functools import cached_property, lru_cache
|
|
9
|
+
from functools import cached_property, lru_cache
|
|
10
10
|
from types import GenericAlias
|
|
11
11
|
from typing import ( # noqa: UP035
|
|
12
12
|
TYPE_CHECKING,
|
|
@@ -19,8 +19,11 @@ from typing import ( # noqa: UP035
|
|
|
19
19
|
Literal,
|
|
20
20
|
MutableMapping,
|
|
21
21
|
NoReturn,
|
|
22
|
+
Protocol,
|
|
22
23
|
Tuple,
|
|
24
|
+
TypeVar,
|
|
23
25
|
Union,
|
|
26
|
+
_eval_type, # pyright: ignore [reportAttributeAccessIssue]
|
|
24
27
|
_GenericAlias, # pyright: ignore [reportAttributeAccessIssue]
|
|
25
28
|
_SpecialGenericAlias, # pyright: ignore [reportAttributeAccessIssue]
|
|
26
29
|
get_args,
|
|
@@ -58,18 +61,91 @@ StateIterVar = list | set | tuple
|
|
|
58
61
|
if TYPE_CHECKING:
|
|
59
62
|
from reflex.vars.base import Var
|
|
60
63
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
64
|
+
VAR1 = TypeVar("VAR1", bound="Var")
|
|
65
|
+
VAR2 = TypeVar("VAR2", bound="Var")
|
|
66
|
+
VAR3 = TypeVar("VAR3", bound="Var")
|
|
67
|
+
VAR4 = TypeVar("VAR4", bound="Var")
|
|
68
|
+
VAR5 = TypeVar("VAR5", bound="Var")
|
|
69
|
+
VAR6 = TypeVar("VAR6", bound="Var")
|
|
70
|
+
VAR7 = TypeVar("VAR7", bound="Var")
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
class _ArgsSpec0(Protocol):
|
|
74
|
+
def __call__(self) -> Sequence[Var]: ...
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
class _ArgsSpec1(Protocol):
|
|
78
|
+
def __call__(self, var1: VAR1, /) -> Sequence[Var]: ... # pyright: ignore [reportInvalidTypeVarUse]
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
class _ArgsSpec2(Protocol):
|
|
82
|
+
def __call__(self, var1: VAR1, var2: VAR2, /) -> Sequence[Var]: ... # pyright: ignore [reportInvalidTypeVarUse]
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
class _ArgsSpec3(Protocol):
|
|
86
|
+
def __call__(self, var1: VAR1, var2: VAR2, var3: VAR3, /) -> Sequence[Var]: ... # pyright: ignore [reportInvalidTypeVarUse]
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
class _ArgsSpec4(Protocol):
|
|
90
|
+
def __call__(
|
|
91
|
+
self,
|
|
92
|
+
var1: VAR1, # pyright: ignore [reportInvalidTypeVarUse]
|
|
93
|
+
var2: VAR2, # pyright: ignore [reportInvalidTypeVarUse]
|
|
94
|
+
var3: VAR3, # pyright: ignore [reportInvalidTypeVarUse]
|
|
95
|
+
var4: VAR4, # pyright: ignore [reportInvalidTypeVarUse]
|
|
96
|
+
/,
|
|
97
|
+
) -> Sequence[Var]: ...
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
class _ArgsSpec5(Protocol):
|
|
101
|
+
def __call__(
|
|
102
|
+
self,
|
|
103
|
+
var1: VAR1, # pyright: ignore [reportInvalidTypeVarUse]
|
|
104
|
+
var2: VAR2, # pyright: ignore [reportInvalidTypeVarUse]
|
|
105
|
+
var3: VAR3, # pyright: ignore [reportInvalidTypeVarUse]
|
|
106
|
+
var4: VAR4, # pyright: ignore [reportInvalidTypeVarUse]
|
|
107
|
+
var5: VAR5, # pyright: ignore [reportInvalidTypeVarUse]
|
|
108
|
+
/,
|
|
109
|
+
) -> Sequence[Var]: ...
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
class _ArgsSpec6(Protocol):
|
|
113
|
+
def __call__(
|
|
114
|
+
self,
|
|
115
|
+
var1: VAR1, # pyright: ignore [reportInvalidTypeVarUse]
|
|
116
|
+
var2: VAR2, # pyright: ignore [reportInvalidTypeVarUse]
|
|
117
|
+
var3: VAR3, # pyright: ignore [reportInvalidTypeVarUse]
|
|
118
|
+
var4: VAR4, # pyright: ignore [reportInvalidTypeVarUse]
|
|
119
|
+
var5: VAR5, # pyright: ignore [reportInvalidTypeVarUse]
|
|
120
|
+
var6: VAR6, # pyright: ignore [reportInvalidTypeVarUse]
|
|
121
|
+
/,
|
|
122
|
+
) -> Sequence[Var]: ...
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
class _ArgsSpec7(Protocol):
|
|
126
|
+
def __call__(
|
|
127
|
+
self,
|
|
128
|
+
var1: VAR1, # pyright: ignore [reportInvalidTypeVarUse]
|
|
129
|
+
var2: VAR2, # pyright: ignore [reportInvalidTypeVarUse]
|
|
130
|
+
var3: VAR3, # pyright: ignore [reportInvalidTypeVarUse]
|
|
131
|
+
var4: VAR4, # pyright: ignore [reportInvalidTypeVarUse]
|
|
132
|
+
var5: VAR5, # pyright: ignore [reportInvalidTypeVarUse]
|
|
133
|
+
var6: VAR6, # pyright: ignore [reportInvalidTypeVarUse]
|
|
134
|
+
var7: VAR7, # pyright: ignore [reportInvalidTypeVarUse]
|
|
135
|
+
/,
|
|
136
|
+
) -> Sequence[Var]: ...
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
ArgsSpec = (
|
|
140
|
+
_ArgsSpec0
|
|
141
|
+
| _ArgsSpec1
|
|
142
|
+
| _ArgsSpec2
|
|
143
|
+
| _ArgsSpec3
|
|
144
|
+
| _ArgsSpec4
|
|
145
|
+
| _ArgsSpec5
|
|
146
|
+
| _ArgsSpec6
|
|
147
|
+
| _ArgsSpec7
|
|
148
|
+
)
|
|
73
149
|
|
|
74
150
|
Scope = MutableMapping[str, Any]
|
|
75
151
|
Message = MutableMapping[str, Any]
|
|
@@ -85,11 +161,7 @@ PrimitiveToAnnotation = {
|
|
|
85
161
|
dict: Dict, # noqa: UP006
|
|
86
162
|
}
|
|
87
163
|
|
|
88
|
-
RESERVED_BACKEND_VAR_NAMES = {
|
|
89
|
-
"_abc_impl",
|
|
90
|
-
"_backend_vars",
|
|
91
|
-
"_was_touched",
|
|
92
|
-
}
|
|
164
|
+
RESERVED_BACKEND_VAR_NAMES = {"_abc_impl", "_backend_vars", "_was_touched", "_mixin"}
|
|
93
165
|
|
|
94
166
|
|
|
95
167
|
class Unset:
|
|
@@ -251,7 +323,11 @@ def is_optional(cls: GenericType) -> bool:
|
|
|
251
323
|
Returns:
|
|
252
324
|
Whether the class is an Optional.
|
|
253
325
|
"""
|
|
254
|
-
return
|
|
326
|
+
return (
|
|
327
|
+
cls is None
|
|
328
|
+
or cls is type(None)
|
|
329
|
+
or (is_union(cls) and type(None) in get_args(cls))
|
|
330
|
+
)
|
|
255
331
|
|
|
256
332
|
|
|
257
333
|
def is_classvar(a_type: Any) -> bool:
|
|
@@ -917,47 +993,6 @@ def validate_literal(key: str, value: Any, expected_type: type, comp_name: str):
|
|
|
917
993
|
raise ValueError(msg)
|
|
918
994
|
|
|
919
995
|
|
|
920
|
-
def validate_parameter_literals(func: Callable):
|
|
921
|
-
"""Decorator to check that the arguments passed to a function
|
|
922
|
-
correspond to the correct function parameter if it (the parameter)
|
|
923
|
-
is a literal type.
|
|
924
|
-
|
|
925
|
-
Args:
|
|
926
|
-
func: The function to validate.
|
|
927
|
-
|
|
928
|
-
Returns:
|
|
929
|
-
The wrapper function.
|
|
930
|
-
"""
|
|
931
|
-
console.deprecate(
|
|
932
|
-
"validate_parameter_literals",
|
|
933
|
-
reason="Use manual validation instead.",
|
|
934
|
-
deprecation_version="0.7.11",
|
|
935
|
-
removal_version="0.8.0",
|
|
936
|
-
dedupe=True,
|
|
937
|
-
)
|
|
938
|
-
|
|
939
|
-
func_params = list(inspect.signature(func).parameters.items())
|
|
940
|
-
annotations = {param[0]: param[1].annotation for param in func_params}
|
|
941
|
-
|
|
942
|
-
@wraps(func)
|
|
943
|
-
def wrapper(*args, **kwargs):
|
|
944
|
-
# validate args
|
|
945
|
-
for param, arg in zip(annotations, args, strict=False):
|
|
946
|
-
if annotations[param] is inspect.Parameter.empty:
|
|
947
|
-
continue
|
|
948
|
-
validate_literal(param, arg, annotations[param], func.__name__)
|
|
949
|
-
|
|
950
|
-
# validate kwargs.
|
|
951
|
-
for key, value in kwargs.items():
|
|
952
|
-
annotation = annotations.get(key)
|
|
953
|
-
if not annotation or annotation is inspect.Parameter.empty:
|
|
954
|
-
continue
|
|
955
|
-
validate_literal(key, value, annotation, func.__name__)
|
|
956
|
-
return func(*args, **kwargs)
|
|
957
|
-
|
|
958
|
-
return wrapper
|
|
959
|
-
|
|
960
|
-
|
|
961
996
|
# Store this here for performance.
|
|
962
997
|
StateBases = get_base_class(StateVar)
|
|
963
998
|
StateIterBases = get_base_class(StateIterVar)
|
|
@@ -1118,3 +1153,103 @@ def typehint_issubclass(
|
|
|
1118
1153
|
)
|
|
1119
1154
|
if accepted_arg is not Any
|
|
1120
1155
|
)
|
|
1156
|
+
|
|
1157
|
+
|
|
1158
|
+
def resolve_annotations(
|
|
1159
|
+
raw_annotations: Mapping[str, type[Any]], module_name: str | None
|
|
1160
|
+
) -> dict[str, type[Any]]:
|
|
1161
|
+
"""Partially taken from typing.get_type_hints.
|
|
1162
|
+
|
|
1163
|
+
Resolve string or ForwardRef annotations into type objects if possible.
|
|
1164
|
+
|
|
1165
|
+
Args:
|
|
1166
|
+
raw_annotations: The raw annotations to resolve.
|
|
1167
|
+
module_name: The name of the module.
|
|
1168
|
+
|
|
1169
|
+
Returns:
|
|
1170
|
+
The resolved annotations.
|
|
1171
|
+
"""
|
|
1172
|
+
module = sys.modules.get(module_name, None) if module_name is not None else None
|
|
1173
|
+
|
|
1174
|
+
base_globals: dict[str, Any] | None = (
|
|
1175
|
+
module.__dict__ if module is not None else None
|
|
1176
|
+
)
|
|
1177
|
+
|
|
1178
|
+
annotations = {}
|
|
1179
|
+
for name, value in raw_annotations.items():
|
|
1180
|
+
if isinstance(value, str):
|
|
1181
|
+
if sys.version_info == (3, 10, 0):
|
|
1182
|
+
value = ForwardRef(value, is_argument=False)
|
|
1183
|
+
else:
|
|
1184
|
+
value = ForwardRef(value, is_argument=False, is_class=True)
|
|
1185
|
+
try:
|
|
1186
|
+
if sys.version_info >= (3, 13):
|
|
1187
|
+
value = _eval_type(value, base_globals, None, type_params=())
|
|
1188
|
+
else:
|
|
1189
|
+
value = _eval_type(value, base_globals, None)
|
|
1190
|
+
except NameError:
|
|
1191
|
+
# this is ok, it can be fixed with update_forward_refs
|
|
1192
|
+
pass
|
|
1193
|
+
annotations[name] = value
|
|
1194
|
+
return annotations
|
|
1195
|
+
|
|
1196
|
+
|
|
1197
|
+
TYPES_THAT_HAS_DEFAULT_VALUE = (int, float, tuple, list, set, dict, str)
|
|
1198
|
+
|
|
1199
|
+
|
|
1200
|
+
def get_default_value_for_type(t: GenericType) -> Any:
|
|
1201
|
+
"""Get the default value of the var.
|
|
1202
|
+
|
|
1203
|
+
Args:
|
|
1204
|
+
t: The type of the var.
|
|
1205
|
+
|
|
1206
|
+
Returns:
|
|
1207
|
+
The default value of the var, if it has one, else None.
|
|
1208
|
+
|
|
1209
|
+
Raises:
|
|
1210
|
+
ImportError: If the var is a dataframe and pandas is not installed.
|
|
1211
|
+
"""
|
|
1212
|
+
if is_optional(t):
|
|
1213
|
+
return None
|
|
1214
|
+
|
|
1215
|
+
origin = get_origin(t) if is_generic_alias(t) else t
|
|
1216
|
+
if origin is Literal:
|
|
1217
|
+
args = get_args(t)
|
|
1218
|
+
return args[0] if args else None
|
|
1219
|
+
if safe_issubclass(origin, TYPES_THAT_HAS_DEFAULT_VALUE):
|
|
1220
|
+
return origin()
|
|
1221
|
+
if safe_issubclass(origin, Mapping):
|
|
1222
|
+
return {}
|
|
1223
|
+
if is_dataframe(origin):
|
|
1224
|
+
try:
|
|
1225
|
+
import pandas as pd
|
|
1226
|
+
|
|
1227
|
+
return pd.DataFrame()
|
|
1228
|
+
except ImportError as e:
|
|
1229
|
+
msg = "Please install pandas to use dataframes in your app."
|
|
1230
|
+
raise ImportError(msg) from e
|
|
1231
|
+
return None
|
|
1232
|
+
|
|
1233
|
+
|
|
1234
|
+
IMMUTABLE_TYPES = (
|
|
1235
|
+
int,
|
|
1236
|
+
float,
|
|
1237
|
+
bool,
|
|
1238
|
+
str,
|
|
1239
|
+
bytes,
|
|
1240
|
+
frozenset,
|
|
1241
|
+
tuple,
|
|
1242
|
+
type(None),
|
|
1243
|
+
)
|
|
1244
|
+
|
|
1245
|
+
|
|
1246
|
+
def is_immutable(i: Any) -> bool:
|
|
1247
|
+
"""Check if a value is immutable.
|
|
1248
|
+
|
|
1249
|
+
Args:
|
|
1250
|
+
i: The value to check.
|
|
1251
|
+
|
|
1252
|
+
Returns:
|
|
1253
|
+
Whether the value is immutable.
|
|
1254
|
+
"""
|
|
1255
|
+
return isinstance(i, IMMUTABLE_TYPES)
|
reflex/vars/__init__.py
CHANGED