diff --git a/reflex/config.py b/reflex/config.py index f4b4e3245..a16418fef 100644 --- a/reflex/config.py +++ b/reflex/config.py @@ -283,6 +283,9 @@ class EnvironmentVariables: # Whether to use seperate threads to compile the frontend and how many. Defaults to `min(32, os.cpu_count() + 4)`. REFLEX_COMPILE_THREADS: Optional[int] = None + # The directory to store reflex dependencies. + REFLEX_DIR: Path = Path(constants.Reflex.DIR) + def __init__(self): """Initialize the environment variables.""" type_hints = get_type_hints(type(self)) diff --git a/reflex/constants/base.py b/reflex/constants/base.py index 635427895..63edbfbe9 100644 --- a/reflex/constants/base.py +++ b/reflex/constants/base.py @@ -66,21 +66,13 @@ class Reflex(SimpleNamespace): # Files and directories used to init a new project. # The directory to store reflex dependencies. - # Get directory value from enviroment variables if it exists. - _dir = os.environ.get("REFLEX_DIR", "") + # on windows, we use C:/Users//AppData/Local/reflex. + # on macOS, we use ~/Library/Application Support/reflex. + # on linux, we use ~/.local/share/reflex. + # If user sets REFLEX_DIR envroment variable use that instead. + DIR = PlatformDirs(MODULE_NAME, False).user_data_path - DIR = Path( - _dir - or ( - # on windows, we use C:/Users//AppData/Local/reflex. - # on macOS, we use ~/Library/Application Support/reflex. - # on linux, we use ~/.local/share/reflex. - # If user sets REFLEX_DIR envroment variable use that instead. - PlatformDirs(MODULE_NAME, False).user_data_dir - ) - ) # The root directory of the reflex library. - ROOT_DIR = Path(__file__).parents[2] RELEASES_URL = f"https://api.github.com/repos/reflex-dev/templates/releases" diff --git a/reflex/constants/installer.py b/reflex/constants/installer.py index a3325f074..f26d07fc4 100644 --- a/reflex/constants/installer.py +++ b/reflex/constants/installer.py @@ -3,9 +3,11 @@ from __future__ import annotations import platform +from pathlib import Path from types import SimpleNamespace +from typing import Any, Callable, Generic, Type, TypeVar -from .base import IS_WINDOWS, Reflex +from .base import IS_WINDOWS def get_fnm_name() -> str | None: @@ -30,18 +32,43 @@ def get_fnm_name() -> str | None: return None +T = TypeVar("T") +V = TypeVar("V") + + +class classproperty(Generic[T, V]): + """A class property decorator.""" + + def __init__(self, getter: Callable[[Type[T]], V]) -> None: + """Initialize the class property. + + Args: + getter: The getter function. + """ + self.getter = getattr(getter, "__func__", getter) + + def __get__(self, instance: Any, owner: Type[T]) -> V: + """Get the value of the class property. + + Args: + instance: The instance of the class. + owner: The class itself. + + Returns: + The value of the class property. + """ + return self.getter(owner) + + # Bun config. class Bun(SimpleNamespace): """Bun constants.""" # The Bun version. VERSION = "1.1.29" + # Min Bun Version MIN_VERSION = "0.7.0" - # The directory to store the bun. - ROOT_PATH = Reflex.DIR / "bun" - # Default bun path. - DEFAULT_PATH = ROOT_PATH / "bin" / ("bun" if not IS_WINDOWS else "bun.exe") # URL to bun install script. INSTALL_URL = "https://raw.githubusercontent.com/reflex-dev/reflex/main/scripts/bun_install.sh" @@ -50,9 +77,24 @@ class Bun(SimpleNamespace): WINDOWS_INSTALL_URL = ( "https://raw.githubusercontent.com/reflex-dev/reflex/main/scripts/install.ps1" ) + # Path of the bunfig file CONFIG_PATH = "bunfig.toml" + @classproperty + @classmethod + def ROOT_PATH(cls): + """The directory to store the bun.""" + from reflex.config import environment + + return environment.REFLEX_DIR / "bun" + + @classproperty + @classmethod + def DEFAULT_PATH(cls): + """Default bun path.""" + return cls.ROOT_PATH / "bin" / ("bun" if not IS_WINDOWS else "bun.exe") + # FNM config. class Fnm(SimpleNamespace): @@ -60,17 +102,28 @@ class Fnm(SimpleNamespace): # The FNM version. VERSION = "1.35.1" - # The directory to store fnm. - DIR = Reflex.DIR / "fnm" + FILENAME = get_fnm_name() - # The fnm executable binary. - EXE = DIR / ("fnm.exe" if IS_WINDOWS else "fnm") # The URL to the fnm release binary INSTALL_URL = ( f"https://github.com/Schniz/fnm/releases/download/v{VERSION}/{FILENAME}.zip" ) + @classproperty + @classmethod + def DIR(cls) -> Path: + """The directory to store fnm.""" + from reflex.config import environment + + return environment.REFLEX_DIR / "fnm" + + @classproperty + @classmethod + def EXE(cls): + """The fnm executable binary.""" + return cls.DIR / ("fnm.exe" if IS_WINDOWS else "fnm") + # Node / NPM config class Node(SimpleNamespace): @@ -81,20 +134,29 @@ class Node(SimpleNamespace): # The minimum required node version. MIN_VERSION = "18.17.0" - # The node bin path. - BIN_PATH = ( - Fnm.DIR - / "node-versions" - / f"v{VERSION}" - / "installation" - / ("bin" if not IS_WINDOWS else "") - ) + @classproperty + @classmethod + def BIN_PATH(cls): + """The node bin path.""" + return ( + Fnm.DIR + / "node-versions" + / f"v{cls.VERSION}" + / "installation" + / ("bin" if not IS_WINDOWS else "") + ) - # The default path where node is installed. - PATH = BIN_PATH / ("node.exe" if IS_WINDOWS else "node") + @classproperty + @classmethod + def PATH(cls): + """The default path where node is installed.""" + return cls.BIN_PATH / ("node.exe" if IS_WINDOWS else "node") - # The default path where npm is installed. - NPM_PATH = BIN_PATH / "npm" + @classproperty + @classmethod + def NPM_PATH(cls): + """The default path where npm is installed.""" + return cls.BIN_PATH / "npm" class PackageJson(SimpleNamespace): diff --git a/reflex/utils/prerequisites.py b/reflex/utils/prerequisites.py index abc35ad22..33165af0e 100644 --- a/reflex/utils/prerequisites.py +++ b/reflex/utils/prerequisites.py @@ -991,7 +991,7 @@ def needs_reinit(frontend: bool = True) -> bool: return False # Make sure the .reflex directory exists. - if not constants.Reflex.DIR.exists(): + if not environment.REFLEX_DIR.exists(): return True # Make sure the .web directory exists in frontend mode. @@ -1096,7 +1096,7 @@ def ensure_reflex_installation_id() -> Optional[int]: """ try: initialize_reflex_user_directory() - installation_id_file = constants.Reflex.DIR / "installation_id" + installation_id_file = environment.REFLEX_DIR / "installation_id" installation_id = None if installation_id_file.exists(): @@ -1121,7 +1121,7 @@ def ensure_reflex_installation_id() -> Optional[int]: def initialize_reflex_user_directory(): """Initialize the reflex user directory.""" # Create the reflex directory. - path_ops.mkdir(constants.Reflex.DIR) + path_ops.mkdir(environment.REFLEX_DIR) def initialize_frontend_dependencies(): diff --git a/tests/units/test_config.py b/tests/units/test_config.py index a6c6fe697..c4a143bc5 100644 --- a/tests/units/test_config.py +++ b/tests/units/test_config.py @@ -5,6 +5,7 @@ import pytest import reflex as rx import reflex.config +from reflex.config import environment from reflex.constants import Endpoint @@ -178,7 +179,7 @@ def test_replace_defaults( def reflex_dir_constant(): - return rx.constants.Reflex.DIR + return environment.REFLEX_DIR def test_reflex_dir_env_var(monkeypatch, tmp_path):