Merge remote-tracking branch 'upstream/main' into fix-rx-config
This commit is contained in:
commit
44d60d1cc8
@ -74,7 +74,7 @@ jobs:
|
|||||||
echo "$outdated"
|
echo "$outdated"
|
||||||
|
|
||||||
# Ignore 3rd party dependencies that are not updated.
|
# Ignore 3rd party dependencies that are not updated.
|
||||||
filtered_outdated=$(echo "$outdated" | grep -vE 'Package|@chakra-ui|lucide-react|@splinetool/runtime|ag-grid-react|framer-motion|react-markdown|remark-math|remark-gfm|rehype-katex|rehype-raw' || true)
|
filtered_outdated=$(echo "$outdated" | grep -vE 'Package|@chakra-ui|lucide-react|@splinetool/runtime|ag-grid-react|framer-motion|react-markdown|remark-math|remark-gfm|rehype-katex|rehype-raw|remark-unwrap-images' || true)
|
||||||
no_extra=$(echo "$filtered_outdated" | grep -vE '\|\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-' || true)
|
no_extra=$(echo "$filtered_outdated" | grep -vE '\|\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-' || true)
|
||||||
|
|
||||||
|
|
||||||
|
1062
poetry.lock
generated
1062
poetry.lock
generated
File diff suppressed because it is too large
Load Diff
@ -70,7 +70,7 @@ pytest-asyncio = ">=0.24.0"
|
|||||||
pytest-cov = ">=4.0.0,<6.0"
|
pytest-cov = ">=4.0.0,<6.0"
|
||||||
ruff = "^0.6.9"
|
ruff = "^0.6.9"
|
||||||
pandas = ">=2.1.1,<3.0"
|
pandas = ">=2.1.1,<3.0"
|
||||||
pillow = ">=10.0.0,<11.0"
|
pillow = ">=10.0.0,<12.0"
|
||||||
plotly = ">=5.13.0,<6.0"
|
plotly = ">=5.13.0,<6.0"
|
||||||
asynctest = ">=0.13.0,<1.0"
|
asynctest = ">=0.13.0,<1.0"
|
||||||
pre-commit = ">=3.2.1"
|
pre-commit = ">=3.2.1"
|
||||||
|
@ -64,7 +64,7 @@ from reflex.components.core.client_side_routing import (
|
|||||||
)
|
)
|
||||||
from reflex.components.core.upload import Upload, get_upload_dir
|
from reflex.components.core.upload import Upload, get_upload_dir
|
||||||
from reflex.components.radix import themes
|
from reflex.components.radix import themes
|
||||||
from reflex.config import get_config
|
from reflex.config import environment, get_config
|
||||||
from reflex.event import Event, EventHandler, EventSpec, window_alert
|
from reflex.event import Event, EventHandler, EventSpec, window_alert
|
||||||
from reflex.model import Model, get_db_status
|
from reflex.model import Model, get_db_status
|
||||||
from reflex.page import (
|
from reflex.page import (
|
||||||
@ -957,15 +957,16 @@ class App(MiddlewareMixin, LifespanMixin, Base):
|
|||||||
executor = None
|
executor = None
|
||||||
if (
|
if (
|
||||||
platform.system() in ("Linux", "Darwin")
|
platform.system() in ("Linux", "Darwin")
|
||||||
and os.environ.get("REFLEX_COMPILE_PROCESSES") is not None
|
and (number_of_processes := environment.REFLEX_COMPILE_PROCESSES)
|
||||||
|
is not None
|
||||||
):
|
):
|
||||||
executor = concurrent.futures.ProcessPoolExecutor(
|
executor = concurrent.futures.ProcessPoolExecutor(
|
||||||
max_workers=int(os.environ.get("REFLEX_COMPILE_PROCESSES", 0)) or None,
|
max_workers=number_of_processes,
|
||||||
mp_context=multiprocessing.get_context("fork"),
|
mp_context=multiprocessing.get_context("fork"),
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
executor = concurrent.futures.ThreadPoolExecutor(
|
executor = concurrent.futures.ThreadPoolExecutor(
|
||||||
max_workers=int(os.environ.get("REFLEX_COMPILE_THREADS", 0)) or None,
|
max_workers=environment.REFLEX_COMPILE_THREADS
|
||||||
)
|
)
|
||||||
|
|
||||||
with executor:
|
with executor:
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import os
|
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Dict, Iterable, Optional, Type, Union
|
from typing import Dict, Iterable, Optional, Type, Union
|
||||||
@ -16,7 +15,7 @@ from reflex.components.component import (
|
|||||||
CustomComponent,
|
CustomComponent,
|
||||||
StatefulComponent,
|
StatefulComponent,
|
||||||
)
|
)
|
||||||
from reflex.config import get_config
|
from reflex.config import environment, get_config
|
||||||
from reflex.state import BaseState
|
from reflex.state import BaseState
|
||||||
from reflex.style import SYSTEM_COLOR_MODE
|
from reflex.style import SYSTEM_COLOR_MODE
|
||||||
from reflex.utils.exec import is_prod_mode
|
from reflex.utils.exec import is_prod_mode
|
||||||
@ -527,7 +526,7 @@ def remove_tailwind_from_postcss() -> tuple[str, str]:
|
|||||||
|
|
||||||
def purge_web_pages_dir():
|
def purge_web_pages_dir():
|
||||||
"""Empty out .web/pages directory."""
|
"""Empty out .web/pages directory."""
|
||||||
if not is_prod_mode() and os.environ.get("REFLEX_PERSIST_WEB_DIR"):
|
if not is_prod_mode() and environment.REFLEX_PERSIST_WEB_DIR:
|
||||||
# Skip purging the web directory in dev mode if REFLEX_PERSIST_WEB_DIR is set.
|
# Skip purging the web directory in dev mode if REFLEX_PERSIST_WEB_DIR is set.
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@ -2,13 +2,13 @@
|
|||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import os
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any, Callable, ClassVar, Dict, List, Optional, Tuple
|
from typing import Any, Callable, ClassVar, Dict, List, Optional, Tuple
|
||||||
|
|
||||||
from reflex.components.component import Component, ComponentNamespace, MemoizationLeaf
|
from reflex.components.component import Component, ComponentNamespace, MemoizationLeaf
|
||||||
from reflex.components.el.elements.forms import Input
|
from reflex.components.el.elements.forms import Input
|
||||||
from reflex.components.radix.themes.layout.box import Box
|
from reflex.components.radix.themes.layout.box import Box
|
||||||
|
from reflex.config import environment
|
||||||
from reflex.constants import Dirs
|
from reflex.constants import Dirs
|
||||||
from reflex.event import (
|
from reflex.event import (
|
||||||
CallableEventSpec,
|
CallableEventSpec,
|
||||||
@ -125,9 +125,7 @@ def get_upload_dir() -> Path:
|
|||||||
"""
|
"""
|
||||||
Upload.is_used = True
|
Upload.is_used = True
|
||||||
|
|
||||||
uploaded_files_dir = Path(
|
uploaded_files_dir = environment.REFLEX_UPLOADED_FILES_DIR
|
||||||
os.environ.get("REFLEX_UPLOADED_FILES_DIR", "./uploaded_files")
|
|
||||||
)
|
|
||||||
uploaded_files_dir.mkdir(parents=True, exist_ok=True)
|
uploaded_files_dir.mkdir(parents=True, exist_ok=True)
|
||||||
return uploaded_files_dir
|
return uploaded_files_dir
|
||||||
|
|
||||||
@ -179,7 +177,7 @@ class UploadFilesProvider(Component):
|
|||||||
class Upload(MemoizationLeaf):
|
class Upload(MemoizationLeaf):
|
||||||
"""A file upload component."""
|
"""A file upload component."""
|
||||||
|
|
||||||
library = "react-dropzone@14.2.9"
|
library = "react-dropzone@14.2.10"
|
||||||
|
|
||||||
tag = "ReactDropzone"
|
tag = "ReactDropzone"
|
||||||
|
|
||||||
|
@ -381,7 +381,7 @@ for theme_name in dir(Theme):
|
|||||||
class CodeBlock(Component):
|
class CodeBlock(Component):
|
||||||
"""A code block."""
|
"""A code block."""
|
||||||
|
|
||||||
library = "react-syntax-highlighter@15.5.0"
|
library = "react-syntax-highlighter@15.6.1"
|
||||||
|
|
||||||
tag = "PrismAsyncLight"
|
tag = "PrismAsyncLight"
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@ from reflex.utils import console
|
|||||||
class Recharts(Component):
|
class Recharts(Component):
|
||||||
"""A component that wraps a recharts lib."""
|
"""A component that wraps a recharts lib."""
|
||||||
|
|
||||||
library = "recharts@2.12.7"
|
library = "recharts@2.13.0"
|
||||||
|
|
||||||
def render(self) -> Dict:
|
def render(self) -> Dict:
|
||||||
"""Render the tag.
|
"""Render the tag.
|
||||||
@ -29,7 +29,7 @@ class Recharts(Component):
|
|||||||
class RechartsCharts(NoSSRComponent, MemoizationLeaf):
|
class RechartsCharts(NoSSRComponent, MemoizationLeaf):
|
||||||
"""A component that wraps a recharts lib."""
|
"""A component that wraps a recharts lib."""
|
||||||
|
|
||||||
library = "recharts@2.12.7"
|
library = "recharts@2.13.0"
|
||||||
|
|
||||||
|
|
||||||
LiteralAnimationEasing = Literal["ease", "ease-in", "ease-out", "ease-in-out", "linear"]
|
LiteralAnimationEasing = Literal["ease", "ease-in", "ease-out", "ease-in-out", "linear"]
|
||||||
|
199
reflex/config.py
199
reflex/config.py
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import dataclasses
|
||||||
import importlib
|
import importlib
|
||||||
import inspect
|
import inspect
|
||||||
import os
|
import os
|
||||||
@ -10,8 +11,10 @@ import urllib.parse
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any, Dict, List, Optional, Set, Union
|
from typing import Any, Dict, List, Optional, Set, Union
|
||||||
|
|
||||||
from reflex.utils.exceptions import ConfigError
|
from typing_extensions import get_type_hints
|
||||||
from reflex.utils.types import is_optional, is_union
|
|
||||||
|
from reflex.utils.exceptions import ConfigError, EnvironmentVarValueError
|
||||||
|
from reflex.utils.types import is_optional, is_union, value_inside_optional
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import pydantic.v1 as pydantic
|
import pydantic.v1 as pydantic
|
||||||
@ -133,6 +136,198 @@ class DBConfig(Base):
|
|||||||
return f"{self.engine}://{path}/{self.database}"
|
return f"{self.engine}://{path}/{self.database}"
|
||||||
|
|
||||||
|
|
||||||
|
def get_default_value_for_field(field: dataclasses.Field) -> Any:
|
||||||
|
"""Get the default value for a field.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
field: The field.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The default value.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
ValueError: If no default value is found.
|
||||||
|
"""
|
||||||
|
if field.default != dataclasses.MISSING:
|
||||||
|
return field.default
|
||||||
|
elif field.default_factory != dataclasses.MISSING:
|
||||||
|
return field.default_factory()
|
||||||
|
else:
|
||||||
|
raise ValueError(
|
||||||
|
f"Missing value for environment variable {field.name} and no default value found"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def interpret_boolean_env(value: str) -> bool:
|
||||||
|
"""Interpret a boolean environment variable value.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
value: The environment variable value.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The interpreted value.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
EnvironmentVarValueError: If the value is invalid.
|
||||||
|
"""
|
||||||
|
true_values = ["true", "1", "yes", "y"]
|
||||||
|
false_values = ["false", "0", "no", "n"]
|
||||||
|
|
||||||
|
if value.lower() in true_values:
|
||||||
|
return True
|
||||||
|
elif value.lower() in false_values:
|
||||||
|
return False
|
||||||
|
raise EnvironmentVarValueError(f"Invalid boolean value: {value}")
|
||||||
|
|
||||||
|
|
||||||
|
def interpret_int_env(value: str) -> int:
|
||||||
|
"""Interpret an integer environment variable value.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
value: The environment variable value.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The interpreted value.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
EnvironmentVarValueError: If the value is invalid.
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
return int(value)
|
||||||
|
except ValueError as ve:
|
||||||
|
raise EnvironmentVarValueError(f"Invalid integer value: {value}") from ve
|
||||||
|
|
||||||
|
|
||||||
|
def interpret_path_env(value: str) -> Path:
|
||||||
|
"""Interpret a path environment variable value.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
value: The environment variable value.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The interpreted value.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
EnvironmentVarValueError: If the path does not exist.
|
||||||
|
"""
|
||||||
|
path = Path(value)
|
||||||
|
if not path.exists():
|
||||||
|
raise EnvironmentVarValueError(f"Path does not exist: {path}")
|
||||||
|
return path
|
||||||
|
|
||||||
|
|
||||||
|
def interpret_env_var_value(value: str, field: dataclasses.Field) -> Any:
|
||||||
|
"""Interpret an environment variable value based on the field type.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
value: The environment variable value.
|
||||||
|
field: The field.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The interpreted value.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
ValueError: If the value is invalid.
|
||||||
|
"""
|
||||||
|
field_type = value_inside_optional(field.type)
|
||||||
|
|
||||||
|
if field_type is bool:
|
||||||
|
return interpret_boolean_env(value)
|
||||||
|
elif field_type is str:
|
||||||
|
return value
|
||||||
|
elif field_type is int:
|
||||||
|
return interpret_int_env(value)
|
||||||
|
elif field_type is Path:
|
||||||
|
return interpret_path_env(value)
|
||||||
|
|
||||||
|
else:
|
||||||
|
raise ValueError(
|
||||||
|
f"Invalid type for environment variable {field.name}: {field_type}. This is probably an issue in Reflex."
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@dataclasses.dataclass(init=False)
|
||||||
|
class EnvironmentVariables:
|
||||||
|
"""Environment variables class to instantiate environment variables."""
|
||||||
|
|
||||||
|
# Whether to use npm over bun to install frontend packages.
|
||||||
|
REFLEX_USE_NPM: bool = False
|
||||||
|
|
||||||
|
# The npm registry to use.
|
||||||
|
NPM_CONFIG_REGISTRY: Optional[str] = None
|
||||||
|
|
||||||
|
# Whether to use Granian for the backend. Otherwise, use Uvicorn.
|
||||||
|
REFLEX_USE_GRANIAN: bool = False
|
||||||
|
|
||||||
|
# The username to use for authentication on python package repository. Username and password must both be provided.
|
||||||
|
TWINE_USERNAME: Optional[str] = None
|
||||||
|
|
||||||
|
# The password to use for authentication on python package repository. Username and password must both be provided.
|
||||||
|
TWINE_PASSWORD: Optional[str] = None
|
||||||
|
|
||||||
|
# Whether to use the system installed bun. If set to false, bun will be bundled with the app.
|
||||||
|
REFLEX_USE_SYSTEM_BUN: bool = False
|
||||||
|
|
||||||
|
# Whether to use the system installed node and npm. If set to false, node and npm will be bundled with the app.
|
||||||
|
REFLEX_USE_SYSTEM_NODE: bool = False
|
||||||
|
|
||||||
|
# The working directory for the next.js commands.
|
||||||
|
REFLEX_WEB_WORKDIR: Path = Path(constants.Dirs.WEB)
|
||||||
|
|
||||||
|
# Path to the alembic config file
|
||||||
|
ALEMBIC_CONFIG: Path = Path(constants.ALEMBIC_CONFIG)
|
||||||
|
|
||||||
|
# Disable SSL verification for HTTPX requests.
|
||||||
|
SSL_NO_VERIFY: bool = False
|
||||||
|
|
||||||
|
# The directory to store uploaded files.
|
||||||
|
REFLEX_UPLOADED_FILES_DIR: Path = Path(constants.Dirs.UPLOADED_FILES)
|
||||||
|
|
||||||
|
# Whether to use seperate processes to compile the frontend and how many. If not set, defaults to thread executor.
|
||||||
|
REFLEX_COMPILE_PROCESSES: Optional[int] = None
|
||||||
|
|
||||||
|
# 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)
|
||||||
|
|
||||||
|
# Whether to print the SQL queries if the log level is INFO or lower.
|
||||||
|
SQLALCHEMY_ECHO: bool = False
|
||||||
|
|
||||||
|
# Whether to ignore the redis config error. Some redis servers only allow out-of-band configuration.
|
||||||
|
REFLEX_IGNORE_REDIS_CONFIG_ERROR: bool = False
|
||||||
|
|
||||||
|
# Whether to skip purging the web directory in dev mode.
|
||||||
|
REFLEX_PERSIST_WEB_DIR: bool = False
|
||||||
|
|
||||||
|
# The reflex.build frontend host.
|
||||||
|
REFLEX_BUILD_FRONTEND: str = constants.Templates.REFLEX_BUILD_FRONTEND
|
||||||
|
|
||||||
|
# The reflex.build backend host.
|
||||||
|
REFLEX_BUILD_BACKEND: str = constants.Templates.REFLEX_BUILD_BACKEND
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
"""Initialize the environment variables."""
|
||||||
|
type_hints = get_type_hints(type(self))
|
||||||
|
|
||||||
|
for field in dataclasses.fields(self):
|
||||||
|
raw_value = os.getenv(field.name, None)
|
||||||
|
|
||||||
|
field.type = type_hints.get(field.name) or field.type
|
||||||
|
|
||||||
|
value = (
|
||||||
|
interpret_env_var_value(raw_value, field)
|
||||||
|
if raw_value is not None
|
||||||
|
else get_default_value_for_field(field)
|
||||||
|
)
|
||||||
|
|
||||||
|
setattr(self, field.name, value)
|
||||||
|
|
||||||
|
|
||||||
|
environment = EnvironmentVariables()
|
||||||
|
|
||||||
|
|
||||||
class Config(Base):
|
class Config(Base):
|
||||||
"""The config defines runtime settings for the app.
|
"""The config defines runtime settings for the app.
|
||||||
|
|
||||||
|
@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
from .base import (
|
from .base import (
|
||||||
COOKIES,
|
COOKIES,
|
||||||
|
ENV_BACKEND_ONLY_ENV_VAR,
|
||||||
|
ENV_FRONTEND_ONLY_ENV_VAR,
|
||||||
ENV_MODE_ENV_VAR,
|
ENV_MODE_ENV_VAR,
|
||||||
IS_WINDOWS,
|
IS_WINDOWS,
|
||||||
LOCAL_STORAGE,
|
LOCAL_STORAGE,
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import os
|
|
||||||
import platform
|
import platform
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
from importlib import metadata
|
from importlib import metadata
|
||||||
@ -11,6 +10,8 @@ from types import SimpleNamespace
|
|||||||
|
|
||||||
from platformdirs import PlatformDirs
|
from platformdirs import PlatformDirs
|
||||||
|
|
||||||
|
from .utils import classproperty
|
||||||
|
|
||||||
IS_WINDOWS = platform.system() == "Windows"
|
IS_WINDOWS = platform.system() == "Windows"
|
||||||
|
|
||||||
|
|
||||||
@ -20,6 +21,8 @@ class Dirs(SimpleNamespace):
|
|||||||
# The frontend directories in a project.
|
# The frontend directories in a project.
|
||||||
# The web folder where the NextJS app is compiled to.
|
# The web folder where the NextJS app is compiled to.
|
||||||
WEB = ".web"
|
WEB = ".web"
|
||||||
|
# The directory where uploaded files are stored.
|
||||||
|
UPLOADED_FILES = "uploaded_files"
|
||||||
# The name of the assets directory.
|
# The name of the assets directory.
|
||||||
APP_ASSETS = "assets"
|
APP_ASSETS = "assets"
|
||||||
# The name of the assets directory for external ressource (a subfolder of APP_ASSETS).
|
# The name of the assets directory for external ressource (a subfolder of APP_ASSETS).
|
||||||
@ -64,21 +67,13 @@ class Reflex(SimpleNamespace):
|
|||||||
|
|
||||||
# Files and directories used to init a new project.
|
# Files and directories used to init a new project.
|
||||||
# The directory to store reflex dependencies.
|
# The directory to store reflex dependencies.
|
||||||
# Get directory value from enviroment variables if it exists.
|
|
||||||
_dir = os.environ.get("REFLEX_DIR", "")
|
|
||||||
|
|
||||||
DIR = Path(
|
|
||||||
_dir
|
|
||||||
or (
|
|
||||||
# on windows, we use C:/Users/<username>/AppData/Local/reflex.
|
# on windows, we use C:/Users/<username>/AppData/Local/reflex.
|
||||||
# on macOS, we use ~/Library/Application Support/reflex.
|
# on macOS, we use ~/Library/Application Support/reflex.
|
||||||
# on linux, we use ~/.local/share/reflex.
|
# on linux, we use ~/.local/share/reflex.
|
||||||
# If user sets REFLEX_DIR envroment variable use that instead.
|
# If user sets REFLEX_DIR envroment variable use that instead.
|
||||||
PlatformDirs(MODULE_NAME, False).user_data_dir
|
DIR = PlatformDirs(MODULE_NAME, False).user_data_path
|
||||||
)
|
|
||||||
)
|
|
||||||
# The root directory of the reflex library.
|
|
||||||
|
|
||||||
|
# The root directory of the reflex library.
|
||||||
ROOT_DIR = Path(__file__).parents[2]
|
ROOT_DIR = Path(__file__).parents[2]
|
||||||
|
|
||||||
RELEASES_URL = f"https://api.github.com/repos/reflex-dev/templates/releases"
|
RELEASES_URL = f"https://api.github.com/repos/reflex-dev/templates/releases"
|
||||||
@ -101,26 +96,50 @@ class Templates(SimpleNamespace):
|
|||||||
DEFAULT = "blank"
|
DEFAULT = "blank"
|
||||||
|
|
||||||
# The reflex.build frontend host
|
# The reflex.build frontend host
|
||||||
REFLEX_BUILD_FRONTEND = os.environ.get(
|
REFLEX_BUILD_FRONTEND = "https://flexgen.reflex.run"
|
||||||
"REFLEX_BUILD_FRONTEND", "https://flexgen.reflex.run"
|
|
||||||
)
|
|
||||||
|
|
||||||
# The reflex.build backend host
|
# The reflex.build backend host
|
||||||
REFLEX_BUILD_BACKEND = os.environ.get(
|
REFLEX_BUILD_BACKEND = "https://flexgen-prod-flexgen.fly.dev"
|
||||||
"REFLEX_BUILD_BACKEND", "https://flexgen-prod-flexgen.fly.dev"
|
|
||||||
|
@classproperty
|
||||||
|
@classmethod
|
||||||
|
def REFLEX_BUILD_URL(cls):
|
||||||
|
"""The URL to redirect to reflex.build.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The URL to redirect to reflex.build.
|
||||||
|
"""
|
||||||
|
from reflex.config import environment
|
||||||
|
|
||||||
|
return (
|
||||||
|
environment.REFLEX_BUILD_FRONTEND
|
||||||
|
+ "/gen?reflex_init_token={reflex_init_token}"
|
||||||
)
|
)
|
||||||
|
|
||||||
# The URL to redirect to reflex.build
|
@classproperty
|
||||||
REFLEX_BUILD_URL = (
|
@classmethod
|
||||||
REFLEX_BUILD_FRONTEND + "/gen?reflex_init_token={reflex_init_token}"
|
def REFLEX_BUILD_POLL_URL(cls):
|
||||||
)
|
"""The URL to poll waiting for the user to select a generation.
|
||||||
|
|
||||||
# The URL to poll waiting for the user to select a generation.
|
Returns:
|
||||||
REFLEX_BUILD_POLL_URL = REFLEX_BUILD_BACKEND + "/api/init/{reflex_init_token}"
|
The URL to poll waiting for the user to select a generation.
|
||||||
|
"""
|
||||||
|
from reflex.config import environment
|
||||||
|
|
||||||
# The URL to fetch the generation's reflex code
|
return environment.REFLEX_BUILD_BACKEND + "/api/init/{reflex_init_token}"
|
||||||
REFLEX_BUILD_CODE_URL = (
|
|
||||||
REFLEX_BUILD_BACKEND + "/api/gen/{generation_hash}/refactored"
|
@classproperty
|
||||||
|
@classmethod
|
||||||
|
def REFLEX_BUILD_CODE_URL(cls):
|
||||||
|
"""The URL to fetch the generation's reflex code.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The URL to fetch the generation's reflex code.
|
||||||
|
"""
|
||||||
|
from reflex.config import environment
|
||||||
|
|
||||||
|
return (
|
||||||
|
environment.REFLEX_BUILD_BACKEND + "/api/gen/{generation_hash}/refactored"
|
||||||
)
|
)
|
||||||
|
|
||||||
class Dirs(SimpleNamespace):
|
class Dirs(SimpleNamespace):
|
||||||
@ -226,6 +245,9 @@ SKIP_COMPILE_ENV_VAR = "__REFLEX_SKIP_COMPILE"
|
|||||||
# This env var stores the execution mode of the app
|
# This env var stores the execution mode of the app
|
||||||
ENV_MODE_ENV_VAR = "REFLEX_ENV_MODE"
|
ENV_MODE_ENV_VAR = "REFLEX_ENV_MODE"
|
||||||
|
|
||||||
|
ENV_BACKEND_ONLY_ENV_VAR = "REFLEX_BACKEND_ONLY"
|
||||||
|
ENV_FRONTEND_ONLY_ENV_VAR = "REFLEX_FRONTEND_ONLY"
|
||||||
|
|
||||||
# Testing variables.
|
# Testing variables.
|
||||||
# Testing os env set by pytest when running a test case.
|
# Testing os env set by pytest when running a test case.
|
||||||
PYTEST_CURRENT_TEST = "PYTEST_CURRENT_TEST"
|
PYTEST_CURRENT_TEST = "PYTEST_CURRENT_TEST"
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
"""Config constants."""
|
"""Config constants."""
|
||||||
|
|
||||||
import os
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from types import SimpleNamespace
|
from types import SimpleNamespace
|
||||||
|
|
||||||
@ -9,7 +8,7 @@ from reflex.constants.base import Dirs, Reflex
|
|||||||
from .compiler import Ext
|
from .compiler import Ext
|
||||||
|
|
||||||
# Alembic migrations
|
# Alembic migrations
|
||||||
ALEMBIC_CONFIG = os.environ.get("ALEMBIC_CONFIG", "alembic.ini")
|
ALEMBIC_CONFIG = "alembic.ini"
|
||||||
|
|
||||||
|
|
||||||
class Config(SimpleNamespace):
|
class Config(SimpleNamespace):
|
||||||
|
@ -3,9 +3,11 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import platform
|
import platform
|
||||||
|
from pathlib import Path
|
||||||
from types import SimpleNamespace
|
from types import SimpleNamespace
|
||||||
|
|
||||||
from .base import IS_WINDOWS, Reflex
|
from .base import IS_WINDOWS
|
||||||
|
from .utils import classproperty
|
||||||
|
|
||||||
|
|
||||||
def get_fnm_name() -> str | None:
|
def get_fnm_name() -> str | None:
|
||||||
@ -36,12 +38,9 @@ class Bun(SimpleNamespace):
|
|||||||
|
|
||||||
# The Bun version.
|
# The Bun version.
|
||||||
VERSION = "1.1.29"
|
VERSION = "1.1.29"
|
||||||
|
|
||||||
# Min Bun Version
|
# Min Bun Version
|
||||||
MIN_VERSION = "0.7.0"
|
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.
|
# URL to bun install script.
|
||||||
INSTALL_URL = "https://raw.githubusercontent.com/reflex-dev/reflex/main/scripts/bun_install.sh"
|
INSTALL_URL = "https://raw.githubusercontent.com/reflex-dev/reflex/main/scripts/bun_install.sh"
|
||||||
@ -50,11 +49,31 @@ class Bun(SimpleNamespace):
|
|||||||
WINDOWS_INSTALL_URL = (
|
WINDOWS_INSTALL_URL = (
|
||||||
"https://raw.githubusercontent.com/reflex-dev/reflex/main/scripts/install.ps1"
|
"https://raw.githubusercontent.com/reflex-dev/reflex/main/scripts/install.ps1"
|
||||||
)
|
)
|
||||||
|
|
||||||
# Path of the bunfig file
|
# Path of the bunfig file
|
||||||
CONFIG_PATH = "bunfig.toml"
|
CONFIG_PATH = "bunfig.toml"
|
||||||
|
|
||||||
# The environment variable to use the system installed bun.
|
@classproperty
|
||||||
USE_SYSTEM_VAR = "REFLEX_USE_SYSTEM_BUN"
|
@classmethod
|
||||||
|
def ROOT_PATH(cls):
|
||||||
|
"""The directory to store the bun.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
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.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The default bun path.
|
||||||
|
"""
|
||||||
|
return cls.ROOT_PATH / "bin" / ("bun" if not IS_WINDOWS else "bun.exe")
|
||||||
|
|
||||||
|
|
||||||
# FNM config.
|
# FNM config.
|
||||||
@ -63,44 +82,81 @@ class Fnm(SimpleNamespace):
|
|||||||
|
|
||||||
# The FNM version.
|
# The FNM version.
|
||||||
VERSION = "1.35.1"
|
VERSION = "1.35.1"
|
||||||
# The directory to store fnm.
|
|
||||||
DIR = Reflex.DIR / "fnm"
|
|
||||||
FILENAME = get_fnm_name()
|
FILENAME = get_fnm_name()
|
||||||
# The fnm executable binary.
|
|
||||||
EXE = DIR / ("fnm.exe" if IS_WINDOWS else "fnm")
|
|
||||||
|
|
||||||
# The URL to the fnm release binary
|
# The URL to the fnm release binary
|
||||||
INSTALL_URL = (
|
INSTALL_URL = (
|
||||||
f"https://github.com/Schniz/fnm/releases/download/v{VERSION}/{FILENAME}.zip"
|
f"https://github.com/Schniz/fnm/releases/download/v{VERSION}/{FILENAME}.zip"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@classproperty
|
||||||
|
@classmethod
|
||||||
|
def DIR(cls) -> Path:
|
||||||
|
"""The directory to store fnm.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The directory to store fnm.
|
||||||
|
"""
|
||||||
|
from reflex.config import environment
|
||||||
|
|
||||||
|
return environment.REFLEX_DIR / "fnm"
|
||||||
|
|
||||||
|
@classproperty
|
||||||
|
@classmethod
|
||||||
|
def EXE(cls):
|
||||||
|
"""The fnm executable binary.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The fnm executable binary.
|
||||||
|
"""
|
||||||
|
return cls.DIR / ("fnm.exe" if IS_WINDOWS else "fnm")
|
||||||
|
|
||||||
|
|
||||||
# Node / NPM config
|
# Node / NPM config
|
||||||
class Node(SimpleNamespace):
|
class Node(SimpleNamespace):
|
||||||
"""Node/ NPM constants."""
|
"""Node/ NPM constants."""
|
||||||
|
|
||||||
# The Node version.
|
# The Node version.
|
||||||
VERSION = "20.18.0"
|
VERSION = "22.10.0"
|
||||||
# The minimum required node version.
|
# The minimum required node version.
|
||||||
MIN_VERSION = "18.17.0"
|
MIN_VERSION = "18.17.0"
|
||||||
|
|
||||||
# The node bin path.
|
@classproperty
|
||||||
BIN_PATH = (
|
@classmethod
|
||||||
|
def BIN_PATH(cls):
|
||||||
|
"""The node bin path.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The node bin path.
|
||||||
|
"""
|
||||||
|
return (
|
||||||
Fnm.DIR
|
Fnm.DIR
|
||||||
/ "node-versions"
|
/ "node-versions"
|
||||||
/ f"v{VERSION}"
|
/ f"v{cls.VERSION}"
|
||||||
/ "installation"
|
/ "installation"
|
||||||
/ ("bin" if not IS_WINDOWS else "")
|
/ ("bin" if not IS_WINDOWS else "")
|
||||||
)
|
)
|
||||||
|
|
||||||
# The default path where node is installed.
|
@classproperty
|
||||||
PATH = BIN_PATH / ("node.exe" if IS_WINDOWS else "node")
|
@classmethod
|
||||||
|
def PATH(cls):
|
||||||
|
"""The default path where node is installed.
|
||||||
|
|
||||||
# The default path where npm is installed.
|
Returns:
|
||||||
NPM_PATH = BIN_PATH / "npm"
|
The default path where node is installed.
|
||||||
|
"""
|
||||||
|
return cls.BIN_PATH / ("node.exe" if IS_WINDOWS else "node")
|
||||||
|
|
||||||
# The environment variable to use the system installed node.
|
@classproperty
|
||||||
USE_SYSTEM_VAR = "REFLEX_USE_SYSTEM_NODE"
|
@classmethod
|
||||||
|
def NPM_PATH(cls):
|
||||||
|
"""The default path where npm is installed.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The default path where npm is installed.
|
||||||
|
"""
|
||||||
|
return cls.BIN_PATH / "npm"
|
||||||
|
|
||||||
|
|
||||||
class PackageJson(SimpleNamespace):
|
class PackageJson(SimpleNamespace):
|
||||||
@ -117,18 +173,18 @@ class PackageJson(SimpleNamespace):
|
|||||||
PATH = "package.json"
|
PATH = "package.json"
|
||||||
|
|
||||||
DEPENDENCIES = {
|
DEPENDENCIES = {
|
||||||
"@babel/standalone": "7.25.7",
|
"@babel/standalone": "7.25.8",
|
||||||
"@emotion/react": "11.13.3",
|
"@emotion/react": "11.13.3",
|
||||||
"axios": "1.7.7",
|
"axios": "1.7.7",
|
||||||
"json5": "2.2.3",
|
"json5": "2.2.3",
|
||||||
"next": "14.2.14",
|
"next": "14.2.15",
|
||||||
"next-sitemap": "4.2.3",
|
"next-sitemap": "4.2.3",
|
||||||
"next-themes": "0.3.0",
|
"next-themes": "0.3.0",
|
||||||
"react": "18.3.1",
|
"react": "18.3.1",
|
||||||
"react-dom": "18.3.1",
|
"react-dom": "18.3.1",
|
||||||
"react-focus-lock": "2.13.2",
|
"react-focus-lock": "2.13.2",
|
||||||
"socket.io-client": "4.8.0",
|
"socket.io-client": "4.8.0",
|
||||||
"universal-cookie": "7.2.0",
|
"universal-cookie": "7.2.1",
|
||||||
}
|
}
|
||||||
DEV_DEPENDENCIES = {
|
DEV_DEPENDENCIES = {
|
||||||
"autoprefixer": "10.4.20",
|
"autoprefixer": "10.4.20",
|
||||||
|
@ -7,7 +7,7 @@ class Tailwind(SimpleNamespace):
|
|||||||
"""Tailwind constants."""
|
"""Tailwind constants."""
|
||||||
|
|
||||||
# The Tailwindcss version
|
# The Tailwindcss version
|
||||||
VERSION = "tailwindcss@3.4.13"
|
VERSION = "tailwindcss@3.4.14"
|
||||||
# The Tailwind config.
|
# The Tailwind config.
|
||||||
CONFIG = "tailwind.config.js"
|
CONFIG = "tailwind.config.js"
|
||||||
# Default Tailwind content paths
|
# Default Tailwind content paths
|
||||||
|
32
reflex/constants/utils.py
Normal file
32
reflex/constants/utils.py
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
"""Utility functions for constants."""
|
||||||
|
|
||||||
|
from typing import Any, Callable, Generic, Type
|
||||||
|
|
||||||
|
from typing_extensions import TypeVar
|
||||||
|
|
||||||
|
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)
|
@ -17,7 +17,7 @@ import typer
|
|||||||
from tomlkit.exceptions import TOMLKitError
|
from tomlkit.exceptions import TOMLKitError
|
||||||
|
|
||||||
from reflex import constants
|
from reflex import constants
|
||||||
from reflex.config import get_config
|
from reflex.config import environment, get_config
|
||||||
from reflex.constants import CustomComponents
|
from reflex.constants import CustomComponents
|
||||||
from reflex.utils import console
|
from reflex.utils import console
|
||||||
|
|
||||||
@ -609,14 +609,14 @@ def publish(
|
|||||||
help="The API token to use for authentication on python package repository. If token is provided, no username/password should be provided at the same time",
|
help="The API token to use for authentication on python package repository. If token is provided, no username/password should be provided at the same time",
|
||||||
),
|
),
|
||||||
username: Optional[str] = typer.Option(
|
username: Optional[str] = typer.Option(
|
||||||
os.getenv("TWINE_USERNAME"),
|
environment.TWINE_USERNAME,
|
||||||
"-u",
|
"-u",
|
||||||
"--username",
|
"--username",
|
||||||
show_default="TWINE_USERNAME environment variable value if set",
|
show_default="TWINE_USERNAME environment variable value if set",
|
||||||
help="The username to use for authentication on python package repository. Username and password must both be provided.",
|
help="The username to use for authentication on python package repository. Username and password must both be provided.",
|
||||||
),
|
),
|
||||||
password: Optional[str] = typer.Option(
|
password: Optional[str] = typer.Option(
|
||||||
os.getenv("TWINE_PASSWORD"),
|
environment.TWINE_PASSWORD,
|
||||||
"-p",
|
"-p",
|
||||||
"--password",
|
"--password",
|
||||||
show_default="TWINE_PASSWORD environment variable value if set",
|
show_default="TWINE_PASSWORD environment variable value if set",
|
||||||
|
@ -2,9 +2,7 @@
|
|||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import os
|
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
from pathlib import Path
|
|
||||||
from typing import Any, ClassVar, Optional, Type, Union
|
from typing import Any, ClassVar, Optional, Type, Union
|
||||||
|
|
||||||
import alembic.autogenerate
|
import alembic.autogenerate
|
||||||
@ -18,9 +16,8 @@ import sqlalchemy
|
|||||||
import sqlalchemy.exc
|
import sqlalchemy.exc
|
||||||
import sqlalchemy.orm
|
import sqlalchemy.orm
|
||||||
|
|
||||||
from reflex import constants
|
|
||||||
from reflex.base import Base
|
from reflex.base import Base
|
||||||
from reflex.config import get_config
|
from reflex.config import environment, get_config
|
||||||
from reflex.utils import console
|
from reflex.utils import console
|
||||||
from reflex.utils.compat import sqlmodel, sqlmodel_field_has_primary_key
|
from reflex.utils.compat import sqlmodel, sqlmodel_field_has_primary_key
|
||||||
|
|
||||||
@ -41,12 +38,12 @@ def get_engine(url: str | None = None) -> sqlalchemy.engine.Engine:
|
|||||||
url = url or conf.db_url
|
url = url or conf.db_url
|
||||||
if url is None:
|
if url is None:
|
||||||
raise ValueError("No database url configured")
|
raise ValueError("No database url configured")
|
||||||
if not Path(constants.ALEMBIC_CONFIG).exists():
|
if environment.ALEMBIC_CONFIG.exists():
|
||||||
console.warn(
|
console.warn(
|
||||||
"Database is not initialized, run [bold]reflex db init[/bold] first."
|
"Database is not initialized, run [bold]reflex db init[/bold] first."
|
||||||
)
|
)
|
||||||
# Print the SQL queries if the log level is INFO or lower.
|
# Print the SQL queries if the log level is INFO or lower.
|
||||||
echo_db_query = os.environ.get("SQLALCHEMY_ECHO") == "True"
|
echo_db_query = environment.SQLALCHEMY_ECHO
|
||||||
# Needed for the admin dash on sqlite.
|
# Needed for the admin dash on sqlite.
|
||||||
connect_args = {"check_same_thread": False} if url.startswith("sqlite") else {}
|
connect_args = {"check_same_thread": False} if url.startswith("sqlite") else {}
|
||||||
return sqlmodel.create_engine(url, echo=echo_db_query, connect_args=connect_args)
|
return sqlmodel.create_engine(url, echo=echo_db_query, connect_args=connect_args)
|
||||||
@ -234,7 +231,7 @@ class Model(Base, sqlmodel.SQLModel): # pyright: ignore [reportGeneralTypeIssue
|
|||||||
Returns:
|
Returns:
|
||||||
tuple of (config, script_directory)
|
tuple of (config, script_directory)
|
||||||
"""
|
"""
|
||||||
config = alembic.config.Config(constants.ALEMBIC_CONFIG)
|
config = alembic.config.Config(environment.ALEMBIC_CONFIG)
|
||||||
return config, alembic.script.ScriptDirectory(
|
return config, alembic.script.ScriptDirectory(
|
||||||
config.get_main_option("script_location", default="version"),
|
config.get_main_option("script_location", default="version"),
|
||||||
)
|
)
|
||||||
@ -269,8 +266,8 @@ class Model(Base, sqlmodel.SQLModel): # pyright: ignore [reportGeneralTypeIssue
|
|||||||
def alembic_init(cls):
|
def alembic_init(cls):
|
||||||
"""Initialize alembic for the project."""
|
"""Initialize alembic for the project."""
|
||||||
alembic.command.init(
|
alembic.command.init(
|
||||||
config=alembic.config.Config(constants.ALEMBIC_CONFIG),
|
config=alembic.config.Config(environment.ALEMBIC_CONFIG),
|
||||||
directory=str(Path(constants.ALEMBIC_CONFIG).parent / "alembic"),
|
directory=str(environment.ALEMBIC_CONFIG.parent / "alembic"),
|
||||||
)
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@ -290,7 +287,7 @@ class Model(Base, sqlmodel.SQLModel): # pyright: ignore [reportGeneralTypeIssue
|
|||||||
Returns:
|
Returns:
|
||||||
True when changes have been detected.
|
True when changes have been detected.
|
||||||
"""
|
"""
|
||||||
if not Path(constants.ALEMBIC_CONFIG).exists():
|
if not environment.ALEMBIC_CONFIG.exists():
|
||||||
return False
|
return False
|
||||||
|
|
||||||
config, script_directory = cls._alembic_config()
|
config, script_directory = cls._alembic_config()
|
||||||
@ -391,7 +388,7 @@ class Model(Base, sqlmodel.SQLModel): # pyright: ignore [reportGeneralTypeIssue
|
|||||||
True - indicating the process was successful.
|
True - indicating the process was successful.
|
||||||
None - indicating the process was skipped.
|
None - indicating the process was skipped.
|
||||||
"""
|
"""
|
||||||
if not Path(constants.ALEMBIC_CONFIG).exists():
|
if not environment.ALEMBIC_CONFIG.exists():
|
||||||
return
|
return
|
||||||
|
|
||||||
with cls.get_db_engine().connect() as connection:
|
with cls.get_db_engine().connect() as connection:
|
||||||
|
@ -13,7 +13,7 @@ from reflex_cli.deployments import deployments_cli
|
|||||||
from reflex_cli.utils import dependency
|
from reflex_cli.utils import dependency
|
||||||
|
|
||||||
from reflex import constants
|
from reflex import constants
|
||||||
from reflex.config import get_config
|
from reflex.config import environment, get_config
|
||||||
from reflex.custom_components.custom_components import custom_components_cli
|
from reflex.custom_components.custom_components import custom_components_cli
|
||||||
from reflex.state import reset_disk_state_manager
|
from reflex.state import reset_disk_state_manager
|
||||||
from reflex.utils import console, redir, telemetry
|
from reflex.utils import console, redir, telemetry
|
||||||
@ -274,9 +274,17 @@ def run(
|
|||||||
constants.Env.DEV, help="The environment to run the app in."
|
constants.Env.DEV, help="The environment to run the app in."
|
||||||
),
|
),
|
||||||
frontend: bool = typer.Option(
|
frontend: bool = typer.Option(
|
||||||
False, "--frontend-only", help="Execute only frontend."
|
False,
|
||||||
|
"--frontend-only",
|
||||||
|
help="Execute only frontend.",
|
||||||
|
envvar=constants.ENV_FRONTEND_ONLY_ENV_VAR,
|
||||||
|
),
|
||||||
|
backend: bool = typer.Option(
|
||||||
|
False,
|
||||||
|
"--backend-only",
|
||||||
|
help="Execute only backend.",
|
||||||
|
envvar=constants.ENV_BACKEND_ONLY_ENV_VAR,
|
||||||
),
|
),
|
||||||
backend: bool = typer.Option(False, "--backend-only", help="Execute only backend."),
|
|
||||||
frontend_port: str = typer.Option(
|
frontend_port: str = typer.Option(
|
||||||
config.frontend_port, help="Specify a different frontend port."
|
config.frontend_port, help="Specify a different frontend port."
|
||||||
),
|
),
|
||||||
@ -291,6 +299,12 @@ def run(
|
|||||||
),
|
),
|
||||||
):
|
):
|
||||||
"""Run the app in the current directory."""
|
"""Run the app in the current directory."""
|
||||||
|
if frontend and backend:
|
||||||
|
console.error("Cannot use both --frontend-only and --backend-only options.")
|
||||||
|
raise typer.Exit(1)
|
||||||
|
os.environ[constants.ENV_BACKEND_ONLY_ENV_VAR] = str(backend).lower()
|
||||||
|
os.environ[constants.ENV_FRONTEND_ONLY_ENV_VAR] = str(frontend).lower()
|
||||||
|
|
||||||
_run(env, frontend, backend, frontend_port, backend_port, backend_host, loglevel)
|
_run(env, frontend, backend, frontend_port, backend_port, backend_host, loglevel)
|
||||||
|
|
||||||
|
|
||||||
@ -406,7 +420,7 @@ def db_init():
|
|||||||
return
|
return
|
||||||
|
|
||||||
# Check the alembic config.
|
# Check the alembic config.
|
||||||
if Path(constants.ALEMBIC_CONFIG).exists():
|
if environment.ALEMBIC_CONFIG.exists():
|
||||||
console.error(
|
console.error(
|
||||||
"Database is already initialized. Use "
|
"Database is already initialized. Use "
|
||||||
"[bold]reflex db makemigrations[/bold] to create schema change "
|
"[bold]reflex db makemigrations[/bold] to create schema change "
|
||||||
|
@ -8,7 +8,6 @@ import copy
|
|||||||
import dataclasses
|
import dataclasses
|
||||||
import functools
|
import functools
|
||||||
import inspect
|
import inspect
|
||||||
import os
|
|
||||||
import pickle
|
import pickle
|
||||||
import sys
|
import sys
|
||||||
import uuid
|
import uuid
|
||||||
@ -64,6 +63,7 @@ from redis.exceptions import ResponseError
|
|||||||
import reflex.istate.dynamic
|
import reflex.istate.dynamic
|
||||||
from reflex import constants
|
from reflex import constants
|
||||||
from reflex.base import Base
|
from reflex.base import Base
|
||||||
|
from reflex.config import environment
|
||||||
from reflex.event import (
|
from reflex.event import (
|
||||||
BACKGROUND_TASK_MARKER,
|
BACKGROUND_TASK_MARKER,
|
||||||
Event,
|
Event,
|
||||||
@ -3274,11 +3274,7 @@ class StateManagerRedis(StateManager):
|
|||||||
)
|
)
|
||||||
except ResponseError:
|
except ResponseError:
|
||||||
# Some redis servers only allow out-of-band configuration, so ignore errors here.
|
# Some redis servers only allow out-of-band configuration, so ignore errors here.
|
||||||
ignore_config_error = os.environ.get(
|
if not environment.REFLEX_IGNORE_REDIS_CONFIG_ERROR:
|
||||||
"REFLEX_IGNORE_REDIS_CONFIG_ERROR",
|
|
||||||
None,
|
|
||||||
)
|
|
||||||
if not ignore_config_error:
|
|
||||||
raise
|
raise
|
||||||
async with self.redis.pubsub() as pubsub:
|
async with self.redis.pubsub() as pubsub:
|
||||||
await pubsub.psubscribe(lock_key_channel)
|
await pubsub.psubscribe(lock_key_channel)
|
||||||
|
@ -23,18 +23,6 @@ def set_env_json():
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def set_os_env(**kwargs):
|
|
||||||
"""Set os environment variables.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
kwargs: env key word args.
|
|
||||||
"""
|
|
||||||
for key, value in kwargs.items():
|
|
||||||
if not value:
|
|
||||||
continue
|
|
||||||
os.environ[key.upper()] = value
|
|
||||||
|
|
||||||
|
|
||||||
def generate_sitemap_config(deploy_url: str, export=False):
|
def generate_sitemap_config(deploy_url: str, export=False):
|
||||||
"""Generate the sitemap config file.
|
"""Generate the sitemap config file.
|
||||||
|
|
||||||
|
@ -135,3 +135,7 @@ class SetUndefinedStateVarError(ReflexError, AttributeError):
|
|||||||
|
|
||||||
class StateSchemaMismatchError(ReflexError, TypeError):
|
class StateSchemaMismatchError(ReflexError, TypeError):
|
||||||
"""Raised when the serialized schema of a state class does not match the current schema."""
|
"""Raised when the serialized schema of a state class does not match the current schema."""
|
||||||
|
|
||||||
|
|
||||||
|
class EnvironmentVarValueError(ReflexError, ValueError):
|
||||||
|
"""Raised when an environment variable is set to an invalid value."""
|
||||||
|
@ -15,7 +15,7 @@ from urllib.parse import urljoin
|
|||||||
import psutil
|
import psutil
|
||||||
|
|
||||||
from reflex import constants
|
from reflex import constants
|
||||||
from reflex.config import get_config
|
from reflex.config import environment, get_config
|
||||||
from reflex.constants.base import LogLevel
|
from reflex.constants.base import LogLevel
|
||||||
from reflex.utils import console, path_ops
|
from reflex.utils import console, path_ops
|
||||||
from reflex.utils.prerequisites import get_web_dir
|
from reflex.utils.prerequisites import get_web_dir
|
||||||
@ -184,7 +184,7 @@ def should_use_granian():
|
|||||||
Returns:
|
Returns:
|
||||||
True if Granian should be used.
|
True if Granian should be used.
|
||||||
"""
|
"""
|
||||||
return os.getenv("REFLEX_USE_GRANIAN", "0") == "1"
|
return environment.REFLEX_USE_GRANIAN
|
||||||
|
|
||||||
|
|
||||||
def get_app_module():
|
def get_app_module():
|
||||||
@ -496,6 +496,24 @@ def is_prod_mode() -> bool:
|
|||||||
return current_mode == constants.Env.PROD.value
|
return current_mode == constants.Env.PROD.value
|
||||||
|
|
||||||
|
|
||||||
|
def is_frontend_only() -> bool:
|
||||||
|
"""Check if the app is running in frontend-only mode.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
True if the app is running in frontend-only mode.
|
||||||
|
"""
|
||||||
|
return os.environ.get(constants.ENV_FRONTEND_ONLY_ENV_VAR, "").lower() == "true"
|
||||||
|
|
||||||
|
|
||||||
|
def is_backend_only() -> bool:
|
||||||
|
"""Check if the app is running in backend-only mode.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
True if the app is running in backend-only mode.
|
||||||
|
"""
|
||||||
|
return os.environ.get(constants.ENV_BACKEND_ONLY_ENV_VAR, "").lower() == "true"
|
||||||
|
|
||||||
|
|
||||||
def should_skip_compile() -> bool:
|
def should_skip_compile() -> bool:
|
||||||
"""Whether the app should skip compile.
|
"""Whether the app should skip compile.
|
||||||
|
|
||||||
|
@ -1,9 +1,8 @@
|
|||||||
"""Helpers for downloading files from the network."""
|
"""Helpers for downloading files from the network."""
|
||||||
|
|
||||||
import os
|
|
||||||
|
|
||||||
import httpx
|
import httpx
|
||||||
|
|
||||||
|
from ..config import environment
|
||||||
from . import console
|
from . import console
|
||||||
|
|
||||||
|
|
||||||
@ -13,8 +12,7 @@ def _httpx_verify_kwarg() -> bool:
|
|||||||
Returns:
|
Returns:
|
||||||
True if SSL verification is enabled, False otherwise
|
True if SSL verification is enabled, False otherwise
|
||||||
"""
|
"""
|
||||||
ssl_no_verify = os.environ.get("SSL_NO_VERIFY", "").lower() in ["true", "1", "yes"]
|
return not environment.SSL_NO_VERIFY
|
||||||
return not ssl_no_verify
|
|
||||||
|
|
||||||
|
|
||||||
def get(url: str, **kwargs) -> httpx.Response:
|
def get(url: str, **kwargs) -> httpx.Response:
|
||||||
|
@ -9,6 +9,7 @@ import shutil
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
from reflex import constants
|
from reflex import constants
|
||||||
|
from reflex.config import environment
|
||||||
|
|
||||||
# Shorthand for join.
|
# Shorthand for join.
|
||||||
join = os.linesep.join
|
join = os.linesep.join
|
||||||
@ -129,30 +130,13 @@ def which(program: str | Path) -> str | Path | None:
|
|||||||
return shutil.which(str(program))
|
return shutil.which(str(program))
|
||||||
|
|
||||||
|
|
||||||
def use_system_install(var_name: str) -> bool:
|
|
||||||
"""Check if the system install should be used.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
var_name: The name of the environment variable.
|
|
||||||
|
|
||||||
Raises:
|
|
||||||
ValueError: If the variable name is invalid.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
Whether the associated env var should use the system install.
|
|
||||||
"""
|
|
||||||
if not var_name.startswith("REFLEX_USE_SYSTEM_"):
|
|
||||||
raise ValueError("Invalid system install variable name.")
|
|
||||||
return os.getenv(var_name, "").lower() in ["true", "1", "yes"]
|
|
||||||
|
|
||||||
|
|
||||||
def use_system_node() -> bool:
|
def use_system_node() -> bool:
|
||||||
"""Check if the system node should be used.
|
"""Check if the system node should be used.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Whether the system node should be used.
|
Whether the system node should be used.
|
||||||
"""
|
"""
|
||||||
return use_system_install(constants.Node.USE_SYSTEM_VAR)
|
return environment.REFLEX_USE_SYSTEM_NODE
|
||||||
|
|
||||||
|
|
||||||
def use_system_bun() -> bool:
|
def use_system_bun() -> bool:
|
||||||
@ -161,7 +145,7 @@ def use_system_bun() -> bool:
|
|||||||
Returns:
|
Returns:
|
||||||
Whether the system bun should be used.
|
Whether the system bun should be used.
|
||||||
"""
|
"""
|
||||||
return use_system_install(constants.Bun.USE_SYSTEM_VAR)
|
return environment.REFLEX_USE_SYSTEM_BUN
|
||||||
|
|
||||||
|
|
||||||
def get_node_bin_path() -> Path | None:
|
def get_node_bin_path() -> Path | None:
|
||||||
|
@ -33,7 +33,7 @@ from redis.asyncio import Redis
|
|||||||
|
|
||||||
from reflex import constants, model
|
from reflex import constants, model
|
||||||
from reflex.compiler import templates
|
from reflex.compiler import templates
|
||||||
from reflex.config import Config, get_config
|
from reflex.config import Config, environment, get_config
|
||||||
from reflex.utils import console, net, path_ops, processes
|
from reflex.utils import console, net, path_ops, processes
|
||||||
from reflex.utils.exceptions import GeneratedCodeHasNoFunctionDefs
|
from reflex.utils.exceptions import GeneratedCodeHasNoFunctionDefs
|
||||||
from reflex.utils.format import format_library_name
|
from reflex.utils.format import format_library_name
|
||||||
@ -69,8 +69,7 @@ def get_web_dir() -> Path:
|
|||||||
Returns:
|
Returns:
|
||||||
The working directory.
|
The working directory.
|
||||||
"""
|
"""
|
||||||
workdir = Path(os.getenv("REFLEX_WEB_WORKDIR", constants.Dirs.WEB))
|
return environment.REFLEX_WEB_WORKDIR
|
||||||
return workdir
|
|
||||||
|
|
||||||
|
|
||||||
def _python_version_check():
|
def _python_version_check():
|
||||||
@ -250,7 +249,7 @@ def windows_npm_escape_hatch() -> bool:
|
|||||||
Returns:
|
Returns:
|
||||||
If the user has set REFLEX_USE_NPM.
|
If the user has set REFLEX_USE_NPM.
|
||||||
"""
|
"""
|
||||||
return os.environ.get("REFLEX_USE_NPM", "").lower() in ["true", "1", "yes"]
|
return environment.REFLEX_USE_NPM
|
||||||
|
|
||||||
|
|
||||||
def get_app(reload: bool = False) -> ModuleType:
|
def get_app(reload: bool = False) -> ModuleType:
|
||||||
@ -992,7 +991,7 @@ def needs_reinit(frontend: bool = True) -> bool:
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
# Make sure the .reflex directory exists.
|
# Make sure the .reflex directory exists.
|
||||||
if not constants.Reflex.DIR.exists():
|
if not environment.REFLEX_DIR.exists():
|
||||||
return True
|
return True
|
||||||
|
|
||||||
# Make sure the .web directory exists in frontend mode.
|
# Make sure the .web directory exists in frontend mode.
|
||||||
@ -1097,7 +1096,7 @@ def ensure_reflex_installation_id() -> Optional[int]:
|
|||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
initialize_reflex_user_directory()
|
initialize_reflex_user_directory()
|
||||||
installation_id_file = constants.Reflex.DIR / "installation_id"
|
installation_id_file = environment.REFLEX_DIR / "installation_id"
|
||||||
|
|
||||||
installation_id = None
|
installation_id = None
|
||||||
if installation_id_file.exists():
|
if installation_id_file.exists():
|
||||||
@ -1122,7 +1121,7 @@ def ensure_reflex_installation_id() -> Optional[int]:
|
|||||||
def initialize_reflex_user_directory():
|
def initialize_reflex_user_directory():
|
||||||
"""Initialize the reflex user directory."""
|
"""Initialize the reflex user directory."""
|
||||||
# Create the reflex directory.
|
# Create the reflex directory.
|
||||||
path_ops.mkdir(constants.Reflex.DIR)
|
path_ops.mkdir(environment.REFLEX_DIR)
|
||||||
|
|
||||||
|
|
||||||
def initialize_frontend_dependencies():
|
def initialize_frontend_dependencies():
|
||||||
@ -1145,7 +1144,7 @@ def check_db_initialized() -> bool:
|
|||||||
Returns:
|
Returns:
|
||||||
True if alembic is initialized (or if database is not used).
|
True if alembic is initialized (or if database is not used).
|
||||||
"""
|
"""
|
||||||
if get_config().db_url is not None and not Path(constants.ALEMBIC_CONFIG).exists():
|
if get_config().db_url is not None and not environment.ALEMBIC_CONFIG.exists():
|
||||||
console.error(
|
console.error(
|
||||||
"Database is not initialized. Run [bold]reflex db init[/bold] first."
|
"Database is not initialized. Run [bold]reflex db init[/bold] first."
|
||||||
)
|
)
|
||||||
@ -1155,7 +1154,7 @@ def check_db_initialized() -> bool:
|
|||||||
|
|
||||||
def check_schema_up_to_date():
|
def check_schema_up_to_date():
|
||||||
"""Check if the sqlmodel metadata matches the current database schema."""
|
"""Check if the sqlmodel metadata matches the current database schema."""
|
||||||
if get_config().db_url is None or not Path(constants.ALEMBIC_CONFIG).exists():
|
if get_config().db_url is None or not environment.ALEMBIC_CONFIG.exists():
|
||||||
return
|
return
|
||||||
with model.Model.get_db_engine().connect() as connection:
|
with model.Model.get_db_engine().connect() as connection:
|
||||||
try:
|
try:
|
||||||
|
@ -1,9 +1,8 @@
|
|||||||
"""Utilities for working with registries."""
|
"""Utilities for working with registries."""
|
||||||
|
|
||||||
import os
|
|
||||||
|
|
||||||
import httpx
|
import httpx
|
||||||
|
|
||||||
|
from reflex.config import environment
|
||||||
from reflex.utils import console, net
|
from reflex.utils import console, net
|
||||||
|
|
||||||
|
|
||||||
@ -56,7 +55,4 @@ def _get_npm_registry() -> str:
|
|||||||
Returns:
|
Returns:
|
||||||
str:
|
str:
|
||||||
"""
|
"""
|
||||||
if npm_registry := os.environ.get("NPM_CONFIG_REGISTRY", ""):
|
return environment.NPM_CONFIG_REGISTRY or get_best_registry()
|
||||||
return npm_registry
|
|
||||||
else:
|
|
||||||
return get_best_registry()
|
|
||||||
|
@ -274,6 +274,20 @@ def is_optional(cls: GenericType) -> bool:
|
|||||||
return is_union(cls) and type(None) in get_args(cls)
|
return is_union(cls) and type(None) in get_args(cls)
|
||||||
|
|
||||||
|
|
||||||
|
def value_inside_optional(cls: GenericType) -> GenericType:
|
||||||
|
"""Get the value inside an Optional type or the original type.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
cls: The class to check.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The value inside the Optional type or the original type.
|
||||||
|
"""
|
||||||
|
if is_union(cls) and len(args := get_args(cls)) >= 2 and type(None) in args:
|
||||||
|
return unionize(*[arg for arg in args if arg is not type(None)])
|
||||||
|
return cls
|
||||||
|
|
||||||
|
|
||||||
def get_property_hint(attr: Any | None) -> GenericType | None:
|
def get_property_hint(attr: Any | None) -> GenericType | None:
|
||||||
"""Check if an attribute is a property and return its type hint.
|
"""Check if an attribute is a property and return its type hint.
|
||||||
|
|
||||||
|
@ -1557,8 +1557,8 @@ class ComputedVar(Var[RETURN_TYPE]):
|
|||||||
"return", Any
|
"return", Any
|
||||||
)
|
)
|
||||||
|
|
||||||
kwargs["_js_expr"] = kwargs.pop("_js_expr", fget.__name__)
|
kwargs.setdefault("_js_expr", fget.__name__)
|
||||||
kwargs["_var_type"] = kwargs.pop("_var_type", hint)
|
kwargs.setdefault("_var_type", hint)
|
||||||
|
|
||||||
Var.__init__(
|
Var.__init__(
|
||||||
self,
|
self,
|
||||||
@ -1567,6 +1567,9 @@ class ComputedVar(Var[RETURN_TYPE]):
|
|||||||
_var_data=kwargs.pop("_var_data", None),
|
_var_data=kwargs.pop("_var_data", None),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if kwargs:
|
||||||
|
raise TypeError(f"Unexpected keyword arguments: {tuple(kwargs)}")
|
||||||
|
|
||||||
if backend is None:
|
if backend is None:
|
||||||
backend = fget.__name__.startswith("_")
|
backend = fget.__name__.startswith("_")
|
||||||
|
|
||||||
|
@ -6,6 +6,7 @@ import pytest
|
|||||||
|
|
||||||
import reflex as rx
|
import reflex as rx
|
||||||
import reflex.config
|
import reflex.config
|
||||||
|
from reflex.config import environment
|
||||||
from reflex.constants import Endpoint
|
from reflex.constants import Endpoint
|
||||||
|
|
||||||
|
|
||||||
@ -185,7 +186,7 @@ def test_replace_defaults(
|
|||||||
|
|
||||||
|
|
||||||
def reflex_dir_constant():
|
def reflex_dir_constant():
|
||||||
return rx.constants.Reflex.DIR
|
return environment.REFLEX_DIR
|
||||||
|
|
||||||
|
|
||||||
def test_reflex_dir_env_var(monkeypatch, tmp_path):
|
def test_reflex_dir_env_var(monkeypatch, tmp_path):
|
||||||
|
Loading…
Reference in New Issue
Block a user