reflex 0.7.3a2__py3-none-any.whl → 0.7.4a0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of reflex might be problematic. Click here for more details.
- reflex/app.py +1 -1
- reflex/compiler/compiler.py +61 -4
- reflex/components/core/upload.py +1 -1
- reflex/components/plotly/plotly.py +9 -9
- reflex/components/recharts/recharts.py +2 -2
- reflex/components/sonner/toast.py +1 -1
- reflex/config.py +2 -5
- reflex/constants/__init__.py +1 -2
- reflex/constants/base.py +3 -0
- reflex/constants/installer.py +8 -105
- reflex/state.py +8 -1
- reflex/testing.py +7 -1
- reflex/utils/build.py +3 -4
- reflex/utils/exec.py +10 -11
- reflex/utils/path_ops.py +15 -25
- reflex/utils/prerequisites.py +113 -181
- reflex/utils/processes.py +21 -18
- reflex/utils/registry.py +5 -5
- {reflex-0.7.3a2.dist-info → reflex-0.7.4a0.dist-info}/METADATA +1 -1
- {reflex-0.7.3a2.dist-info → reflex-0.7.4a0.dist-info}/RECORD +23 -23
- {reflex-0.7.3a2.dist-info → reflex-0.7.4a0.dist-info}/WHEEL +0 -0
- {reflex-0.7.3a2.dist-info → reflex-0.7.4a0.dist-info}/entry_points.txt +0 -0
- {reflex-0.7.3a2.dist-info → reflex-0.7.4a0.dist-info}/licenses/LICENSE +0 -0
reflex/utils/prerequisites.py
CHANGED
|
@@ -14,7 +14,6 @@ import platform
|
|
|
14
14
|
import random
|
|
15
15
|
import re
|
|
16
16
|
import shutil
|
|
17
|
-
import stat
|
|
18
17
|
import sys
|
|
19
18
|
import tempfile
|
|
20
19
|
import time
|
|
@@ -23,7 +22,7 @@ import zipfile
|
|
|
23
22
|
from datetime import datetime
|
|
24
23
|
from pathlib import Path
|
|
25
24
|
from types import ModuleType
|
|
26
|
-
from typing import Callable, NamedTuple
|
|
25
|
+
from typing import Callable, NamedTuple, Sequence
|
|
27
26
|
from urllib.parse import urlparse
|
|
28
27
|
|
|
29
28
|
import httpx
|
|
@@ -43,13 +42,11 @@ from reflex.utils.exceptions import (
|
|
|
43
42
|
SystemPackageMissingError,
|
|
44
43
|
)
|
|
45
44
|
from reflex.utils.format import format_library_name
|
|
46
|
-
from reflex.utils.registry import
|
|
45
|
+
from reflex.utils.registry import get_npm_registry
|
|
47
46
|
|
|
48
47
|
if typing.TYPE_CHECKING:
|
|
49
48
|
from reflex.app import App
|
|
50
49
|
|
|
51
|
-
CURRENTLY_INSTALLING_NODE = False
|
|
52
|
-
|
|
53
50
|
|
|
54
51
|
class AppInfo(NamedTuple):
|
|
55
52
|
"""A tuple containing the app instance and module."""
|
|
@@ -191,24 +188,6 @@ def get_node_version() -> version.Version | None:
|
|
|
191
188
|
return None
|
|
192
189
|
|
|
193
190
|
|
|
194
|
-
def get_fnm_version() -> version.Version | None:
|
|
195
|
-
"""Get the version of fnm.
|
|
196
|
-
|
|
197
|
-
Returns:
|
|
198
|
-
The version of FNM.
|
|
199
|
-
"""
|
|
200
|
-
try:
|
|
201
|
-
result = processes.new_process([constants.Fnm.EXE, "--version"], run=True)
|
|
202
|
-
return version.parse(result.stdout.split(" ")[1]) # pyright: ignore [reportOptionalMemberAccess, reportAttributeAccessIssue]
|
|
203
|
-
except (FileNotFoundError, TypeError):
|
|
204
|
-
return None
|
|
205
|
-
except version.InvalidVersion as e:
|
|
206
|
-
console.warn(
|
|
207
|
-
f"The detected fnm version ({e.args[0]}) is not valid. Defaulting to None."
|
|
208
|
-
)
|
|
209
|
-
return None
|
|
210
|
-
|
|
211
|
-
|
|
212
191
|
def get_bun_version() -> version.Version | None:
|
|
213
192
|
"""Get the version of bun.
|
|
214
193
|
|
|
@@ -231,42 +210,107 @@ def get_bun_version() -> version.Version | None:
|
|
|
231
210
|
return None
|
|
232
211
|
|
|
233
212
|
|
|
234
|
-
def
|
|
235
|
-
"""
|
|
236
|
-
|
|
213
|
+
def prefer_npm_over_bun() -> bool:
|
|
214
|
+
"""Check if npm should be preferred over bun.
|
|
215
|
+
|
|
216
|
+
Returns:
|
|
217
|
+
If npm should be preferred over bun.
|
|
218
|
+
"""
|
|
219
|
+
return npm_escape_hatch() or (
|
|
220
|
+
constants.IS_WINDOWS and windows_check_onedrive_in_path()
|
|
221
|
+
)
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
def get_nodejs_compatible_package_managers(
|
|
225
|
+
raise_on_none: bool = True,
|
|
226
|
+
) -> Sequence[str]:
|
|
227
|
+
"""Get the package manager executable for installation. Typically, bun is used for installation.
|
|
237
228
|
|
|
238
229
|
Args:
|
|
239
|
-
|
|
230
|
+
raise_on_none: Whether to raise an error if the package manager is not found.
|
|
240
231
|
|
|
241
232
|
Returns:
|
|
242
233
|
The path to the package manager.
|
|
234
|
+
|
|
235
|
+
Raises:
|
|
236
|
+
FileNotFoundError: If the package manager is not found and raise_on_none is True.
|
|
243
237
|
"""
|
|
244
|
-
|
|
245
|
-
|
|
238
|
+
bun_package_manager = (
|
|
239
|
+
str(bun_path) if (bun_path := path_ops.get_bun_path()) else None
|
|
240
|
+
)
|
|
241
|
+
|
|
242
|
+
npm_package_manager = (
|
|
243
|
+
str(npm_path) if (npm_path := path_ops.get_npm_path()) else None
|
|
244
|
+
)
|
|
245
|
+
|
|
246
|
+
if prefer_npm_over_bun():
|
|
247
|
+
package_managers = [npm_package_manager, bun_package_manager]
|
|
248
|
+
else:
|
|
249
|
+
package_managers = [bun_package_manager, npm_package_manager]
|
|
250
|
+
|
|
251
|
+
package_managers = list(filter(None, package_managers))
|
|
252
|
+
|
|
253
|
+
if not package_managers and not raise_on_none:
|
|
254
|
+
raise FileNotFoundError(
|
|
255
|
+
"Bun or npm not found. You might need to rerun `reflex init` or install either."
|
|
256
|
+
)
|
|
257
|
+
|
|
258
|
+
return package_managers
|
|
259
|
+
|
|
260
|
+
|
|
261
|
+
def is_outdated_nodejs_installed():
|
|
262
|
+
"""Check if the installed Node.js version is outdated.
|
|
263
|
+
|
|
264
|
+
Returns:
|
|
265
|
+
If the installed Node.js version is outdated.
|
|
266
|
+
"""
|
|
267
|
+
current_version = get_node_version()
|
|
268
|
+
if current_version is not None and current_version < version.parse(
|
|
269
|
+
constants.Node.MIN_VERSION
|
|
246
270
|
):
|
|
247
|
-
|
|
248
|
-
|
|
271
|
+
console.warn(
|
|
272
|
+
f"Your version ({current_version}) of Node.js is out of date. Upgrade to {constants.Node.MIN_VERSION} or higher."
|
|
273
|
+
)
|
|
274
|
+
return True
|
|
275
|
+
return False
|
|
249
276
|
|
|
250
277
|
|
|
251
|
-
def
|
|
252
|
-
"""Get the package
|
|
253
|
-
|
|
278
|
+
def get_js_package_executor(raise_on_none: bool = False) -> Sequence[Sequence[str]]:
|
|
279
|
+
"""Get the paths to package managers for running commands. Ordered by preference.
|
|
280
|
+
This is currently identical to get_install_package_managers, but may change in the future.
|
|
254
281
|
|
|
255
282
|
Args:
|
|
256
|
-
|
|
283
|
+
raise_on_none: Whether to raise an error if no package managers is not found.
|
|
257
284
|
|
|
258
285
|
Returns:
|
|
259
|
-
The
|
|
286
|
+
The paths to the package managers as a list of lists, where each list is the command to run and its arguments.
|
|
260
287
|
|
|
261
288
|
Raises:
|
|
262
|
-
FileNotFoundError: If
|
|
289
|
+
FileNotFoundError: If no package managers are found and raise_on_none is True.
|
|
263
290
|
"""
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
291
|
+
bun_package_manager = (
|
|
292
|
+
[str(bun_path)] + (["--bun"] if is_outdated_nodejs_installed() else [])
|
|
293
|
+
if (bun_path := path_ops.get_bun_path())
|
|
294
|
+
else None
|
|
295
|
+
)
|
|
296
|
+
|
|
297
|
+
npm_package_manager = (
|
|
298
|
+
[str(npm_path)] if (npm_path := path_ops.get_npm_path()) else None
|
|
299
|
+
)
|
|
300
|
+
|
|
301
|
+
if prefer_npm_over_bun():
|
|
302
|
+
package_managers = [npm_package_manager, bun_package_manager]
|
|
303
|
+
else:
|
|
304
|
+
package_managers = [bun_package_manager, npm_package_manager]
|
|
305
|
+
|
|
306
|
+
package_managers = list(filter(None, package_managers))
|
|
307
|
+
|
|
308
|
+
if not package_managers and raise_on_none:
|
|
309
|
+
raise FileNotFoundError(
|
|
310
|
+
"Bun or npm not found. You might need to rerun `reflex init` or install either."
|
|
311
|
+
)
|
|
312
|
+
|
|
313
|
+
return package_managers
|
|
270
314
|
|
|
271
315
|
|
|
272
316
|
def windows_check_onedrive_in_path() -> bool:
|
|
@@ -278,8 +322,8 @@ def windows_check_onedrive_in_path() -> bool:
|
|
|
278
322
|
return "onedrive" in str(Path.cwd()).lower()
|
|
279
323
|
|
|
280
324
|
|
|
281
|
-
def
|
|
282
|
-
"""
|
|
325
|
+
def npm_escape_hatch() -> bool:
|
|
326
|
+
"""If the user sets REFLEX_USE_NPM, prefer npm over bun.
|
|
283
327
|
|
|
284
328
|
Returns:
|
|
285
329
|
If the user has set REFLEX_USE_NPM.
|
|
@@ -862,7 +906,7 @@ def initialize_bun_config():
|
|
|
862
906
|
bunfig_content = custom_bunfig.read_text()
|
|
863
907
|
console.info(f"Copying custom bunfig.toml inside {get_web_dir()} folder")
|
|
864
908
|
else:
|
|
865
|
-
best_registry =
|
|
909
|
+
best_registry = get_npm_registry()
|
|
866
910
|
bunfig_content = constants.Bun.DEFAULT_CONFIG.format(registry=best_registry)
|
|
867
911
|
|
|
868
912
|
bun_config_path.write_text(bunfig_content)
|
|
@@ -970,92 +1014,6 @@ def download_and_run(url: str, *args, show_status: bool = False, **env):
|
|
|
970
1014
|
show(f"Installing {url}", process)
|
|
971
1015
|
|
|
972
1016
|
|
|
973
|
-
def download_and_extract_fnm_zip():
|
|
974
|
-
"""Download and run a script.
|
|
975
|
-
|
|
976
|
-
Raises:
|
|
977
|
-
Exit: If an error occurs while downloading or extracting the FNM zip.
|
|
978
|
-
"""
|
|
979
|
-
# Download the zip file
|
|
980
|
-
url = constants.Fnm.INSTALL_URL
|
|
981
|
-
console.debug(f"Downloading {url}")
|
|
982
|
-
fnm_zip_file: Path = constants.Fnm.DIR / f"{constants.Fnm.FILENAME}.zip"
|
|
983
|
-
# Function to download and extract the FNM zip release.
|
|
984
|
-
try:
|
|
985
|
-
# Download the FNM zip release.
|
|
986
|
-
# TODO: show progress to improve UX
|
|
987
|
-
response = net.get(url, follow_redirects=True)
|
|
988
|
-
response.raise_for_status()
|
|
989
|
-
with fnm_zip_file.open("wb") as output_file:
|
|
990
|
-
for chunk in response.iter_bytes():
|
|
991
|
-
output_file.write(chunk)
|
|
992
|
-
|
|
993
|
-
# Extract the downloaded zip file.
|
|
994
|
-
with zipfile.ZipFile(fnm_zip_file, "r") as zip_ref:
|
|
995
|
-
zip_ref.extractall(constants.Fnm.DIR)
|
|
996
|
-
|
|
997
|
-
console.debug("FNM package downloaded and extracted successfully.")
|
|
998
|
-
except Exception as e:
|
|
999
|
-
console.error(f"An error occurred while downloading fnm package: {e}")
|
|
1000
|
-
raise typer.Exit(1) from e
|
|
1001
|
-
finally:
|
|
1002
|
-
# Clean up the downloaded zip file.
|
|
1003
|
-
path_ops.rm(fnm_zip_file)
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
def install_node():
|
|
1007
|
-
"""Install fnm and nodejs for use by Reflex.
|
|
1008
|
-
Independent of any existing system installations.
|
|
1009
|
-
"""
|
|
1010
|
-
if not constants.Fnm.FILENAME:
|
|
1011
|
-
# fnm only support Linux, macOS and Windows distros.
|
|
1012
|
-
console.debug("")
|
|
1013
|
-
return
|
|
1014
|
-
|
|
1015
|
-
# Skip installation if check_node_version() checks out
|
|
1016
|
-
if check_node_version():
|
|
1017
|
-
console.debug("Skipping node installation as it is already installed.")
|
|
1018
|
-
return
|
|
1019
|
-
|
|
1020
|
-
path_ops.mkdir(constants.Fnm.DIR)
|
|
1021
|
-
if not constants.Fnm.EXE.exists():
|
|
1022
|
-
download_and_extract_fnm_zip()
|
|
1023
|
-
|
|
1024
|
-
if constants.IS_WINDOWS:
|
|
1025
|
-
# Install node
|
|
1026
|
-
fnm_exe = Path(constants.Fnm.EXE).resolve()
|
|
1027
|
-
fnm_dir = Path(constants.Fnm.DIR).resolve()
|
|
1028
|
-
process = processes.new_process(
|
|
1029
|
-
[
|
|
1030
|
-
"powershell",
|
|
1031
|
-
"-Command",
|
|
1032
|
-
f'& "{fnm_exe}" install {constants.Node.VERSION} --fnm-dir "{fnm_dir}"',
|
|
1033
|
-
],
|
|
1034
|
-
)
|
|
1035
|
-
else: # All other platforms (Linux, MacOS).
|
|
1036
|
-
# Add execute permissions to fnm executable.
|
|
1037
|
-
constants.Fnm.EXE.chmod(stat.S_IXUSR)
|
|
1038
|
-
# Install node.
|
|
1039
|
-
# Specify arm64 arch explicitly for M1s and M2s.
|
|
1040
|
-
architecture_arg = (
|
|
1041
|
-
["--arch=arm64"]
|
|
1042
|
-
if platform.system() == "Darwin" and platform.machine() == "arm64"
|
|
1043
|
-
else []
|
|
1044
|
-
)
|
|
1045
|
-
|
|
1046
|
-
process = processes.new_process(
|
|
1047
|
-
[
|
|
1048
|
-
constants.Fnm.EXE,
|
|
1049
|
-
"install",
|
|
1050
|
-
*architecture_arg,
|
|
1051
|
-
constants.Node.VERSION,
|
|
1052
|
-
"--fnm-dir",
|
|
1053
|
-
constants.Fnm.DIR,
|
|
1054
|
-
],
|
|
1055
|
-
)
|
|
1056
|
-
processes.show_status("Installing node", process)
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
1017
|
def install_bun():
|
|
1060
1018
|
"""Install bun onto the user's system.
|
|
1061
1019
|
|
|
@@ -1069,7 +1027,9 @@ def install_bun():
|
|
|
1069
1027
|
)
|
|
1070
1028
|
|
|
1071
1029
|
# Skip if bun is already installed.
|
|
1072
|
-
if get_bun_version()
|
|
1030
|
+
if (current_version := get_bun_version()) and current_version >= version.parse(
|
|
1031
|
+
constants.Bun.MIN_VERSION
|
|
1032
|
+
):
|
|
1073
1033
|
console.debug("Skipping bun installation as it is already installed.")
|
|
1074
1034
|
return
|
|
1075
1035
|
|
|
@@ -1157,38 +1117,19 @@ def install_frontend_packages(packages: set[str], config: Config):
|
|
|
1157
1117
|
packages: A list of package names to be installed.
|
|
1158
1118
|
config: The config object.
|
|
1159
1119
|
|
|
1160
|
-
Raises:
|
|
1161
|
-
FileNotFoundError: If the package manager is not found.
|
|
1162
|
-
|
|
1163
1120
|
Example:
|
|
1164
1121
|
>>> install_frontend_packages(["react", "react-dom"], get_config())
|
|
1165
1122
|
"""
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
get_package_manager(on_failure_return_none=True)
|
|
1169
|
-
if (
|
|
1170
|
-
not constants.IS_WINDOWS
|
|
1171
|
-
or (constants.IS_WINDOWS and not windows_check_onedrive_in_path())
|
|
1172
|
-
)
|
|
1173
|
-
else None
|
|
1123
|
+
install_package_managers = get_nodejs_compatible_package_managers(
|
|
1124
|
+
raise_on_none=True
|
|
1174
1125
|
)
|
|
1175
1126
|
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
)
|
|
1179
|
-
|
|
1180
|
-
if install_package_manager is None:
|
|
1181
|
-
raise FileNotFoundError(
|
|
1182
|
-
"Could not find a package manager to install frontend packages. You may need to run `reflex init`."
|
|
1183
|
-
)
|
|
1184
|
-
|
|
1185
|
-
fallback_command = (
|
|
1186
|
-
fallback_command if fallback_command is not install_package_manager else None
|
|
1187
|
-
)
|
|
1127
|
+
primary_package_manager = install_package_managers[0]
|
|
1128
|
+
fallbacks = install_package_managers[1:]
|
|
1188
1129
|
|
|
1189
|
-
processes.
|
|
1190
|
-
[
|
|
1191
|
-
|
|
1130
|
+
processes.run_process_with_fallbacks(
|
|
1131
|
+
[primary_package_manager, "install", "--legacy-peer-deps"],
|
|
1132
|
+
fallbacks=fallbacks,
|
|
1192
1133
|
analytics_enabled=True,
|
|
1193
1134
|
show_status_message="Installing base frontend packages",
|
|
1194
1135
|
cwd=get_web_dir(),
|
|
@@ -1196,16 +1137,16 @@ def install_frontend_packages(packages: set[str], config: Config):
|
|
|
1196
1137
|
)
|
|
1197
1138
|
|
|
1198
1139
|
if config.tailwind is not None:
|
|
1199
|
-
processes.
|
|
1140
|
+
processes.run_process_with_fallbacks(
|
|
1200
1141
|
[
|
|
1201
|
-
|
|
1142
|
+
primary_package_manager,
|
|
1202
1143
|
"add",
|
|
1203
1144
|
"--legacy-peer-deps",
|
|
1204
1145
|
"-d",
|
|
1205
1146
|
constants.Tailwind.VERSION,
|
|
1206
1147
|
*((config.tailwind or {}).get("plugins", [])),
|
|
1207
1148
|
],
|
|
1208
|
-
|
|
1149
|
+
fallbacks=fallbacks,
|
|
1209
1150
|
analytics_enabled=True,
|
|
1210
1151
|
show_status_message="Installing tailwind",
|
|
1211
1152
|
cwd=get_web_dir(),
|
|
@@ -1214,9 +1155,9 @@ def install_frontend_packages(packages: set[str], config: Config):
|
|
|
1214
1155
|
|
|
1215
1156
|
# Install custom packages defined in frontend_packages
|
|
1216
1157
|
if len(packages) > 0:
|
|
1217
|
-
processes.
|
|
1218
|
-
[
|
|
1219
|
-
|
|
1158
|
+
processes.run_process_with_fallbacks(
|
|
1159
|
+
[primary_package_manager, "add", "--legacy-peer-deps", *packages],
|
|
1160
|
+
fallbacks=fallbacks,
|
|
1220
1161
|
analytics_enabled=True,
|
|
1221
1162
|
show_status_message="Installing frontend packages from config and components",
|
|
1222
1163
|
cwd=get_web_dir(),
|
|
@@ -1338,24 +1279,19 @@ def validate_frontend_dependencies(init: bool = True):
|
|
|
1338
1279
|
Exit: If the package manager is invalid.
|
|
1339
1280
|
"""
|
|
1340
1281
|
if not init:
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
console.error(
|
|
1346
|
-
"Could not find NPM package manager. Make sure you have node installed."
|
|
1347
|
-
)
|
|
1348
|
-
raise typer.Exit(1)
|
|
1282
|
+
try:
|
|
1283
|
+
get_js_package_executor(raise_on_none=True)
|
|
1284
|
+
except FileNotFoundError as e:
|
|
1285
|
+
raise typer.Exit(1) from e
|
|
1349
1286
|
|
|
1287
|
+
if prefer_npm_over_bun():
|
|
1350
1288
|
if not check_node_version():
|
|
1351
1289
|
node_version = get_node_version()
|
|
1352
1290
|
console.error(
|
|
1353
1291
|
f"Reflex requires node version {constants.Node.MIN_VERSION} or higher to run, but the detected version is {node_version}",
|
|
1354
1292
|
)
|
|
1355
1293
|
raise typer.Exit(1)
|
|
1356
|
-
|
|
1357
|
-
if init:
|
|
1358
|
-
# we only need bun for package install on `reflex init`.
|
|
1294
|
+
else:
|
|
1359
1295
|
validate_bun()
|
|
1360
1296
|
|
|
1361
1297
|
|
|
@@ -1400,12 +1336,8 @@ def initialize_frontend_dependencies():
|
|
|
1400
1336
|
"""Initialize all the frontend dependencies."""
|
|
1401
1337
|
# validate dependencies before install
|
|
1402
1338
|
validate_frontend_dependencies()
|
|
1403
|
-
# Avoid warning about Node installation while we're trying to install it.
|
|
1404
|
-
global CURRENTLY_INSTALLING_NODE
|
|
1405
|
-
CURRENTLY_INSTALLING_NODE = True
|
|
1406
1339
|
# Install the frontend dependencies.
|
|
1407
|
-
processes.run_concurrently(
|
|
1408
|
-
CURRENTLY_INSTALLING_NODE = False
|
|
1340
|
+
processes.run_concurrently(install_bun)
|
|
1409
1341
|
# Set up the web directory.
|
|
1410
1342
|
initialize_web_directory()
|
|
1411
1343
|
|
reflex/utils/processes.py
CHANGED
|
@@ -10,7 +10,7 @@ import signal
|
|
|
10
10
|
import subprocess
|
|
11
11
|
from concurrent import futures
|
|
12
12
|
from pathlib import Path
|
|
13
|
-
from typing import Callable, Generator, Tuple
|
|
13
|
+
from typing import Callable, Generator, Sequence, Tuple
|
|
14
14
|
|
|
15
15
|
import psutil
|
|
16
16
|
import typer
|
|
@@ -171,14 +171,9 @@ def new_process(
|
|
|
171
171
|
|
|
172
172
|
# Add node_bin_path to the PATH environment variable.
|
|
173
173
|
if not environment.REFLEX_BACKEND_ONLY.get():
|
|
174
|
-
node_bin_path =
|
|
175
|
-
if
|
|
176
|
-
|
|
177
|
-
"The path to the Node binary could not be found. Please ensure that Node is properly "
|
|
178
|
-
"installed and added to your system's PATH environment variable or try running "
|
|
179
|
-
"`reflex init` again."
|
|
180
|
-
)
|
|
181
|
-
path_env = os.pathsep.join([node_bin_path, path_env])
|
|
174
|
+
node_bin_path = path_ops.get_node_bin_path()
|
|
175
|
+
if node_bin_path:
|
|
176
|
+
path_env = os.pathsep.join([str(node_bin_path), path_env])
|
|
182
177
|
|
|
183
178
|
env: dict[str, str] = {
|
|
184
179
|
**os.environ,
|
|
@@ -380,11 +375,11 @@ def get_command_with_loglevel(command: list[str]) -> list[str]:
|
|
|
380
375
|
return command
|
|
381
376
|
|
|
382
377
|
|
|
383
|
-
def
|
|
378
|
+
def run_process_with_fallbacks(
|
|
384
379
|
args: list[str],
|
|
385
380
|
*,
|
|
386
381
|
show_status_message: str,
|
|
387
|
-
|
|
382
|
+
fallbacks: str | Sequence[str] | Sequence[Sequence[str]] | None = None,
|
|
388
383
|
analytics_enabled: bool = False,
|
|
389
384
|
**kwargs,
|
|
390
385
|
):
|
|
@@ -393,12 +388,12 @@ def run_process_with_fallback(
|
|
|
393
388
|
Args:
|
|
394
389
|
args: A string, or a sequence of program arguments.
|
|
395
390
|
show_status_message: The status message to be displayed in the console.
|
|
396
|
-
|
|
391
|
+
fallbacks: The fallback command to run if the initial command fails.
|
|
397
392
|
analytics_enabled: Whether analytics are enabled for this command.
|
|
398
393
|
kwargs: Kwargs to pass to new_process function.
|
|
399
394
|
"""
|
|
400
395
|
process = new_process(get_command_with_loglevel(args), **kwargs)
|
|
401
|
-
if
|
|
396
|
+
if not fallbacks:
|
|
402
397
|
# No fallback given, or this _is_ the fallback command.
|
|
403
398
|
show_status(
|
|
404
399
|
show_status_message,
|
|
@@ -408,16 +403,24 @@ def run_process_with_fallback(
|
|
|
408
403
|
else:
|
|
409
404
|
# Suppress errors for initial command, because we will try to fallback
|
|
410
405
|
show_status(show_status_message, process, suppress_errors=True)
|
|
406
|
+
|
|
407
|
+
current_fallback = fallbacks[0] if not isinstance(fallbacks, str) else fallbacks
|
|
408
|
+
next_fallbacks = fallbacks[1:] if not isinstance(fallbacks, str) else None
|
|
409
|
+
|
|
411
410
|
if process.returncode != 0:
|
|
412
411
|
# retry with fallback command.
|
|
413
|
-
|
|
412
|
+
fallback_with_args = (
|
|
413
|
+
[current_fallback, *args[1:]]
|
|
414
|
+
if isinstance(fallbacks, str)
|
|
415
|
+
else [*current_fallback, *args[1:]]
|
|
416
|
+
)
|
|
414
417
|
console.warn(
|
|
415
|
-
f"There was an error running command: {args}. Falling back to: {
|
|
418
|
+
f"There was an error running command: {args}. Falling back to: {fallback_with_args}."
|
|
416
419
|
)
|
|
417
|
-
|
|
418
|
-
|
|
420
|
+
run_process_with_fallbacks(
|
|
421
|
+
fallback_with_args,
|
|
419
422
|
show_status_message=show_status_message,
|
|
420
|
-
|
|
423
|
+
fallbacks=next_fallbacks,
|
|
421
424
|
analytics_enabled=analytics_enabled,
|
|
422
425
|
**kwargs,
|
|
423
426
|
)
|
reflex/utils/registry.py
CHANGED
|
@@ -35,11 +35,11 @@ def average_latency(registry: str, attempts: int = 3) -> int:
|
|
|
35
35
|
return sum(latency(registry) for _ in range(attempts)) // attempts
|
|
36
36
|
|
|
37
37
|
|
|
38
|
-
def
|
|
38
|
+
def _get_best_registry() -> str:
|
|
39
39
|
"""Get the best registry based on latency.
|
|
40
40
|
|
|
41
41
|
Returns:
|
|
42
|
-
|
|
42
|
+
The best registry.
|
|
43
43
|
"""
|
|
44
44
|
registries = [
|
|
45
45
|
"https://registry.npmjs.org",
|
|
@@ -49,10 +49,10 @@ def get_best_registry() -> str:
|
|
|
49
49
|
return min(registries, key=average_latency)
|
|
50
50
|
|
|
51
51
|
|
|
52
|
-
def
|
|
52
|
+
def get_npm_registry() -> str:
|
|
53
53
|
"""Get npm registry. If environment variable is set, use it first.
|
|
54
54
|
|
|
55
55
|
Returns:
|
|
56
|
-
|
|
56
|
+
The npm registry.
|
|
57
57
|
"""
|
|
58
|
-
return environment.NPM_CONFIG_REGISTRY.get() or
|
|
58
|
+
return environment.NPM_CONFIG_REGISTRY.get() or _get_best_registry()
|