reflex 0.7.3a1__py3-none-any.whl → 0.7.4__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/web/components/reflex/radix_themes_color_mode_provider.js +9 -1
- reflex/.templates/web/utils/state.js +1 -1
- reflex/app.py +21 -5
- reflex/app_mixins/middleware.py +2 -3
- reflex/base.py +3 -3
- reflex/compiler/compiler.py +68 -8
- reflex/components/component.py +6 -3
- reflex/components/core/client_side_routing.py +3 -3
- reflex/components/core/cond.py +20 -12
- reflex/components/core/upload.py +1 -1
- reflex/components/dynamic.py +2 -4
- reflex/components/lucide/icon.py +20 -27
- reflex/components/plotly/plotly.py +9 -9
- reflex/components/recharts/recharts.py +2 -2
- reflex/components/sonner/toast.py +1 -1
- reflex/config.py +23 -23
- reflex/constants/__init__.py +1 -2
- reflex/constants/base.py +3 -0
- reflex/constants/installer.py +8 -105
- reflex/custom_components/custom_components.py +8 -3
- reflex/reflex.py +22 -4
- reflex/state.py +9 -1
- reflex/testing.py +7 -1
- reflex/utils/build.py +3 -4
- reflex/utils/exec.py +156 -75
- reflex/utils/net.py +107 -18
- reflex/utils/path_ops.py +15 -25
- reflex/utils/prerequisites.py +225 -189
- reflex/utils/processes.py +70 -35
- reflex/utils/redir.py +3 -1
- reflex/utils/registry.py +16 -8
- reflex/vars/base.py +2 -38
- reflex/vars/datetime.py +10 -34
- reflex/vars/number.py +16 -112
- reflex/vars/sequence.py +99 -108
- {reflex-0.7.3a1.dist-info → reflex-0.7.4.dist-info}/METADATA +32 -23
- {reflex-0.7.3a1.dist-info → reflex-0.7.4.dist-info}/RECORD +58 -68
- {reflex-0.7.3a1.dist-info → reflex-0.7.4.dist-info}/WHEEL +1 -1
- {reflex-0.7.3a1.dist-info → reflex-0.7.4.dist-info}/entry_points.txt +0 -3
- benchmarks/__init__.py +0 -3
- benchmarks/benchmark_compile_times.py +0 -147
- benchmarks/benchmark_imports.py +0 -128
- benchmarks/benchmark_lighthouse.py +0 -75
- benchmarks/benchmark_package_size.py +0 -135
- benchmarks/benchmark_web_size.py +0 -106
- benchmarks/conftest.py +0 -20
- benchmarks/lighthouse.sh +0 -77
- benchmarks/utils.py +0 -74
- reflex/app_module_for_backend.py +0 -33
- {reflex-0.7.3a1.dist-info → reflex-0.7.4.dist-info}/licenses/LICENSE +0 -0
reflex/utils/exec.py
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
5
|
import hashlib
|
|
6
|
+
import importlib.util
|
|
6
7
|
import json
|
|
7
8
|
import os
|
|
8
9
|
import platform
|
|
@@ -19,6 +20,7 @@ from reflex import constants
|
|
|
19
20
|
from reflex.config import environment, get_config
|
|
20
21
|
from reflex.constants.base import LogLevel
|
|
21
22
|
from reflex.utils import console, path_ops
|
|
23
|
+
from reflex.utils.decorator import once
|
|
22
24
|
from reflex.utils.prerequisites import get_web_dir
|
|
23
25
|
|
|
24
26
|
# For uvicorn windows bug fix (#2335)
|
|
@@ -154,7 +156,11 @@ def run_frontend(root: Path, port: str, backend_present: bool = True):
|
|
|
154
156
|
console.rule("[bold green]App Running")
|
|
155
157
|
os.environ["PORT"] = str(get_config().frontend_port if port is None else port)
|
|
156
158
|
run_process_and_launch_url(
|
|
157
|
-
[
|
|
159
|
+
[
|
|
160
|
+
*prerequisites.get_js_package_executor(raise_on_none=True)[0],
|
|
161
|
+
"run",
|
|
162
|
+
"dev",
|
|
163
|
+
],
|
|
158
164
|
backend_present,
|
|
159
165
|
)
|
|
160
166
|
|
|
@@ -176,18 +182,35 @@ def run_frontend_prod(root: Path, port: str, backend_present: bool = True):
|
|
|
176
182
|
# Run the frontend in production mode.
|
|
177
183
|
console.rule("[bold green]App Running")
|
|
178
184
|
run_process_and_launch_url(
|
|
179
|
-
[prerequisites.
|
|
185
|
+
[*prerequisites.get_js_package_executor(raise_on_none=True)[0], "run", "prod"],
|
|
180
186
|
backend_present,
|
|
181
187
|
)
|
|
182
188
|
|
|
183
189
|
|
|
190
|
+
@once
|
|
191
|
+
def _warn_user_about_uvicorn():
|
|
192
|
+
# When we eventually switch to Granian by default, we should enable this warning.
|
|
193
|
+
if False:
|
|
194
|
+
console.warn(
|
|
195
|
+
"Using Uvicorn for backend as it is installed. This behavior will change in 0.8.0 to use Granian by default."
|
|
196
|
+
)
|
|
197
|
+
|
|
198
|
+
|
|
184
199
|
def should_use_granian():
|
|
185
200
|
"""Whether to use Granian for backend.
|
|
186
201
|
|
|
187
202
|
Returns:
|
|
188
203
|
True if Granian should be used.
|
|
189
204
|
"""
|
|
190
|
-
|
|
205
|
+
if environment.REFLEX_USE_GRANIAN.get():
|
|
206
|
+
return True
|
|
207
|
+
if (
|
|
208
|
+
importlib.util.find_spec("uvicorn") is None
|
|
209
|
+
or importlib.util.find_spec("gunicorn") is None
|
|
210
|
+
):
|
|
211
|
+
return True
|
|
212
|
+
_warn_user_about_uvicorn()
|
|
213
|
+
return False
|
|
191
214
|
|
|
192
215
|
|
|
193
216
|
def get_app_module():
|
|
@@ -196,22 +219,9 @@ def get_app_module():
|
|
|
196
219
|
Returns:
|
|
197
220
|
The app module for the backend.
|
|
198
221
|
"""
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
def get_granian_target():
|
|
203
|
-
"""Get the Granian target for the backend.
|
|
204
|
-
|
|
205
|
-
Returns:
|
|
206
|
-
The Granian target for the backend.
|
|
207
|
-
"""
|
|
208
|
-
import reflex
|
|
209
|
-
|
|
210
|
-
app_module_path = Path(reflex.__file__).parent / "app_module_for_backend.py"
|
|
222
|
+
config = get_config()
|
|
211
223
|
|
|
212
|
-
return
|
|
213
|
-
f"{app_module_path!s}:{constants.CompileVars.APP}.{constants.CompileVars.API}"
|
|
214
|
-
)
|
|
224
|
+
return f"{config.module}:{constants.CompileVars.APP}"
|
|
215
225
|
|
|
216
226
|
|
|
217
227
|
def run_backend(
|
|
@@ -313,7 +323,8 @@ def run_uvicorn_backend(host: str, port: int, loglevel: LogLevel):
|
|
|
313
323
|
import uvicorn
|
|
314
324
|
|
|
315
325
|
uvicorn.run(
|
|
316
|
-
app=f"{get_app_module()}
|
|
326
|
+
app=f"{get_app_module()}",
|
|
327
|
+
factory=True,
|
|
317
328
|
host=host,
|
|
318
329
|
port=port,
|
|
319
330
|
log_level=loglevel.value,
|
|
@@ -331,36 +342,91 @@ def run_granian_backend(host: str, port: int, loglevel: LogLevel):
|
|
|
331
342
|
loglevel: The log level.
|
|
332
343
|
"""
|
|
333
344
|
console.debug("Using Granian for backend")
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
345
|
+
|
|
346
|
+
from granian.constants import Interfaces
|
|
347
|
+
from granian.log import LogLevels
|
|
348
|
+
from granian.server import MPServer as Granian
|
|
349
|
+
|
|
350
|
+
Granian(
|
|
351
|
+
target=get_app_module(),
|
|
352
|
+
factory=True,
|
|
353
|
+
address=host,
|
|
354
|
+
port=port,
|
|
355
|
+
interface=Interfaces.ASGI,
|
|
356
|
+
log_level=LogLevels(loglevel.value),
|
|
357
|
+
reload=True,
|
|
358
|
+
reload_paths=get_reload_paths(),
|
|
359
|
+
).serve()
|
|
360
|
+
|
|
361
|
+
|
|
362
|
+
def _deprecate_asgi_config(
|
|
363
|
+
config_name: str,
|
|
364
|
+
reason: str = "",
|
|
365
|
+
):
|
|
366
|
+
# When we eventually switch to Granian by default, we should enable this deprecation.
|
|
367
|
+
if False:
|
|
368
|
+
console.deprecate(
|
|
369
|
+
f"config.{config_name}",
|
|
370
|
+
reason=reason,
|
|
371
|
+
deprecation_version="0.7.5",
|
|
372
|
+
removal_version="0.8.0",
|
|
351
373
|
)
|
|
352
|
-
os._exit(1)
|
|
353
374
|
|
|
354
375
|
|
|
376
|
+
@once
|
|
355
377
|
def _get_backend_workers():
|
|
356
378
|
from reflex.utils import processes
|
|
357
379
|
|
|
358
380
|
config = get_config()
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
381
|
+
|
|
382
|
+
gunicorn_workers = config.gunicorn_workers or 0
|
|
383
|
+
|
|
384
|
+
if config.gunicorn_workers is not None:
|
|
385
|
+
_deprecate_asgi_config(
|
|
386
|
+
"gunicorn_workers",
|
|
387
|
+
"If you're using Granian, use GRANIAN_WORKERS instead.",
|
|
388
|
+
)
|
|
389
|
+
|
|
390
|
+
return gunicorn_workers if gunicorn_workers else processes.get_num_workers()
|
|
391
|
+
|
|
392
|
+
|
|
393
|
+
@once
|
|
394
|
+
def _get_backend_timeout():
|
|
395
|
+
config = get_config()
|
|
396
|
+
|
|
397
|
+
timeout = config.timeout or 120
|
|
398
|
+
|
|
399
|
+
if config.timeout is not None:
|
|
400
|
+
_deprecate_asgi_config(
|
|
401
|
+
"timeout",
|
|
402
|
+
"If you're using Granian, use GRANIAN_WORKERS_LIFETIME instead.",
|
|
403
|
+
)
|
|
404
|
+
|
|
405
|
+
return timeout
|
|
406
|
+
|
|
407
|
+
|
|
408
|
+
@once
|
|
409
|
+
def _get_backend_max_requests():
|
|
410
|
+
config = get_config()
|
|
411
|
+
|
|
412
|
+
gunicorn_max_requests = config.gunicorn_max_requests or 120
|
|
413
|
+
|
|
414
|
+
if config.gunicorn_max_requests is not None:
|
|
415
|
+
_deprecate_asgi_config("gunicorn_max_requests")
|
|
416
|
+
|
|
417
|
+
return gunicorn_max_requests
|
|
418
|
+
|
|
419
|
+
|
|
420
|
+
@once
|
|
421
|
+
def _get_backend_max_requests_jitter():
|
|
422
|
+
config = get_config()
|
|
423
|
+
|
|
424
|
+
gunicorn_max_requests_jitter = config.gunicorn_max_requests_jitter or 25
|
|
425
|
+
|
|
426
|
+
if config.gunicorn_max_requests_jitter is not None:
|
|
427
|
+
_deprecate_asgi_config("gunicorn_max_requests_jitter")
|
|
428
|
+
|
|
429
|
+
return gunicorn_max_requests_jitter
|
|
364
430
|
|
|
365
431
|
|
|
366
432
|
def run_backend_prod(
|
|
@@ -404,17 +470,25 @@ def run_uvicorn_backend_prod(host: str, port: int, loglevel: LogLevel):
|
|
|
404
470
|
[
|
|
405
471
|
"uvicorn",
|
|
406
472
|
*(
|
|
407
|
-
|
|
473
|
+
(
|
|
408
474
|
"--limit-max-requests",
|
|
409
|
-
str(
|
|
410
|
-
|
|
411
|
-
if
|
|
412
|
-
|
|
475
|
+
str(max_requessts),
|
|
476
|
+
)
|
|
477
|
+
if (
|
|
478
|
+
(max_requessts := _get_backend_max_requests()) is not None
|
|
479
|
+
and max_requessts > 0
|
|
480
|
+
)
|
|
481
|
+
else ()
|
|
482
|
+
),
|
|
483
|
+
*(
|
|
484
|
+
("--timeout-keep-alive", str(timeout))
|
|
485
|
+
if (timeout := _get_backend_timeout()) is not None
|
|
486
|
+
else ()
|
|
413
487
|
),
|
|
414
|
-
*("--timeout-keep-alive", str(config.timeout)),
|
|
415
488
|
*("--host", host),
|
|
416
489
|
*("--port", str(port)),
|
|
417
490
|
*("--workers", str(_get_backend_workers())),
|
|
491
|
+
"--factory",
|
|
418
492
|
app_module,
|
|
419
493
|
]
|
|
420
494
|
if constants.IS_WINDOWS
|
|
@@ -422,17 +496,34 @@ def run_uvicorn_backend_prod(host: str, port: int, loglevel: LogLevel):
|
|
|
422
496
|
"gunicorn",
|
|
423
497
|
*("--worker-class", config.gunicorn_worker_class),
|
|
424
498
|
*(
|
|
425
|
-
|
|
499
|
+
(
|
|
426
500
|
"--max-requests",
|
|
427
|
-
str(
|
|
501
|
+
str(max_requessts),
|
|
502
|
+
)
|
|
503
|
+
if (
|
|
504
|
+
(max_requessts := _get_backend_max_requests()) is not None
|
|
505
|
+
and max_requessts > 0
|
|
506
|
+
)
|
|
507
|
+
else ()
|
|
508
|
+
),
|
|
509
|
+
*(
|
|
510
|
+
(
|
|
428
511
|
"--max-requests-jitter",
|
|
429
|
-
str(
|
|
430
|
-
|
|
431
|
-
if
|
|
432
|
-
|
|
512
|
+
str(max_requessts_jitter),
|
|
513
|
+
)
|
|
514
|
+
if (
|
|
515
|
+
(max_requessts_jitter := _get_backend_max_requests_jitter())
|
|
516
|
+
is not None
|
|
517
|
+
and max_requessts_jitter > 0
|
|
518
|
+
)
|
|
519
|
+
else ()
|
|
433
520
|
),
|
|
434
521
|
"--preload",
|
|
435
|
-
*(
|
|
522
|
+
*(
|
|
523
|
+
("--timeout", str(timeout))
|
|
524
|
+
if (timeout := _get_backend_timeout()) is not None
|
|
525
|
+
else ()
|
|
526
|
+
),
|
|
436
527
|
*("--bind", f"{host}:{port}"),
|
|
437
528
|
*("--threads", str(_get_backend_workers())),
|
|
438
529
|
f"{app_module}()",
|
|
@@ -468,17 +559,12 @@ def run_granian_backend_prod(host: str, port: int, loglevel: LogLevel):
|
|
|
468
559
|
|
|
469
560
|
command = [
|
|
470
561
|
"granian",
|
|
471
|
-
"--workers",
|
|
472
|
-
|
|
473
|
-
"--
|
|
474
|
-
"
|
|
475
|
-
"--
|
|
476
|
-
|
|
477
|
-
"--port",
|
|
478
|
-
str(port),
|
|
479
|
-
"--interface",
|
|
480
|
-
str(Interfaces.ASGI),
|
|
481
|
-
get_granian_target(),
|
|
562
|
+
*("--workers", str(_get_backend_workers())),
|
|
563
|
+
*("--log-level", "critical"),
|
|
564
|
+
*("--host", host),
|
|
565
|
+
*("--port", str(port)),
|
|
566
|
+
*("--interface", str(Interfaces.ASGI)),
|
|
567
|
+
*("--factory", get_app_module()),
|
|
482
568
|
]
|
|
483
569
|
processes.new_process(
|
|
484
570
|
command,
|
|
@@ -518,13 +604,8 @@ def output_system_info():
|
|
|
518
604
|
|
|
519
605
|
system = platform.system()
|
|
520
606
|
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
dependencies.extend(
|
|
524
|
-
[
|
|
525
|
-
fnm_info,
|
|
526
|
-
f"[Bun {prerequisites.get_bun_version()} (Expected: {constants.Bun.VERSION}) (PATH: {path_ops.get_bun_path()})]",
|
|
527
|
-
],
|
|
607
|
+
dependencies.append(
|
|
608
|
+
f"[Bun {prerequisites.get_bun_version()} (Expected: {constants.Bun.VERSION}) (PATH: {path_ops.get_bun_path()})]"
|
|
528
609
|
)
|
|
529
610
|
|
|
530
611
|
if system == "Linux":
|
|
@@ -540,10 +621,10 @@ def output_system_info():
|
|
|
540
621
|
console.debug(f"{dep}")
|
|
541
622
|
|
|
542
623
|
console.debug(
|
|
543
|
-
f"Using package installer at: {prerequisites.
|
|
624
|
+
f"Using package installer at: {prerequisites.get_nodejs_compatible_package_managers(raise_on_none=False)}"
|
|
544
625
|
)
|
|
545
626
|
console.debug(
|
|
546
|
-
f"Using package executer at: {prerequisites.
|
|
627
|
+
f"Using package executer at: {prerequisites.get_js_package_executor(raise_on_none=False)}"
|
|
547
628
|
)
|
|
548
629
|
if system != "Windows":
|
|
549
630
|
console.debug(f"Unzip path: {path_ops.which('unzip')}")
|
reflex/utils/net.py
CHANGED
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
"""Helpers for downloading files from the network."""
|
|
2
2
|
|
|
3
|
+
import functools
|
|
4
|
+
import time
|
|
5
|
+
from typing import Callable, ParamSpec, TypeVar
|
|
6
|
+
|
|
3
7
|
import httpx
|
|
4
8
|
|
|
5
|
-
from
|
|
9
|
+
from reflex.utils.decorator import once
|
|
10
|
+
|
|
6
11
|
from . import console
|
|
7
12
|
|
|
8
13
|
|
|
@@ -12,30 +17,114 @@ def _httpx_verify_kwarg() -> bool:
|
|
|
12
17
|
Returns:
|
|
13
18
|
True if SSL verification is enabled, False otherwise
|
|
14
19
|
"""
|
|
20
|
+
from ..config import environment
|
|
21
|
+
|
|
15
22
|
return not environment.SSL_NO_VERIFY.get()
|
|
16
23
|
|
|
17
24
|
|
|
18
|
-
|
|
19
|
-
|
|
25
|
+
_P = ParamSpec("_P")
|
|
26
|
+
_T = TypeVar("_T")
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def _wrap_https_func(
|
|
30
|
+
func: Callable[_P, _T],
|
|
31
|
+
) -> Callable[_P, _T]:
|
|
32
|
+
"""Wrap an HTTPS function with logging.
|
|
20
33
|
|
|
21
34
|
Args:
|
|
22
|
-
|
|
23
|
-
**kwargs: Additional keyword arguments to pass to httpx.get.
|
|
35
|
+
func: The function to wrap.
|
|
24
36
|
|
|
25
37
|
Returns:
|
|
26
|
-
The
|
|
38
|
+
The wrapped function.
|
|
39
|
+
"""
|
|
40
|
+
|
|
41
|
+
@functools.wraps(func)
|
|
42
|
+
def wrapper(*args: _P.args, **kwargs: _P.kwargs) -> _T:
|
|
43
|
+
url = args[0]
|
|
44
|
+
console.debug(f"Sending HTTPS request to {args[0]}")
|
|
45
|
+
initial_time = time.time()
|
|
46
|
+
try:
|
|
47
|
+
response = func(*args, **kwargs)
|
|
48
|
+
except httpx.ConnectError as err:
|
|
49
|
+
if "CERTIFICATE_VERIFY_FAILED" in str(err):
|
|
50
|
+
# If the error is a certificate verification error, recommend mitigating steps.
|
|
51
|
+
console.error(
|
|
52
|
+
f"Certificate verification failed for {url}. Set environment variable SSL_CERT_FILE to the "
|
|
53
|
+
"path of the certificate file or SSL_NO_VERIFY=1 to disable verification."
|
|
54
|
+
)
|
|
55
|
+
raise
|
|
56
|
+
else:
|
|
57
|
+
console.debug(
|
|
58
|
+
f"Received response from {url} in {time.time() - initial_time:.3f} seconds"
|
|
59
|
+
)
|
|
60
|
+
return response
|
|
61
|
+
|
|
62
|
+
return wrapper
|
|
63
|
+
|
|
27
64
|
|
|
28
|
-
|
|
29
|
-
|
|
65
|
+
def _is_ipv4_supported() -> bool:
|
|
66
|
+
"""Determine if the system supports IPv4.
|
|
67
|
+
|
|
68
|
+
Returns:
|
|
69
|
+
True if the system supports IPv4, False otherwise.
|
|
30
70
|
"""
|
|
31
|
-
kwargs.setdefault("verify", _httpx_verify_kwarg())
|
|
32
71
|
try:
|
|
33
|
-
|
|
34
|
-
except httpx.
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
72
|
+
httpx.head("http://1.1.1.1", timeout=3)
|
|
73
|
+
except httpx.RequestError:
|
|
74
|
+
return False
|
|
75
|
+
else:
|
|
76
|
+
return True
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def _is_ipv6_supported() -> bool:
|
|
80
|
+
"""Determine if the system supports IPv6.
|
|
81
|
+
|
|
82
|
+
Returns:
|
|
83
|
+
True if the system supports IPv6, False otherwise.
|
|
84
|
+
"""
|
|
85
|
+
try:
|
|
86
|
+
httpx.head("http://[2606:4700:4700::1111]", timeout=3)
|
|
87
|
+
except httpx.RequestError:
|
|
88
|
+
return False
|
|
89
|
+
else:
|
|
90
|
+
return True
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def _should_use_ipv6() -> bool:
|
|
94
|
+
"""Determine if the system supports IPv6.
|
|
95
|
+
|
|
96
|
+
Returns:
|
|
97
|
+
True if the system supports IPv6, False otherwise.
|
|
98
|
+
"""
|
|
99
|
+
return not _is_ipv4_supported() and _is_ipv6_supported()
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def _httpx_local_address_kwarg() -> str:
|
|
103
|
+
"""Get the value of the HTTPX local_address keyword argument.
|
|
104
|
+
|
|
105
|
+
Returns:
|
|
106
|
+
The local address to bind to
|
|
107
|
+
"""
|
|
108
|
+
from ..config import environment
|
|
109
|
+
|
|
110
|
+
return environment.REFLEX_HTTP_CLIENT_BIND_ADDRESS.get() or (
|
|
111
|
+
"::" if _should_use_ipv6() else "0.0.0.0"
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
@once
|
|
116
|
+
def _httpx_client() -> httpx.Client:
|
|
117
|
+
"""Get an HTTPX client.
|
|
118
|
+
|
|
119
|
+
Returns:
|
|
120
|
+
An HTTPX client.
|
|
121
|
+
"""
|
|
122
|
+
return httpx.Client(
|
|
123
|
+
transport=httpx.HTTPTransport(
|
|
124
|
+
local_address=_httpx_local_address_kwarg(),
|
|
125
|
+
verify=_httpx_verify_kwarg(),
|
|
126
|
+
)
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
get = _wrap_https_func(_httpx_client().get)
|
reflex/utils/path_ops.py
CHANGED
|
@@ -9,7 +9,6 @@ import shutil
|
|
|
9
9
|
import stat
|
|
10
10
|
from pathlib import Path
|
|
11
11
|
|
|
12
|
-
from reflex import constants
|
|
13
12
|
from reflex.config import environment, get_config
|
|
14
13
|
|
|
15
14
|
# Shorthand for join.
|
|
@@ -43,13 +42,19 @@ def rm(path: str | Path):
|
|
|
43
42
|
path.unlink()
|
|
44
43
|
|
|
45
44
|
|
|
46
|
-
def cp(
|
|
45
|
+
def cp(
|
|
46
|
+
src: str | Path,
|
|
47
|
+
dest: str | Path,
|
|
48
|
+
overwrite: bool = True,
|
|
49
|
+
ignore: tuple[str, ...] | None = None,
|
|
50
|
+
) -> bool:
|
|
47
51
|
"""Copy a file or directory.
|
|
48
52
|
|
|
49
53
|
Args:
|
|
50
54
|
src: The path to the file or directory.
|
|
51
55
|
dest: The path to the destination.
|
|
52
56
|
overwrite: Whether to overwrite the destination.
|
|
57
|
+
ignore: Ignoring files and directories that match one of the glob-style patterns provided
|
|
53
58
|
|
|
54
59
|
Returns:
|
|
55
60
|
Whether the copy was successful.
|
|
@@ -61,7 +66,11 @@ def cp(src: str | Path, dest: str | Path, overwrite: bool = True) -> bool:
|
|
|
61
66
|
return False
|
|
62
67
|
if src.is_dir():
|
|
63
68
|
rm(dest)
|
|
64
|
-
shutil.copytree(
|
|
69
|
+
shutil.copytree(
|
|
70
|
+
src,
|
|
71
|
+
dest,
|
|
72
|
+
ignore=shutil.ignore_patterns(*ignore) if ignore is not None else ignore,
|
|
73
|
+
)
|
|
65
74
|
else:
|
|
66
75
|
shutil.copyfile(src, dest)
|
|
67
76
|
return True
|
|
@@ -146,15 +155,6 @@ def which(program: str | Path) -> Path | None:
|
|
|
146
155
|
return Path(which_result) if which_result else None
|
|
147
156
|
|
|
148
157
|
|
|
149
|
-
def use_system_node() -> bool:
|
|
150
|
-
"""Check if the system node should be used.
|
|
151
|
-
|
|
152
|
-
Returns:
|
|
153
|
-
Whether the system node should be used.
|
|
154
|
-
"""
|
|
155
|
-
return environment.REFLEX_USE_SYSTEM_NODE.get()
|
|
156
|
-
|
|
157
|
-
|
|
158
158
|
def use_system_bun() -> bool:
|
|
159
159
|
"""Check if the system bun should be used.
|
|
160
160
|
|
|
@@ -170,11 +170,7 @@ def get_node_bin_path() -> Path | None:
|
|
|
170
170
|
Returns:
|
|
171
171
|
The path to the node bin folder.
|
|
172
172
|
"""
|
|
173
|
-
bin_path
|
|
174
|
-
if not bin_path.exists():
|
|
175
|
-
path = which("node")
|
|
176
|
-
return path.parent.absolute() if path else None
|
|
177
|
-
return bin_path.absolute()
|
|
173
|
+
return bin_path.parent.absolute() if (bin_path := get_node_path()) else None
|
|
178
174
|
|
|
179
175
|
|
|
180
176
|
def get_node_path() -> Path | None:
|
|
@@ -183,10 +179,7 @@ def get_node_path() -> Path | None:
|
|
|
183
179
|
Returns:
|
|
184
180
|
The path to the node binary file.
|
|
185
181
|
"""
|
|
186
|
-
|
|
187
|
-
if use_system_node() or not node_path.exists():
|
|
188
|
-
node_path = which("node")
|
|
189
|
-
return node_path
|
|
182
|
+
return which("node")
|
|
190
183
|
|
|
191
184
|
|
|
192
185
|
def get_npm_path() -> Path | None:
|
|
@@ -195,10 +188,7 @@ def get_npm_path() -> Path | None:
|
|
|
195
188
|
Returns:
|
|
196
189
|
The path to the npm binary file.
|
|
197
190
|
"""
|
|
198
|
-
npm_path
|
|
199
|
-
if use_system_node() or not npm_path.exists():
|
|
200
|
-
npm_path = which("npm")
|
|
201
|
-
return npm_path.absolute() if npm_path else None
|
|
191
|
+
return npm_path.absolute() if (npm_path := which("npm")) else None
|
|
202
192
|
|
|
203
193
|
|
|
204
194
|
def get_bun_path() -> Path | None:
|