reflex 0.7.4a2__py3-none-any.whl → 0.7.5__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/__init__.py +1 -0
- reflex/__init__.pyi +1 -0
- reflex/app.py +10 -8
- reflex/app_mixins/middleware.py +13 -20
- reflex/compiler/compiler.py +10 -3
- reflex/compiler/utils.py +4 -4
- reflex/components/base/app_wrap.pyi +7 -3
- reflex/components/base/body.pyi +7 -3
- reflex/components/base/document.pyi +27 -7
- reflex/components/base/error_boundary.pyi +7 -3
- reflex/components/base/fragment.pyi +7 -3
- reflex/components/base/head.pyi +12 -4
- reflex/components/base/link.pyi +12 -4
- reflex/components/base/meta.pyi +22 -6
- reflex/components/base/script.pyi +7 -3
- reflex/components/base/strict_mode.pyi +7 -3
- reflex/components/component.py +64 -23
- reflex/components/core/auto_scroll.pyi +7 -3
- reflex/components/core/banner.py +6 -2
- reflex/components/core/banner.pyi +32 -8
- reflex/components/core/client_side_routing.pyi +12 -4
- reflex/components/core/clipboard.pyi +7 -3
- reflex/components/core/debounce.pyi +7 -3
- reflex/components/core/foreach.py +5 -1
- reflex/components/core/html.pyi +7 -3
- reflex/components/core/match.py +5 -5
- reflex/components/core/sticky.pyi +21 -6
- reflex/components/core/upload.pyi +27 -7
- reflex/components/datadisplay/code.pyi +12 -4
- reflex/components/datadisplay/dataeditor.py +2 -2
- reflex/components/datadisplay/dataeditor.pyi +17 -3
- reflex/components/datadisplay/shiki_code_block.pyi +17 -4
- reflex/components/el/__init__.pyi +1 -1
- reflex/components/el/element.pyi +7 -3
- reflex/components/el/elements/__init__.py +3 -1
- reflex/components/el/elements/__init__.pyi +3 -2
- reflex/components/el/elements/base.pyi +7 -3
- reflex/components/el/elements/forms.py +1 -1
- reflex/components/el/elements/forms.pyi +72 -16
- reflex/components/el/elements/inline.pyi +142 -30
- reflex/components/el/elements/media.pyi +127 -27
- reflex/components/el/elements/metadata.pyi +32 -8
- reflex/components/el/elements/other.pyi +37 -9
- reflex/components/el/elements/scripts.pyi +17 -5
- reflex/components/el/elements/sectioning.pyi +77 -17
- reflex/components/el/elements/tables.pyi +52 -12
- reflex/components/el/elements/typography.pyi +77 -17
- reflex/components/gridjs/datatable.py +2 -2
- reflex/components/gridjs/datatable.pyi +12 -4
- reflex/components/lucide/icon.py +7 -6
- reflex/components/lucide/icon.pyi +22 -7
- reflex/components/markdown/markdown.py +1 -1
- reflex/components/markdown/markdown.pyi +7 -3
- reflex/components/moment/moment.pyi +7 -3
- reflex/components/next/base.pyi +7 -3
- reflex/components/next/image.pyi +7 -3
- reflex/components/next/link.pyi +7 -3
- reflex/components/next/video.pyi +7 -3
- reflex/components/plotly/plotly.pyi +47 -11
- reflex/components/radix/primitives/accordion.pyi +37 -9
- reflex/components/radix/primitives/base.pyi +12 -4
- reflex/components/radix/primitives/drawer.pyi +57 -13
- reflex/components/radix/primitives/form.pyi +52 -12
- reflex/components/radix/primitives/progress.pyi +27 -7
- reflex/components/radix/primitives/slider.pyi +27 -7
- reflex/components/radix/themes/base.pyi +41 -10
- reflex/components/radix/themes/color_mode.py +2 -2
- reflex/components/radix/themes/color_mode.pyi +17 -5
- reflex/components/radix/themes/components/alert_dialog.pyi +36 -9
- reflex/components/radix/themes/components/aspect_ratio.pyi +7 -3
- reflex/components/radix/themes/components/avatar.pyi +6 -3
- reflex/components/radix/themes/components/badge.pyi +6 -3
- reflex/components/radix/themes/components/button.pyi +6 -3
- reflex/components/radix/themes/components/callout.pyi +26 -7
- reflex/components/radix/themes/components/card.pyi +6 -3
- reflex/components/radix/themes/components/checkbox.pyi +16 -5
- reflex/components/radix/themes/components/checkbox_cards.pyi +11 -4
- reflex/components/radix/themes/components/checkbox_group.pyi +11 -4
- reflex/components/radix/themes/components/context_menu.pyi +66 -15
- reflex/components/radix/themes/components/data_list.pyi +21 -6
- reflex/components/radix/themes/components/dialog.pyi +36 -9
- reflex/components/radix/themes/components/dropdown_menu.pyi +41 -10
- reflex/components/radix/themes/components/hover_card.pyi +21 -6
- reflex/components/radix/themes/components/icon_button.pyi +6 -3
- reflex/components/radix/themes/components/inset.pyi +6 -3
- reflex/components/radix/themes/components/popover.pyi +21 -6
- reflex/components/radix/themes/components/progress.pyi +6 -3
- reflex/components/radix/themes/components/radio.pyi +6 -3
- reflex/components/radix/themes/components/radio_cards.pyi +11 -4
- reflex/components/radix/themes/components/radio_group.py +6 -1
- reflex/components/radix/themes/components/radio_group.pyi +21 -6
- reflex/components/radix/themes/components/scroll_area.pyi +7 -3
- reflex/components/radix/themes/components/segmented_control.pyi +11 -4
- reflex/components/radix/themes/components/select.pyi +46 -11
- reflex/components/radix/themes/components/separator.pyi +6 -3
- reflex/components/radix/themes/components/skeleton.pyi +6 -3
- reflex/components/radix/themes/components/slider.pyi +6 -3
- reflex/components/radix/themes/components/spinner.pyi +6 -3
- reflex/components/radix/themes/components/switch.pyi +6 -3
- reflex/components/radix/themes/components/table.pyi +36 -9
- reflex/components/radix/themes/components/tabs.pyi +26 -7
- reflex/components/radix/themes/components/text_area.pyi +6 -3
- reflex/components/radix/themes/components/text_field.py +3 -2
- reflex/components/radix/themes/components/text_field.pyi +16 -5
- reflex/components/radix/themes/components/tooltip.pyi +7 -3
- reflex/components/radix/themes/layout/base.pyi +6 -3
- reflex/components/radix/themes/layout/box.pyi +7 -3
- reflex/components/radix/themes/layout/center.pyi +6 -3
- reflex/components/radix/themes/layout/container.pyi +6 -3
- reflex/components/radix/themes/layout/flex.pyi +6 -3
- reflex/components/radix/themes/layout/grid.pyi +6 -3
- reflex/components/radix/themes/layout/list.pyi +27 -7
- reflex/components/radix/themes/layout/section.pyi +6 -3
- reflex/components/radix/themes/layout/spacer.pyi +6 -3
- reflex/components/radix/themes/layout/stack.pyi +16 -5
- reflex/components/radix/themes/typography/blockquote.pyi +6 -3
- reflex/components/radix/themes/typography/code.pyi +6 -3
- reflex/components/radix/themes/typography/heading.pyi +6 -3
- reflex/components/radix/themes/typography/link.pyi +6 -3
- reflex/components/radix/themes/typography/text.pyi +36 -9
- reflex/components/react_player/audio.pyi +7 -3
- reflex/components/react_player/react_player.pyi +7 -3
- reflex/components/react_player/video.pyi +7 -3
- reflex/components/recharts/cartesian.pyi +97 -21
- reflex/components/recharts/charts.pyi +62 -14
- reflex/components/recharts/general.pyi +32 -8
- reflex/components/recharts/polar.py +1 -1
- reflex/components/recharts/polar.pyi +33 -9
- reflex/components/recharts/recharts.pyi +12 -4
- reflex/components/sonner/toast.pyi +7 -2
- reflex/components/suneditor/editor.pyi +7 -3
- reflex/config.py +18 -1
- reflex/constants/installer.py +22 -1
- reflex/custom_components/custom_components.py +12 -7
- reflex/event.py +26 -10
- reflex/experimental/__init__.py +17 -6
- reflex/experimental/layout.pyi +27 -7
- reflex/model.py +3 -3
- reflex/reflex.py +33 -18
- reflex/state.py +4 -4
- reflex/style.py +2 -2
- reflex/testing.py +17 -5
- reflex/utils/console.py +2 -3
- reflex/utils/exec.py +4 -0
- reflex/utils/imports.py +14 -7
- reflex/utils/net.py +107 -18
- reflex/utils/prerequisites.py +92 -13
- reflex/utils/processes.py +52 -19
- reflex/utils/pyi_generator.py +66 -53
- reflex/utils/redir.py +3 -1
- reflex/utils/registry.py +15 -5
- reflex/utils/serializers.py +1 -2
- reflex/utils/types.py +4 -4
- reflex/vars/base.py +58 -22
- reflex/vars/number.py +23 -6
- reflex/vars/sequence.py +2 -0
- {reflex-0.7.4a2.dist-info → reflex-0.7.5.dist-info}/METADATA +2 -2
- {reflex-0.7.4a2.dist-info → reflex-0.7.5.dist-info}/RECORD +162 -162
- /reflex/{experimental → utils}/misc.py +0 -0
- {reflex-0.7.4a2.dist-info → reflex-0.7.5.dist-info}/WHEEL +0 -0
- {reflex-0.7.4a2.dist-info → reflex-0.7.5.dist-info}/entry_points.txt +0 -0
- {reflex-0.7.4a2.dist-info → reflex-0.7.5.dist-info}/licenses/LICENSE +0 -0
reflex/utils/prerequisites.py
CHANGED
|
@@ -115,11 +115,13 @@ def check_latest_package_version(package_name: str):
|
|
|
115
115
|
if environment.REFLEX_CHECK_LATEST_VERSION.get() is False:
|
|
116
116
|
return
|
|
117
117
|
try:
|
|
118
|
+
console.debug(f"Checking for the latest version of {package_name}...")
|
|
118
119
|
# Get the latest version from PyPI
|
|
119
120
|
current_version = importlib.metadata.version(package_name)
|
|
120
121
|
url = f"https://pypi.org/pypi/{package_name}/json"
|
|
121
122
|
response = net.get(url)
|
|
122
123
|
latest_version = response.json()["info"]["version"]
|
|
124
|
+
console.debug(f"Latest version of {package_name}: {latest_version}")
|
|
123
125
|
if get_or_set_last_reflex_version_check_datetime():
|
|
124
126
|
# Versions were already checked and saved in reflex.json, no need to warn again
|
|
125
127
|
return
|
|
@@ -129,6 +131,7 @@ def check_latest_package_version(package_name: str):
|
|
|
129
131
|
f"Your version ({current_version}) of {package_name} is out of date. Upgrade to {latest_version} with 'pip install {package_name} --upgrade'"
|
|
130
132
|
)
|
|
131
133
|
except Exception:
|
|
134
|
+
console.debug(f"Failed to check for the latest version of {package_name}.")
|
|
132
135
|
pass
|
|
133
136
|
|
|
134
137
|
|
|
@@ -507,6 +510,9 @@ def compile_or_validate_app(compile: bool = False) -> bool:
|
|
|
507
510
|
else:
|
|
508
511
|
validate_app()
|
|
509
512
|
except Exception as e:
|
|
513
|
+
if isinstance(e, typer.Exit):
|
|
514
|
+
return False
|
|
515
|
+
|
|
510
516
|
import traceback
|
|
511
517
|
|
|
512
518
|
sys_exception = sys.exception()
|
|
@@ -902,11 +908,12 @@ def initialize_app_directory(
|
|
|
902
908
|
|
|
903
909
|
console.debug(f"Using {template_name=} {template_dir=} {template_code_dir_name=}.")
|
|
904
910
|
|
|
905
|
-
# Remove
|
|
906
|
-
for
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
911
|
+
# Remove __pycache__ dirs in template directory and current directory.
|
|
912
|
+
for pycache_dir in [
|
|
913
|
+
*template_dir.glob("**/__pycache__"),
|
|
914
|
+
*Path.cwd().glob("**/__pycache__"),
|
|
915
|
+
]:
|
|
916
|
+
shutil.rmtree(pycache_dir, ignore_errors=True)
|
|
910
917
|
|
|
911
918
|
for file in template_dir.iterdir():
|
|
912
919
|
# Copy the file to current directory but keep the name the same.
|
|
@@ -950,16 +957,25 @@ def initialize_web_directory():
|
|
|
950
957
|
# Reuse the hash if one is already created, so we don't over-write it when running reflex init
|
|
951
958
|
project_hash = get_project_hash()
|
|
952
959
|
|
|
960
|
+
console.debug(f"Copying {constants.Templates.Dirs.WEB_TEMPLATE} to {get_web_dir()}")
|
|
953
961
|
path_ops.cp(constants.Templates.Dirs.WEB_TEMPLATE, str(get_web_dir()))
|
|
954
962
|
|
|
963
|
+
console.debug("Initializing the web directory.")
|
|
955
964
|
initialize_package_json()
|
|
956
965
|
|
|
966
|
+
console.debug("Initializing the bun config file.")
|
|
957
967
|
initialize_bun_config()
|
|
958
968
|
|
|
969
|
+
console.debug("Initializing the .npmrc file.")
|
|
970
|
+
initialize_npmrc()
|
|
971
|
+
|
|
972
|
+
console.debug("Initializing the public directory.")
|
|
959
973
|
path_ops.mkdir(get_web_dir() / constants.Dirs.PUBLIC)
|
|
960
974
|
|
|
975
|
+
console.debug("Initializing the next.config.js file.")
|
|
961
976
|
update_next_config()
|
|
962
977
|
|
|
978
|
+
console.debug("Initializing the reflex.json file.")
|
|
963
979
|
# Initialize the reflex json file.
|
|
964
980
|
init_reflex_json(project_hash=project_hash)
|
|
965
981
|
|
|
@@ -1002,6 +1018,20 @@ def initialize_bun_config():
|
|
|
1002
1018
|
bun_config_path.write_text(bunfig_content)
|
|
1003
1019
|
|
|
1004
1020
|
|
|
1021
|
+
def initialize_npmrc():
|
|
1022
|
+
"""Initialize the .npmrc file."""
|
|
1023
|
+
npmrc_path = get_web_dir() / constants.Node.CONFIG_PATH
|
|
1024
|
+
|
|
1025
|
+
if (custom_npmrc := Path(constants.Node.CONFIG_PATH)).exists():
|
|
1026
|
+
npmrc_content = custom_npmrc.read_text()
|
|
1027
|
+
console.info(f"Copying custom .npmrc inside {get_web_dir()} folder")
|
|
1028
|
+
else:
|
|
1029
|
+
best_registry = get_npm_registry()
|
|
1030
|
+
npmrc_content = constants.Node.DEFAULT_CONFIG.format(registry=best_registry)
|
|
1031
|
+
|
|
1032
|
+
npmrc_path.write_text(npmrc_content)
|
|
1033
|
+
|
|
1034
|
+
|
|
1005
1035
|
def init_reflex_json(project_hash: int | None):
|
|
1006
1036
|
"""Write the hash of the Reflex project to a REFLEX_JSON.
|
|
1007
1037
|
|
|
@@ -1057,6 +1087,7 @@ def _update_next_config(
|
|
|
1057
1087
|
"compress": config.next_compression,
|
|
1058
1088
|
"trailingSlash": True,
|
|
1059
1089
|
"staticPageGenerationTimeout": config.static_page_generation_timeout,
|
|
1090
|
+
"devIndicators": config.next_dev_indicators,
|
|
1060
1091
|
}
|
|
1061
1092
|
if transpile_packages:
|
|
1062
1093
|
next_config["transpilePackages"] = list(
|
|
@@ -1170,26 +1201,39 @@ def _clear_cached_procedure_file(cache_file: str | Path):
|
|
|
1170
1201
|
cache_file.unlink()
|
|
1171
1202
|
|
|
1172
1203
|
|
|
1173
|
-
def cached_procedure(
|
|
1204
|
+
def cached_procedure(
|
|
1205
|
+
cache_file: str | None,
|
|
1206
|
+
payload_fn: Callable[..., str],
|
|
1207
|
+
cache_file_fn: Callable[[], str] | None = None,
|
|
1208
|
+
):
|
|
1174
1209
|
"""Decorator to cache the runs of a procedure on disk. Procedures should not have
|
|
1175
1210
|
a return value.
|
|
1176
1211
|
|
|
1177
1212
|
Args:
|
|
1178
1213
|
cache_file: The file to store the cache payload in.
|
|
1179
|
-
payload_fn: Function that computes cache payload from function args
|
|
1214
|
+
payload_fn: Function that computes cache payload from function args.
|
|
1215
|
+
cache_file_fn: Function that computes the cache file name at runtime.
|
|
1180
1216
|
|
|
1181
1217
|
Returns:
|
|
1182
1218
|
The decorated function.
|
|
1219
|
+
|
|
1220
|
+
Raises:
|
|
1221
|
+
ValueError: If both cache_file and cache_file_fn are provided.
|
|
1183
1222
|
"""
|
|
1223
|
+
if cache_file and cache_file_fn is not None:
|
|
1224
|
+
raise ValueError("cache_file and cache_file_fn cannot both be provided.")
|
|
1184
1225
|
|
|
1185
1226
|
def _inner_decorator(func: Callable):
|
|
1186
1227
|
def _inner(*args, **kwargs):
|
|
1187
|
-
|
|
1228
|
+
_cache_file = cache_file_fn() if cache_file_fn is not None else cache_file
|
|
1229
|
+
if not _cache_file:
|
|
1230
|
+
raise ValueError("Unknown cache file, cannot cache result.")
|
|
1231
|
+
payload = _read_cached_procedure_file(_cache_file)
|
|
1188
1232
|
new_payload = payload_fn(*args, **kwargs)
|
|
1189
1233
|
if payload != new_payload:
|
|
1190
|
-
_clear_cached_procedure_file(
|
|
1234
|
+
_clear_cached_procedure_file(_cache_file)
|
|
1191
1235
|
func(*args, **kwargs)
|
|
1192
|
-
_write_cached_procedure_file(new_payload,
|
|
1236
|
+
_write_cached_procedure_file(new_payload, _cache_file)
|
|
1193
1237
|
|
|
1194
1238
|
return _inner
|
|
1195
1239
|
|
|
@@ -1197,8 +1241,11 @@ def cached_procedure(cache_file: str, payload_fn: Callable[..., str]):
|
|
|
1197
1241
|
|
|
1198
1242
|
|
|
1199
1243
|
@cached_procedure(
|
|
1200
|
-
|
|
1244
|
+
cache_file_fn=lambda: str(
|
|
1245
|
+
get_web_dir() / "reflex.install_frontend_packages.cached"
|
|
1246
|
+
),
|
|
1201
1247
|
payload_fn=lambda p, c: f"{sorted(p)!r},{c.json()}",
|
|
1248
|
+
cache_file=None,
|
|
1202
1249
|
)
|
|
1203
1250
|
def install_frontend_packages(packages: set[str], config: Config):
|
|
1204
1251
|
"""Installs the base and custom frontend packages.
|
|
@@ -1214,6 +1261,14 @@ def install_frontend_packages(packages: set[str], config: Config):
|
|
|
1214
1261
|
raise_on_none=True
|
|
1215
1262
|
)
|
|
1216
1263
|
|
|
1264
|
+
env = (
|
|
1265
|
+
{
|
|
1266
|
+
"NODE_TLS_REJECT_UNAUTHORIZED": "0",
|
|
1267
|
+
}
|
|
1268
|
+
if environment.SSL_NO_VERIFY.get()
|
|
1269
|
+
else {}
|
|
1270
|
+
)
|
|
1271
|
+
|
|
1217
1272
|
primary_package_manager = install_package_managers[0]
|
|
1218
1273
|
fallbacks = install_package_managers[1:]
|
|
1219
1274
|
|
|
@@ -1224,6 +1279,7 @@ def install_frontend_packages(packages: set[str], config: Config):
|
|
|
1224
1279
|
show_status_message="Installing base frontend packages",
|
|
1225
1280
|
cwd=get_web_dir(),
|
|
1226
1281
|
shell=constants.IS_WINDOWS,
|
|
1282
|
+
env=env,
|
|
1227
1283
|
)
|
|
1228
1284
|
|
|
1229
1285
|
if config.tailwind is not None:
|
|
@@ -1241,6 +1297,7 @@ def install_frontend_packages(packages: set[str], config: Config):
|
|
|
1241
1297
|
show_status_message="Installing tailwind",
|
|
1242
1298
|
cwd=get_web_dir(),
|
|
1243
1299
|
shell=constants.IS_WINDOWS,
|
|
1300
|
+
env=env,
|
|
1244
1301
|
)
|
|
1245
1302
|
|
|
1246
1303
|
# Install custom packages defined in frontend_packages
|
|
@@ -1252,6 +1309,7 @@ def install_frontend_packages(packages: set[str], config: Config):
|
|
|
1252
1309
|
show_status_message="Installing frontend packages from config and components",
|
|
1253
1310
|
cwd=get_web_dir(),
|
|
1254
1311
|
shell=constants.IS_WINDOWS,
|
|
1312
|
+
env=env,
|
|
1255
1313
|
)
|
|
1256
1314
|
|
|
1257
1315
|
|
|
@@ -1392,6 +1450,7 @@ def ensure_reflex_installation_id() -> int | None:
|
|
|
1392
1450
|
Distinct id.
|
|
1393
1451
|
"""
|
|
1394
1452
|
try:
|
|
1453
|
+
console.debug("Ensuring reflex installation id.")
|
|
1395
1454
|
initialize_reflex_user_directory()
|
|
1396
1455
|
installation_id_file = environment.REFLEX_DIR.get() / "installation_id"
|
|
1397
1456
|
|
|
@@ -1418,6 +1477,7 @@ def ensure_reflex_installation_id() -> int | None:
|
|
|
1418
1477
|
|
|
1419
1478
|
def initialize_reflex_user_directory():
|
|
1420
1479
|
"""Initialize the reflex user directory."""
|
|
1480
|
+
console.debug(f"Creating {environment.REFLEX_DIR.get()}")
|
|
1421
1481
|
# Create the reflex directory.
|
|
1422
1482
|
path_ops.mkdir(environment.REFLEX_DIR.get())
|
|
1423
1483
|
|
|
@@ -1425,9 +1485,11 @@ def initialize_reflex_user_directory():
|
|
|
1425
1485
|
def initialize_frontend_dependencies():
|
|
1426
1486
|
"""Initialize all the frontend dependencies."""
|
|
1427
1487
|
# validate dependencies before install
|
|
1488
|
+
console.debug("Validating frontend dependencies.")
|
|
1428
1489
|
validate_frontend_dependencies()
|
|
1429
1490
|
# Install the frontend dependencies.
|
|
1430
|
-
|
|
1491
|
+
console.debug("Installing or validating bun.")
|
|
1492
|
+
install_bun()
|
|
1431
1493
|
# Set up the web directory.
|
|
1432
1494
|
initialize_web_directory()
|
|
1433
1495
|
|
|
@@ -1496,6 +1558,9 @@ def prompt_for_template_options(templates: list[Template]) -> str:
|
|
|
1496
1558
|
|
|
1497
1559
|
Returns:
|
|
1498
1560
|
The template name the user selects.
|
|
1561
|
+
|
|
1562
|
+
Raises:
|
|
1563
|
+
Exit: If the user does not select a template.
|
|
1499
1564
|
"""
|
|
1500
1565
|
# Show the user the URLs of each template to preview.
|
|
1501
1566
|
console.print("\nGet started with a template:")
|
|
@@ -1520,8 +1585,22 @@ def prompt_for_template_options(templates: list[Template]) -> str:
|
|
|
1520
1585
|
default="0",
|
|
1521
1586
|
)
|
|
1522
1587
|
|
|
1588
|
+
if not template:
|
|
1589
|
+
console.error("No template selected.")
|
|
1590
|
+
raise typer.Exit(1)
|
|
1591
|
+
|
|
1592
|
+
try:
|
|
1593
|
+
template_index = int(template)
|
|
1594
|
+
except ValueError:
|
|
1595
|
+
console.error("Invalid template selected.")
|
|
1596
|
+
raise typer.Exit(1) from None
|
|
1597
|
+
|
|
1598
|
+
if template_index < 0 or template_index >= len(templates):
|
|
1599
|
+
console.error("Invalid template selected.")
|
|
1600
|
+
raise typer.Exit(1)
|
|
1601
|
+
|
|
1523
1602
|
# Return the template.
|
|
1524
|
-
return templates[
|
|
1603
|
+
return templates[template_index].name
|
|
1525
1604
|
|
|
1526
1605
|
|
|
1527
1606
|
def fetch_app_templates(version: str) -> dict[str, Template]:
|
reflex/utils/processes.py
CHANGED
|
@@ -20,6 +20,7 @@ from rich.progress import Progress
|
|
|
20
20
|
from reflex import constants
|
|
21
21
|
from reflex.config import environment
|
|
22
22
|
from reflex.utils import console, path_ops, prerequisites
|
|
23
|
+
from reflex.utils.registry import get_npm_registry
|
|
23
24
|
|
|
24
25
|
|
|
25
26
|
def kill(pid: int):
|
|
@@ -276,6 +277,7 @@ def stream_logs(
|
|
|
276
277
|
progress: Progress | None = None,
|
|
277
278
|
suppress_errors: bool = False,
|
|
278
279
|
analytics_enabled: bool = False,
|
|
280
|
+
prior_logs: Tuple[tuple[str, ...], ...] = (),
|
|
279
281
|
):
|
|
280
282
|
"""Stream the logs for a process.
|
|
281
283
|
|
|
@@ -285,6 +287,7 @@ def stream_logs(
|
|
|
285
287
|
progress: The ongoing progress bar if one is being used.
|
|
286
288
|
suppress_errors: If True, do not exit if errors are encountered (for fallback).
|
|
287
289
|
analytics_enabled: Whether analytics are enabled for this command.
|
|
290
|
+
prior_logs: The logs of the prior processes that have been run.
|
|
288
291
|
|
|
289
292
|
Yields:
|
|
290
293
|
The lines of the process output.
|
|
@@ -312,8 +315,31 @@ def stream_logs(
|
|
|
312
315
|
accepted_return_codes = [0, -2, 15] if constants.IS_WINDOWS else [0, -2]
|
|
313
316
|
if process.returncode not in accepted_return_codes and not suppress_errors:
|
|
314
317
|
console.error(f"{message} failed with exit code {process.returncode}")
|
|
315
|
-
|
|
316
|
-
|
|
318
|
+
if "".join(logs).count("CERT_HAS_EXPIRED") > 0:
|
|
319
|
+
bunfig = prerequisites.get_web_dir() / constants.Bun.CONFIG_PATH
|
|
320
|
+
npm_registry_line = next(
|
|
321
|
+
(
|
|
322
|
+
line
|
|
323
|
+
for line in bunfig.read_text().splitlines()
|
|
324
|
+
if line.startswith("registry")
|
|
325
|
+
),
|
|
326
|
+
None,
|
|
327
|
+
)
|
|
328
|
+
if not npm_registry_line or "=" not in npm_registry_line:
|
|
329
|
+
npm_registry = get_npm_registry()
|
|
330
|
+
else:
|
|
331
|
+
npm_registry = npm_registry_line.split("=")[1].strip()
|
|
332
|
+
console.error(
|
|
333
|
+
f"Failed to fetch securely from [bold]{npm_registry}[/bold]. Please check your network connection. "
|
|
334
|
+
"You can try running the command again or changing the registry by setting the "
|
|
335
|
+
"NPM_CONFIG_REGISTRY environment variable. If TLS is the issue, and you know what "
|
|
336
|
+
"you are doing, you can disable it by setting the SSL_NO_VERIFY environment variable."
|
|
337
|
+
)
|
|
338
|
+
raise typer.Exit(1)
|
|
339
|
+
for set_of_logs in (*prior_logs, tuple(logs)):
|
|
340
|
+
for line in set_of_logs:
|
|
341
|
+
console.error(line, end="")
|
|
342
|
+
console.error("\n\n")
|
|
317
343
|
if analytics_enabled:
|
|
318
344
|
telemetry.send("error", context=message)
|
|
319
345
|
console.error("Run with [bold]--loglevel debug [/bold] for the full log.")
|
|
@@ -336,8 +362,8 @@ def show_status(
|
|
|
336
362
|
process: subprocess.Popen,
|
|
337
363
|
suppress_errors: bool = False,
|
|
338
364
|
analytics_enabled: bool = False,
|
|
339
|
-
|
|
340
|
-
):
|
|
365
|
+
prior_logs: Tuple[tuple[str, ...], ...] = (),
|
|
366
|
+
) -> list[str]:
|
|
341
367
|
"""Show the status of a process.
|
|
342
368
|
|
|
343
369
|
Args:
|
|
@@ -345,17 +371,24 @@ def show_status(
|
|
|
345
371
|
process: The process.
|
|
346
372
|
suppress_errors: If True, do not exit if errors are encountered (for fallback).
|
|
347
373
|
analytics_enabled: Whether analytics are enabled for this command.
|
|
348
|
-
|
|
374
|
+
prior_logs: The logs of the prior processes that have been run.
|
|
375
|
+
|
|
376
|
+
Returns:
|
|
377
|
+
The lines of the process output.
|
|
349
378
|
"""
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
379
|
+
lines = []
|
|
380
|
+
|
|
381
|
+
with console.status(message) as status:
|
|
382
|
+
for line in stream_logs(
|
|
383
|
+
message,
|
|
384
|
+
process,
|
|
385
|
+
suppress_errors=suppress_errors,
|
|
386
|
+
analytics_enabled=analytics_enabled,
|
|
387
|
+
prior_logs=prior_logs,
|
|
388
|
+
):
|
|
389
|
+
status.update(f"{message} {line}")
|
|
390
|
+
lines.append(line)
|
|
391
|
+
return lines
|
|
359
392
|
|
|
360
393
|
|
|
361
394
|
def show_progress(message: str, process: subprocess.Popen, checkpoints: list[str]):
|
|
@@ -409,7 +442,7 @@ def run_process_with_fallbacks(
|
|
|
409
442
|
show_status_message: str,
|
|
410
443
|
fallbacks: str | Sequence[str] | Sequence[Sequence[str]] | None = None,
|
|
411
444
|
analytics_enabled: bool = False,
|
|
412
|
-
|
|
445
|
+
prior_logs: Tuple[tuple[str, ...], ...] = (),
|
|
413
446
|
**kwargs,
|
|
414
447
|
):
|
|
415
448
|
"""Run subprocess and retry using fallback command if initial command fails.
|
|
@@ -419,7 +452,7 @@ def run_process_with_fallbacks(
|
|
|
419
452
|
show_status_message: The status message to be displayed in the console.
|
|
420
453
|
fallbacks: The fallback command to run if the initial command fails.
|
|
421
454
|
analytics_enabled: Whether analytics are enabled for this command.
|
|
422
|
-
|
|
455
|
+
prior_logs: The logs of the prior processes that have been run.
|
|
423
456
|
**kwargs: Kwargs to pass to new_process function.
|
|
424
457
|
"""
|
|
425
458
|
process = new_process(get_command_with_loglevel(args), **kwargs)
|
|
@@ -429,11 +462,11 @@ def run_process_with_fallbacks(
|
|
|
429
462
|
show_status_message,
|
|
430
463
|
process,
|
|
431
464
|
analytics_enabled=analytics_enabled,
|
|
432
|
-
|
|
465
|
+
prior_logs=prior_logs,
|
|
433
466
|
)
|
|
434
467
|
else:
|
|
435
468
|
# Suppress errors for initial command, because we will try to fallback
|
|
436
|
-
show_status(show_status_message, process, suppress_errors=True)
|
|
469
|
+
logs = show_status(show_status_message, process, suppress_errors=True)
|
|
437
470
|
|
|
438
471
|
current_fallback = fallbacks[0] if not isinstance(fallbacks, str) else fallbacks
|
|
439
472
|
next_fallbacks = fallbacks[1:] if not isinstance(fallbacks, str) else None
|
|
@@ -453,7 +486,7 @@ def run_process_with_fallbacks(
|
|
|
453
486
|
show_status_message=show_status_message,
|
|
454
487
|
fallbacks=next_fallbacks,
|
|
455
488
|
analytics_enabled=analytics_enabled,
|
|
456
|
-
|
|
489
|
+
prior_logs=(*prior_logs, tuple(logs)),
|
|
457
490
|
**kwargs,
|
|
458
491
|
)
|
|
459
492
|
|
reflex/utils/pyi_generator.py
CHANGED
|
@@ -55,6 +55,10 @@ EXCLUDED_PROPS = [
|
|
|
55
55
|
"State",
|
|
56
56
|
]
|
|
57
57
|
|
|
58
|
+
OVERWRITE_TYPES = {
|
|
59
|
+
"style": "Sequence[Mapping[str, Any]] | Mapping[str, Any] | Var[Mapping[str, Any]] | Breakpoints | None",
|
|
60
|
+
}
|
|
61
|
+
|
|
58
62
|
DEFAULT_TYPING_IMPORTS = {
|
|
59
63
|
"overload",
|
|
60
64
|
"Any",
|
|
@@ -62,6 +66,7 @@ DEFAULT_TYPING_IMPORTS = {
|
|
|
62
66
|
"Dict",
|
|
63
67
|
# "List",
|
|
64
68
|
"Sequence",
|
|
69
|
+
"Mapping",
|
|
65
70
|
"Literal",
|
|
66
71
|
"Optional",
|
|
67
72
|
"Union",
|
|
@@ -377,7 +382,9 @@ def _extract_class_props_as_ast_nodes(
|
|
|
377
382
|
ast.arg(
|
|
378
383
|
arg=name,
|
|
379
384
|
annotation=ast.Name(
|
|
380
|
-
id=
|
|
385
|
+
id=OVERWRITE_TYPES.get(
|
|
386
|
+
name, _get_type_hint(value, type_hint_globals)
|
|
387
|
+
)
|
|
381
388
|
),
|
|
382
389
|
),
|
|
383
390
|
ast.Constant(value=default),
|
|
@@ -386,7 +393,7 @@ def _extract_class_props_as_ast_nodes(
|
|
|
386
393
|
return kwargs
|
|
387
394
|
|
|
388
395
|
|
|
389
|
-
def type_to_ast(typ: Any, cls: type) -> ast.
|
|
396
|
+
def type_to_ast(typ: Any, cls: type) -> ast.expr:
|
|
390
397
|
"""Converts any type annotation into its AST representation.
|
|
391
398
|
Handles nested generic types, unions, etc.
|
|
392
399
|
|
|
@@ -439,11 +446,11 @@ def type_to_ast(typ: Any, cls: type) -> ast.AST:
|
|
|
439
446
|
if len(arg_nodes) == 1:
|
|
440
447
|
slice_value = arg_nodes[0]
|
|
441
448
|
else:
|
|
442
|
-
slice_value = ast.Tuple(elts=arg_nodes, ctx=ast.Load())
|
|
449
|
+
slice_value = ast.Tuple(elts=arg_nodes, ctx=ast.Load())
|
|
443
450
|
|
|
444
451
|
return ast.Subscript(
|
|
445
452
|
value=ast.Name(id=base_name),
|
|
446
|
-
slice=
|
|
453
|
+
slice=slice_value,
|
|
447
454
|
ctx=ast.Load(),
|
|
448
455
|
)
|
|
449
456
|
|
|
@@ -463,16 +470,18 @@ def _get_parent_imports(func: Callable):
|
|
|
463
470
|
|
|
464
471
|
|
|
465
472
|
def _generate_component_create_functiondef(
|
|
466
|
-
|
|
467
|
-
clz: type[Component] | type[SimpleNamespace],
|
|
473
|
+
clz: type[Component],
|
|
468
474
|
type_hint_globals: dict[str, Any],
|
|
475
|
+
lineno: int,
|
|
476
|
+
decorator_list: Sequence[ast.expr] = (ast.Name(id="classmethod"),),
|
|
469
477
|
) -> ast.FunctionDef:
|
|
470
478
|
"""Generate the create function definition for a Component.
|
|
471
479
|
|
|
472
480
|
Args:
|
|
473
|
-
node: The existing create functiondef node from the ast
|
|
474
481
|
clz: The Component class to generate the create functiondef for.
|
|
475
482
|
type_hint_globals: The globals to use to resolving a type hint str.
|
|
483
|
+
lineno: The line number to use for the ast nodes.
|
|
484
|
+
decorator_list: The list of decorators to apply to the create functiondef.
|
|
476
485
|
|
|
477
486
|
Returns:
|
|
478
487
|
The create functiondef node for the ast.
|
|
@@ -584,28 +593,26 @@ def _generate_component_create_functiondef(
|
|
|
584
593
|
arg=trigger,
|
|
585
594
|
annotation=ast.Subscript(
|
|
586
595
|
ast.Name("Optional"),
|
|
587
|
-
ast.
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
),
|
|
608
|
-
)
|
|
596
|
+
ast.Name(
|
|
597
|
+
id=ast.unparse(
|
|
598
|
+
figure_out_return_type(
|
|
599
|
+
inspect.signature(event_specs).return_annotation
|
|
600
|
+
)
|
|
601
|
+
if not isinstance(
|
|
602
|
+
event_specs := event_triggers[trigger], Sequence
|
|
603
|
+
)
|
|
604
|
+
else ast.Subscript(
|
|
605
|
+
ast.Name("Union"),
|
|
606
|
+
ast.Tuple(
|
|
607
|
+
[
|
|
608
|
+
figure_out_return_type(
|
|
609
|
+
inspect.signature(
|
|
610
|
+
event_spec
|
|
611
|
+
).return_annotation
|
|
612
|
+
)
|
|
613
|
+
for event_spec in event_specs
|
|
614
|
+
]
|
|
615
|
+
),
|
|
609
616
|
)
|
|
610
617
|
)
|
|
611
618
|
),
|
|
@@ -630,7 +637,7 @@ def _generate_component_create_functiondef(
|
|
|
630
637
|
definition = ast.FunctionDef( # pyright: ignore [reportCallIssue]
|
|
631
638
|
name="create",
|
|
632
639
|
args=create_args,
|
|
633
|
-
body=[
|
|
640
|
+
body=[
|
|
634
641
|
ast.Expr(
|
|
635
642
|
value=ast.Constant(
|
|
636
643
|
value=_generate_docstrings(
|
|
@@ -644,25 +651,19 @@ def _generate_component_create_functiondef(
|
|
|
644
651
|
],
|
|
645
652
|
decorator_list=[
|
|
646
653
|
ast.Name(id="overload"),
|
|
647
|
-
*
|
|
648
|
-
node.decorator_list
|
|
649
|
-
if node is not None
|
|
650
|
-
else [ast.Name(id="classmethod")]
|
|
651
|
-
),
|
|
654
|
+
*decorator_list,
|
|
652
655
|
],
|
|
653
|
-
lineno=
|
|
656
|
+
lineno=lineno,
|
|
654
657
|
returns=ast.Constant(value=clz.__name__),
|
|
655
658
|
)
|
|
656
659
|
return definition
|
|
657
660
|
|
|
658
661
|
|
|
659
662
|
def _generate_staticmethod_call_functiondef(
|
|
660
|
-
node: ast.
|
|
663
|
+
node: ast.ClassDef,
|
|
661
664
|
clz: type[Component] | type[SimpleNamespace],
|
|
662
665
|
type_hint_globals: dict[str, Any],
|
|
663
666
|
) -> ast.FunctionDef | None:
|
|
664
|
-
...
|
|
665
|
-
|
|
666
667
|
fullspec = getfullargspec(clz.__call__)
|
|
667
668
|
|
|
668
669
|
call_args = ast.arguments(
|
|
@@ -699,7 +700,7 @@ def _generate_staticmethod_call_functiondef(
|
|
|
699
700
|
),
|
|
700
701
|
],
|
|
701
702
|
decorator_list=[ast.Name(id="staticmethod")],
|
|
702
|
-
lineno=node.lineno
|
|
703
|
+
lineno=node.lineno,
|
|
703
704
|
returns=ast.Constant(
|
|
704
705
|
value=_get_type_hint(
|
|
705
706
|
typing.get_type_hints(clz.__call__).get("return", None),
|
|
@@ -712,7 +713,7 @@ def _generate_staticmethod_call_functiondef(
|
|
|
712
713
|
|
|
713
714
|
|
|
714
715
|
def _generate_namespace_call_functiondef(
|
|
715
|
-
node: ast.ClassDef
|
|
716
|
+
node: ast.ClassDef,
|
|
716
717
|
clz_name: str,
|
|
717
718
|
classes: dict[str, type[Component] | type[SimpleNamespace]],
|
|
718
719
|
type_hint_globals: dict[str, Any],
|
|
@@ -736,7 +737,7 @@ def _generate_namespace_call_functiondef(
|
|
|
736
737
|
clz = classes[clz_name]
|
|
737
738
|
|
|
738
739
|
if not hasattr(clz.__call__, "__self__"):
|
|
739
|
-
return _generate_staticmethod_call_functiondef(node, clz, type_hint_globals)
|
|
740
|
+
return _generate_staticmethod_call_functiondef(node, clz, type_hint_globals)
|
|
740
741
|
|
|
741
742
|
# Determine which class is wrapped by the namespace __call__ method
|
|
742
743
|
component_clz = clz.__call__.__self__
|
|
@@ -744,10 +745,14 @@ def _generate_namespace_call_functiondef(
|
|
|
744
745
|
if clz.__call__.__func__.__name__ != "create": # pyright: ignore [reportFunctionMemberAccess]
|
|
745
746
|
return None
|
|
746
747
|
|
|
748
|
+
if not issubclass(component_clz, Component):
|
|
749
|
+
return None
|
|
750
|
+
|
|
747
751
|
definition = _generate_component_create_functiondef(
|
|
748
|
-
|
|
749
|
-
clz=component_clz, # pyright: ignore [reportArgumentType]
|
|
752
|
+
clz=component_clz,
|
|
750
753
|
type_hint_globals=type_hint_globals,
|
|
754
|
+
lineno=node.lineno,
|
|
755
|
+
decorator_list=[],
|
|
751
756
|
)
|
|
752
757
|
definition.name = "__call__"
|
|
753
758
|
|
|
@@ -804,17 +809,18 @@ class StubGenerator(ast.NodeTransformer):
|
|
|
804
809
|
node.body.pop(0)
|
|
805
810
|
return node
|
|
806
811
|
|
|
807
|
-
def _current_class_is_component(self) ->
|
|
812
|
+
def _current_class_is_component(self) -> type[Component] | None:
|
|
808
813
|
"""Check if the current class is a Component.
|
|
809
814
|
|
|
810
815
|
Returns:
|
|
811
816
|
Whether the current class is a Component.
|
|
812
817
|
"""
|
|
813
|
-
|
|
818
|
+
if (
|
|
814
819
|
self.current_class is not None
|
|
815
820
|
and self.current_class in self.classes
|
|
816
|
-
and issubclass(self.classes[self.current_class], Component)
|
|
817
|
-
)
|
|
821
|
+
and issubclass((clz := self.classes[self.current_class]), Component)
|
|
822
|
+
):
|
|
823
|
+
return clz
|
|
818
824
|
|
|
819
825
|
def visit_Module(self, node: ast.Module) -> ast.Module:
|
|
820
826
|
"""Visit a Module node and remove docstring from body.
|
|
@@ -916,14 +922,14 @@ class StubGenerator(ast.NodeTransformer):
|
|
|
916
922
|
isinstance(child, ast.FunctionDef) and child.name == "create"
|
|
917
923
|
for child in node.body
|
|
918
924
|
)
|
|
919
|
-
and self._current_class_is_component()
|
|
925
|
+
and (clz := self._current_class_is_component()) is not None
|
|
920
926
|
):
|
|
921
927
|
# Add a new .create FunctionDef since one does not exist.
|
|
922
928
|
node.body.append(
|
|
923
929
|
_generate_component_create_functiondef(
|
|
924
|
-
|
|
925
|
-
clz=self.classes[self.current_class],
|
|
930
|
+
clz=clz,
|
|
926
931
|
type_hint_globals=self.type_hint_globals,
|
|
932
|
+
lineno=node.lineno,
|
|
927
933
|
)
|
|
928
934
|
)
|
|
929
935
|
if call_definition is not None:
|
|
@@ -949,9 +955,16 @@ class StubGenerator(ast.NodeTransformer):
|
|
|
949
955
|
Returns:
|
|
950
956
|
The modified FunctionDef node (or None).
|
|
951
957
|
"""
|
|
952
|
-
if
|
|
958
|
+
if (
|
|
959
|
+
node.name == "create"
|
|
960
|
+
and self.current_class in self.classes
|
|
961
|
+
and issubclass((clz := self.classes[self.current_class]), Component)
|
|
962
|
+
):
|
|
953
963
|
node = _generate_component_create_functiondef(
|
|
954
|
-
|
|
964
|
+
clz=clz,
|
|
965
|
+
type_hint_globals=self.type_hint_globals,
|
|
966
|
+
lineno=node.lineno,
|
|
967
|
+
decorator_list=node.decorator_list,
|
|
955
968
|
)
|
|
956
969
|
else:
|
|
957
970
|
if node.name.startswith("_") and node.name != "__call__":
|
reflex/utils/redir.py
CHANGED
|
@@ -5,6 +5,8 @@ import webbrowser
|
|
|
5
5
|
|
|
6
6
|
import httpx
|
|
7
7
|
|
|
8
|
+
from reflex.utils import net
|
|
9
|
+
|
|
8
10
|
from .. import constants
|
|
9
11
|
from . import console
|
|
10
12
|
|
|
@@ -38,7 +40,7 @@ def open_browser_and_wait(
|
|
|
38
40
|
console.info("[b]Complete the workflow in the browser to continue.[/b]")
|
|
39
41
|
while True:
|
|
40
42
|
try:
|
|
41
|
-
response =
|
|
43
|
+
response = net.get(poll_url, follow_redirects=True)
|
|
42
44
|
if response.is_success:
|
|
43
45
|
break
|
|
44
46
|
except httpx.RequestError as err:
|