reflex 0.7.4a1__py3-none-any.whl → 0.7.4a3__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.

@@ -1,5 +1,5 @@
1
1
  import { useTheme } from "next-themes";
2
- import { useEffect, useState } from "react";
2
+ import { useRef, useEffect, useState } from "react";
3
3
  import {
4
4
  ColorModeContext,
5
5
  defaultColorMode,
@@ -13,6 +13,14 @@ export default function RadixThemesColorModeProvider({ children }) {
13
13
  const [resolvedColorMode, setResolvedColorMode] = useState(
14
14
  defaultColorMode === "dark" ? "dark" : "light",
15
15
  );
16
+ const firstUpdate = useRef(true);
17
+ useEffect(() => {
18
+ if (firstUpdate.current) {
19
+ firstUpdate.current = false;
20
+ setRawColorMode(theme);
21
+ setResolvedColorMode(resolvedTheme);
22
+ }
23
+ });
16
24
 
17
25
  useEffect(() => {
18
26
  if (isDevMode) {
reflex/app.py CHANGED
@@ -968,7 +968,7 @@ class App(MiddlewareMixin, LifespanMixin):
968
968
  # Check the nocompile file.
969
969
  if nocompile.exists():
970
970
  # Delete the nocompile file
971
- nocompile.unlink()
971
+ nocompile.unlink(missing_ok=True)
972
972
  return False
973
973
 
974
974
  # By default, compile the app.
@@ -1108,8 +1108,6 @@ class App(MiddlewareMixin, LifespanMixin):
1108
1108
  if config.react_strict_mode:
1109
1109
  app_wrappers[(200, "StrictMode")] = StrictMode.create()
1110
1110
 
1111
- should_compile = self._should_compile()
1112
-
1113
1111
  if not should_compile:
1114
1112
  with console.timing("Evaluate Pages (Backend)"):
1115
1113
  for route in self._unevaluated_pages:
@@ -1258,7 +1256,9 @@ class App(MiddlewareMixin, LifespanMixin):
1258
1256
  compiler.compile_document_root(
1259
1257
  self.head_components,
1260
1258
  html_lang=self.html_lang,
1261
- html_custom_attrs=self.html_custom_attrs, # pyright: ignore [reportArgumentType]
1259
+ html_custom_attrs=(
1260
+ {**self.html_custom_attrs} if self.html_custom_attrs else {}
1261
+ ),
1262
1262
  )
1263
1263
  )
1264
1264
 
reflex/base.py CHANGED
@@ -38,7 +38,7 @@ def validate_field_name(bases: list[Type["BaseModel"]], field_name: str) -> None
38
38
 
39
39
  # monkeypatch pydantic validate_field_name method to skip validating
40
40
  # shadowed state vars when reloading app via utils.prerequisites.get_app(reload=True)
41
- pydantic_main.validate_field_name = validate_field_name # pyright: ignore [reportPossiblyUnboundVariable, reportPrivateImportUsage]
41
+ pydantic_main.validate_field_name = validate_field_name # pyright: ignore [reportPrivateImportUsage]
42
42
 
43
43
  if TYPE_CHECKING:
44
44
  from reflex.vars import Var
@@ -107,7 +107,7 @@ class Base(BaseModel):
107
107
  default_value: The default value of the field
108
108
  """
109
109
  var_name = var._var_field_name
110
- new_field = ModelField.infer( # pyright: ignore [reportPossiblyUnboundVariable]
110
+ new_field = ModelField.infer(
111
111
  name=var_name,
112
112
  value=default_value,
113
113
  annotation=var._var_type,
@@ -128,5 +128,5 @@ class Base(BaseModel):
128
128
  if isinstance(key, str):
129
129
  # Seems like this function signature was wrong all along?
130
130
  # If the user wants a field that we know of, get it and pass it off to _get_value
131
- return getattr(self, key, key)
131
+ return getattr(self, key)
132
132
  return key
@@ -20,6 +20,7 @@ from reflex.config import environment, get_config
20
20
  from reflex.state import BaseState
21
21
  from reflex.style import SYSTEM_COLOR_MODE
22
22
  from reflex.utils import console, path_ops
23
+ from reflex.utils.exceptions import ReflexError
23
24
  from reflex.utils.exec import is_prod_mode
24
25
  from reflex.utils.imports import ImportVar
25
26
  from reflex.utils.prerequisites import get_web_dir
@@ -651,6 +652,8 @@ def into_component(component: Component | ComponentCallable) -> Component:
651
652
  ):
652
653
  return converted
653
654
  except KeyError as e:
655
+ if isinstance(e, ReflexError):
656
+ raise
654
657
  key = e.args[0] if e.args else None
655
658
  if key is not None and isinstance(key, Var):
656
659
  raise TypeError(
@@ -658,6 +661,8 @@ def into_component(component: Component | ComponentCallable) -> Component:
658
661
  ).with_traceback(e.__traceback__) from None
659
662
  raise
660
663
  except TypeError as e:
664
+ if isinstance(e, ReflexError):
665
+ raise
661
666
  message = e.args[0] if e.args else None
662
667
  if message and isinstance(message, str):
663
668
  if message.endswith("has no len()") and (
@@ -2,6 +2,7 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
+ import contextlib
5
6
  import copy
6
7
  import dataclasses
7
8
  import functools
@@ -1974,13 +1975,15 @@ class NoSSRComponent(Component):
1974
1975
  # Do NOT import the main library/tag statically.
1975
1976
  import_name = self._get_import_name()
1976
1977
  if import_name is not None:
1977
- _imports[import_name] = [
1978
+ with contextlib.suppress(ValueError):
1979
+ _imports[import_name].remove(self.import_var)
1980
+ _imports[import_name].append(
1978
1981
  imports.ImportVar(
1979
1982
  tag=None,
1980
1983
  render=False,
1981
1984
  transpile=self._should_transpile(self.library),
1982
- ),
1983
- ]
1985
+ )
1986
+ )
1984
1987
 
1985
1988
  return imports.merge_imports(
1986
1989
  dynamic_import,
reflex/config.py CHANGED
@@ -44,7 +44,7 @@ from reflex.utils.types import (
44
44
  )
45
45
 
46
46
  try:
47
- from dotenv import load_dotenv # pyright: ignore [reportMissingImports]
47
+ from dotenv import load_dotenv
48
48
  except ImportError:
49
49
  load_dotenv = None
50
50
 
@@ -720,6 +720,9 @@ class EnvironmentVariables:
720
720
  # Used by flexgen to enumerate the pages.
721
721
  REFLEX_ADD_ALL_ROUTES_ENDPOINT: EnvVar[bool] = env_var(False)
722
722
 
723
+ # The address to bind the HTTP client to. You can set this to "::" to enable IPv6.
724
+ REFLEX_HTTP_CLIENT_BIND_ADDRESS: EnvVar[str | None] = env_var(None)
725
+
723
726
 
724
727
  environment = EnvironmentVariables()
725
728
 
reflex/reflex.py CHANGED
@@ -205,18 +205,22 @@ def _run(
205
205
  prerequisites.check_latest_package_version(constants.Reflex.MODULE_NAME)
206
206
 
207
207
  # Get the app module.
208
- app_task = prerequisites.compile_app if frontend else prerequisites.validate_app
208
+ app_task = prerequisites.compile_or_validate_app
209
+ args = (frontend,)
209
210
 
210
211
  # Granian fails if the app is already imported.
211
212
  if should_use_granian():
212
213
  import concurrent.futures
213
214
 
214
215
  compile_future = concurrent.futures.ProcessPoolExecutor(max_workers=1).submit(
215
- app_task
216
+ app_task,
217
+ *args,
216
218
  )
217
- compile_future.result()
219
+ validation_result = compile_future.result()
218
220
  else:
219
- app_task()
221
+ validation_result = app_task(*args)
222
+ if not validation_result:
223
+ raise typer.Exit(1)
220
224
 
221
225
  # Warn if schema is not up to date.
222
226
  prerequisites.check_schema_up_to_date()
reflex/state.py CHANGED
@@ -907,7 +907,7 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
907
907
  raise ValueError(f"Only one parent state is allowed {parent_states}.")
908
908
  # The first non-mixin state in the mro is our parent.
909
909
  for base in cls.mro()[1:]:
910
- if base._mixin or not issubclass(base, BaseState):
910
+ if not issubclass(base, BaseState) or base._mixin:
911
911
  continue
912
912
  if base is BaseState:
913
913
  break
reflex/utils/exec.py CHANGED
@@ -189,9 +189,11 @@ def run_frontend_prod(root: Path, port: str, backend_present: bool = True):
189
189
 
190
190
  @once
191
191
  def _warn_user_about_uvicorn():
192
- console.warn(
193
- "Using Uvicorn for backend as it is installed. This behavior will change in 0.8.0 to use Granian by default."
194
- )
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
+ )
195
197
 
196
198
 
197
199
  def should_use_granian():
@@ -357,70 +359,74 @@ def run_granian_backend(host: str, port: int, loglevel: LogLevel):
357
359
  ).serve()
358
360
 
359
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",
373
+ )
374
+
375
+
360
376
  @once
361
377
  def _get_backend_workers():
362
378
  from reflex.utils import processes
363
379
 
364
380
  config = get_config()
365
381
 
382
+ gunicorn_workers = config.gunicorn_workers or 0
383
+
366
384
  if config.gunicorn_workers is not None:
367
- console.deprecate(
368
- "config.gunicorn_workers",
369
- reason="If you're using Granian, use GRANIAN_WORKERS instead.",
370
- deprecation_version="0.7.4",
371
- removal_version="0.8.0",
385
+ _deprecate_asgi_config(
386
+ "gunicorn_workers",
387
+ "If you're using Granian, use GRANIAN_WORKERS instead.",
372
388
  )
373
389
 
374
- return (
375
- processes.get_num_workers()
376
- if not config.gunicorn_workers
377
- else config.gunicorn_workers
378
- )
390
+ return gunicorn_workers if gunicorn_workers else processes.get_num_workers()
379
391
 
380
392
 
381
393
  @once
382
394
  def _get_backend_timeout():
383
395
  config = get_config()
384
396
 
397
+ timeout = config.timeout or 120
398
+
385
399
  if config.timeout is not None:
386
- console.deprecate(
387
- "config.timeout",
388
- reason="If you're using Granian, use GRANIAN_WORKERS_LIFETIME instead.",
389
- deprecation_version="0.7.4",
390
- removal_version="0.8.0",
400
+ _deprecate_asgi_config(
401
+ "timeout",
402
+ "If you're using Granian, use GRANIAN_WORKERS_LIFETIME instead.",
391
403
  )
392
404
 
393
- return config.timeout
405
+ return timeout
394
406
 
395
407
 
396
408
  @once
397
409
  def _get_backend_max_requests():
398
410
  config = get_config()
399
411
 
412
+ gunicorn_max_requests = config.gunicorn_max_requests or 120
413
+
400
414
  if config.gunicorn_max_requests is not None:
401
- console.deprecate(
402
- "config.gunicorn_max_requests",
403
- reason="",
404
- deprecation_version="0.7.4",
405
- removal_version="0.8.0",
406
- )
415
+ _deprecate_asgi_config("gunicorn_max_requests")
407
416
 
408
- return config.gunicorn_max_requests
417
+ return gunicorn_max_requests
409
418
 
410
419
 
411
420
  @once
412
421
  def _get_backend_max_requests_jitter():
413
422
  config = get_config()
414
423
 
424
+ gunicorn_max_requests_jitter = config.gunicorn_max_requests_jitter or 25
425
+
415
426
  if config.gunicorn_max_requests_jitter is not None:
416
- console.deprecate(
417
- "config.gunicorn_max_requests_jitter",
418
- reason="",
419
- deprecation_version="0.7.4",
420
- removal_version="0.8.0",
421
- )
427
+ _deprecate_asgi_config("gunicorn_max_requests_jitter")
422
428
 
423
- return config.gunicorn_max_requests_jitter
429
+ return gunicorn_max_requests_jitter
424
430
 
425
431
 
426
432
  def run_backend_prod(
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 ..config import environment
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
- def get(url: str, **kwargs) -> httpx.Response:
19
- """Make an HTTP GET request.
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
- url: The URL to request.
23
- **kwargs: Additional keyword arguments to pass to httpx.get.
35
+ func: The function to wrap.
24
36
 
25
37
  Returns:
26
- The response object.
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
- Raises:
29
- httpx.ConnectError: If the connection cannot be established.
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
- return httpx.get(url, **kwargs)
34
- except httpx.ConnectError as err:
35
- if "CERTIFICATE_VERIFY_FAILED" in str(err):
36
- # If the error is a certificate verification error, recommend mitigating steps.
37
- console.error(
38
- f"Certificate verification failed for {url}. Set environment variable SSL_CERT_FILE to the "
39
- "path of the certificate file or SSL_NO_VERIFY=1 to disable verification."
40
- )
41
- raise
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)
@@ -8,6 +8,7 @@ import functools
8
8
  import importlib
9
9
  import importlib.metadata
10
10
  import importlib.util
11
+ import io
11
12
  import json
12
13
  import os
13
14
  import platform
@@ -114,11 +115,13 @@ def check_latest_package_version(package_name: str):
114
115
  if environment.REFLEX_CHECK_LATEST_VERSION.get() is False:
115
116
  return
116
117
  try:
118
+ console.debug(f"Checking for the latest version of {package_name}...")
117
119
  # Get the latest version from PyPI
118
120
  current_version = importlib.metadata.version(package_name)
119
121
  url = f"https://pypi.org/pypi/{package_name}/json"
120
122
  response = net.get(url)
121
123
  latest_version = response.json()["info"]["version"]
124
+ console.debug(f"Latest version of {package_name}: {latest_version}")
122
125
  if get_or_set_last_reflex_version_check_datetime():
123
126
  # Versions were already checked and saved in reflex.json, no need to warn again
124
127
  return
@@ -128,6 +131,7 @@ def check_latest_package_version(package_name: str):
128
131
  f"Your version ({current_version}) of {package_name} is out of date. Upgrade to {latest_version} with 'pip install {package_name} --upgrade'"
129
132
  )
130
133
  except Exception:
134
+ console.debug(f"Failed to check for the latest version of {package_name}.")
131
135
  pass
132
136
 
133
137
 
@@ -183,7 +187,7 @@ def get_node_version() -> version.Version | None:
183
187
  try:
184
188
  result = processes.new_process([node_path, "-v"], run=True)
185
189
  # The output will be in the form "vX.Y.Z", but version.parse() can handle it
186
- return version.parse(result.stdout) # pyright: ignore [reportArgumentType]
190
+ return version.parse(result.stdout)
187
191
  except (FileNotFoundError, TypeError):
188
192
  return None
189
193
 
@@ -200,7 +204,7 @@ def get_bun_version() -> version.Version | None:
200
204
  try:
201
205
  # Run the bun -v command and capture the output
202
206
  result = processes.new_process([str(bun_path), "-v"], run=True)
203
- return version.parse(str(result.stdout)) # pyright: ignore [reportArgumentType]
207
+ return version.parse(str(result.stdout))
204
208
  except FileNotFoundError:
205
209
  return None
206
210
  except version.InvalidVersion as e:
@@ -449,6 +453,76 @@ def compile_app(reload: bool = False, export: bool = False) -> None:
449
453
  get_compiled_app(reload=reload, export=export)
450
454
 
451
455
 
456
+ def _can_colorize() -> bool:
457
+ """Check if the output can be colorized.
458
+
459
+ Copied from _colorize.can_colorize.
460
+
461
+ https://raw.githubusercontent.com/python/cpython/refs/heads/main/Lib/_colorize.py
462
+
463
+ Returns:
464
+ If the output can be colorized
465
+ """
466
+ file = sys.stdout
467
+
468
+ if not sys.flags.ignore_environment:
469
+ if os.environ.get("PYTHON_COLORS") == "0":
470
+ return False
471
+ if os.environ.get("PYTHON_COLORS") == "1":
472
+ return True
473
+ if os.environ.get("NO_COLOR"):
474
+ return False
475
+ if os.environ.get("FORCE_COLOR"):
476
+ return True
477
+ if os.environ.get("TERM") == "dumb":
478
+ return False
479
+
480
+ if not hasattr(file, "fileno"):
481
+ return False
482
+
483
+ if sys.platform == "win32":
484
+ try:
485
+ import nt
486
+
487
+ if not nt._supports_virtual_terminal():
488
+ return False
489
+ except (ImportError, AttributeError):
490
+ return False
491
+
492
+ try:
493
+ return os.isatty(file.fileno())
494
+ except io.UnsupportedOperation:
495
+ return file.isatty()
496
+
497
+
498
+ def compile_or_validate_app(compile: bool = False) -> bool:
499
+ """Compile or validate the app module based on the default config.
500
+
501
+ Args:
502
+ compile: Whether to compile the app.
503
+
504
+ Returns:
505
+ If the app is compiled successfully.
506
+ """
507
+ try:
508
+ if compile:
509
+ compile_app()
510
+ else:
511
+ validate_app()
512
+ except Exception as e:
513
+ import traceback
514
+
515
+ sys_exception = sys.exception()
516
+
517
+ try:
518
+ colorize = _can_colorize()
519
+ traceback.print_exception(e, colorize=colorize) # pyright: ignore[reportCallIssue]
520
+ except Exception:
521
+ traceback.print_exception(sys_exception)
522
+ return False
523
+ return True
524
+
525
+
452
526
  def get_redis() -> Redis | None:
453
527
  """Get the asynchronous redis client.
454
528
 
@@ -831,11 +905,12 @@ def initialize_app_directory(
831
905
 
832
906
  console.debug(f"Using {template_name=} {template_dir=} {template_code_dir_name=}.")
833
907
 
834
- # Remove all pyc and __pycache__ dirs in template directory.
835
- for pyc_file in template_dir.glob("**/*.pyc"):
836
- pyc_file.unlink()
837
- for pycache_dir in template_dir.glob("**/__pycache__"):
838
- pycache_dir.rmdir()
908
+ # Remove __pycache__ dirs in template directory and current directory.
909
+ for pycache_dir in [
910
+ *template_dir.glob("**/__pycache__"),
911
+ *Path.cwd().glob("**/__pycache__"),
912
+ ]:
913
+ shutil.rmtree(pycache_dir, ignore_errors=True)
839
914
 
840
915
  for file in template_dir.iterdir():
841
916
  # Copy the file to current directory but keep the name the same.
@@ -879,16 +954,22 @@ def initialize_web_directory():
879
954
  # Reuse the hash if one is already created, so we don't over-write it when running reflex init
880
955
  project_hash = get_project_hash()
881
956
 
957
+ console.debug(f"Copying {constants.Templates.Dirs.WEB_TEMPLATE} to {get_web_dir()}")
882
958
  path_ops.cp(constants.Templates.Dirs.WEB_TEMPLATE, str(get_web_dir()))
883
959
 
960
+ console.debug("Initializing the web directory.")
884
961
  initialize_package_json()
885
962
 
963
+ console.debug("Initializing the bun config file.")
886
964
  initialize_bun_config()
887
965
 
966
+ console.debug("Initializing the public directory.")
888
967
  path_ops.mkdir(get_web_dir() / constants.Dirs.PUBLIC)
889
968
 
969
+ console.debug("Initializing the next.config.js file.")
890
970
  update_next_config()
891
971
 
972
+ console.debug("Initializing the reflex.json file.")
892
973
  # Initialize the reflex json file.
893
974
  init_reflex_json(project_hash=project_hash)
894
975
 
@@ -1321,6 +1402,7 @@ def ensure_reflex_installation_id() -> int | None:
1321
1402
  Distinct id.
1322
1403
  """
1323
1404
  try:
1405
+ console.debug("Ensuring reflex installation id.")
1324
1406
  initialize_reflex_user_directory()
1325
1407
  installation_id_file = environment.REFLEX_DIR.get() / "installation_id"
1326
1408
 
@@ -1347,6 +1429,7 @@ def ensure_reflex_installation_id() -> int | None:
1347
1429
 
1348
1430
  def initialize_reflex_user_directory():
1349
1431
  """Initialize the reflex user directory."""
1432
+ console.debug(f"Creating {environment.REFLEX_DIR.get()}")
1350
1433
  # Create the reflex directory.
1351
1434
  path_ops.mkdir(environment.REFLEX_DIR.get())
1352
1435
 
@@ -1354,9 +1437,11 @@ def initialize_reflex_user_directory():
1354
1437
  def initialize_frontend_dependencies():
1355
1438
  """Initialize all the frontend dependencies."""
1356
1439
  # validate dependencies before install
1440
+ console.debug("Validating frontend dependencies.")
1357
1441
  validate_frontend_dependencies()
1358
1442
  # Install the frontend dependencies.
1359
- processes.run_concurrently(install_bun)
1443
+ console.debug("Installing or validating bun.")
1444
+ install_bun()
1360
1445
  # Set up the web directory.
1361
1446
  initialize_web_directory()
1362
1447