diff --git a/reflex/config.py b/reflex/config.py index 6977d745631..955adb1577f 100644 --- a/reflex/config.py +++ b/reflex/config.py @@ -377,7 +377,7 @@ def _add_builtin_plugins(self): if not any(isinstance(p, plugin) for p in self.plugins): console.warn( f"`{plugin_name}` plugin is enabled by default, but not explicitly added to the config. " - "If you want to use it, please add it to the `plugins` list in your config inside of `rxconfig.py`. " + f"If you want to use it, please add it to the `plugins` list in your config inside of `{constants.Config.FILE}`. " f"To disable this plugin, set `disable_plugins` to `{[plugin_name, *self.disable_plugins]!r}`.", ) self.plugins.append(plugin()) @@ -385,7 +385,7 @@ def _add_builtin_plugins(self): if any(isinstance(p, plugin) for p in self.plugins): console.warn( f"`{plugin_name}` is disabled in the config, but it is still present in the `plugins` list. " - "Please remove it from the `plugins` list in your config inside of `rxconfig.py`.", + f"Please remove it from the `plugins` list in your config inside of `{constants.Config.FILE}`.", ) for disabled_plugin in self.disable_plugins: @@ -399,7 +399,7 @@ def _add_builtin_plugins(self): ): console.warn( f"`{disabled_plugin}` is disabled in the config, but it is not a built-in plugin. " - "Please remove it from the `disable_plugins` list in your config inside of `rxconfig.py`.", + f"Please remove it from the `disable_plugins` list in your config inside of `{constants.Config.FILE}`.", ) @classmethod diff --git a/reflex/constants/config.py b/reflex/constants/config.py index 6ae12a92aeb..a06bba20e8f 100644 --- a/reflex/constants/config.py +++ b/reflex/constants/config.py @@ -1,5 +1,6 @@ """Config constants.""" +import os from pathlib import Path from types import SimpleNamespace @@ -10,14 +11,45 @@ # Alembic migrations ALEMBIC_CONFIG = "alembic.ini" +# Default config module name. +_DEFAULT_CONFIG_MODULE = "rxconfig" -class Config(SimpleNamespace): - """Config constants.""" - # The name of the reflex config module. - MODULE = "rxconfig" - # The python config file. - FILE = Path(f"{MODULE}{Ext.PY}") +def _get_config_module() -> str: + """Get the config module name from env or default. + + Returns: + The config module name. + """ + return os.environ.get("REFLEX_CONFIG_MODULE", _DEFAULT_CONFIG_MODULE) + + +def _get_config_file() -> Path: + """Get the config file path from env or derive from module name. + + Returns: + The config file path. + """ + env_file = os.environ.get("REFLEX_CONFIG_FILE") + if env_file: + return Path(env_file) + return Path(f"{_get_config_module()}{Ext.PY}") + + +class _ConfigMeta(type(SimpleNamespace)): + """Metaclass for Config that makes MODULE and FILE dynamic class attributes.""" + + @property + def MODULE(cls) -> str: # noqa: N802 + return _get_config_module() + + @property + def FILE(cls) -> Path: # noqa: N802 + return _get_config_file() + + +class Config(SimpleNamespace, metaclass=_ConfigMeta): + """Config constants.""" class Expiration(SimpleNamespace): diff --git a/reflex/utils/exec.py b/reflex/utils/exec.py index ac6f720cda8..26979592105 100644 --- a/reflex/utils/exec.py +++ b/reflex/utils/exec.py @@ -421,7 +421,7 @@ def get_reload_paths() -> Sequence[Path]: while module_path.parent.name and _has_child_file(module_path, "__init__.py"): if ( - _has_child_file(module_path, "rxconfig.py") + _has_child_file(module_path, constants.Config.FILE.name) and module_path == Path.cwd() ): init_file = module_path / "__init__.py" @@ -436,7 +436,7 @@ def get_reload_paths() -> Sequence[Path]: init_file.unlink() break - # go up a level to find dir without `__init__.py` or with `rxconfig.py` + # go up a level to find dir without `__init__.py` or with config file module_path = module_path.parent reload_paths = [module_path] diff --git a/reflex/utils/prerequisites.py b/reflex/utils/prerequisites.py index 886d1dead96..fee9c0a037d 100644 --- a/reflex/utils/prerequisites.py +++ b/reflex/utils/prerequisites.py @@ -149,7 +149,7 @@ def _check_app_name(config: Config): """ if not config.app_name: msg = ( - "Cannot get the app module because `app_name` is not set in rxconfig! " + f"Cannot get the app module because `app_name` is not set in {constants.Config.FILE}! " "If this error occurs in a reflex test case, ensure that `get_app` is mocked." ) raise RuntimeError(msg) @@ -161,9 +161,9 @@ def _check_app_name(config: Config): if module_path is None: msg = f"Module {config.module} not found. " if config.app_module_import is not None: - msg += f"Ensure app_module_import='{config.app_module_import}' in rxconfig.py matches your folder structure." + msg += f"Ensure app_module_import='{config.app_module_import}' in {constants.Config.FILE} matches your folder structure." else: - msg += f"Ensure app_name='{config.app_name}' in rxconfig.py matches your folder structure." + msg += f"Ensure app_name='{config.app_name}' in {constants.Config.FILE} matches your folder structure." raise ModuleNotFoundError(msg) config._app_name_is_valid = True @@ -234,7 +234,7 @@ def get_and_validate_app( app_module = get_app(reload=reload) app = getattr(app_module, constants.CompileVars.APP) if not isinstance(app, App): - msg = "The app instance in the specified app_module_import in rxconfig must be an instance of rx.App." + msg = f"The app instance in the specified app_module_import in {constants.Config.FILE} must be an instance of rx.App." raise RuntimeError(msg) if check_if_schema_up_to_date: diff --git a/reflex/utils/rename.py b/reflex/utils/rename.py index a51e6c990b1..60736907c63 100644 --- a/reflex/utils/rename.py +++ b/reflex/utils/rename.py @@ -12,7 +12,7 @@ def rename_path_up_tree(full_path: str | Path, old_name: str, new_name: str) -> Path: """Rename all instances of `old_name` in the path (file and directories) to `new_name`. - The renaming stops when we reach the directory containing `rxconfig.py`. + The renaming stops when we reach the directory containing the config file. Args: full_path: The full path to start renaming from. @@ -27,8 +27,8 @@ def rename_path_up_tree(full_path: str | Path, old_name: str, new_name: str) -> while True: directory, base = current_path.parent, current_path.name - # Stop renaming when we reach the root dir (which contains rxconfig.py) - if current_path.is_dir() and (current_path / "rxconfig.py").exists(): + # Stop renaming when we reach the root dir (which contains the config file) + if current_path.is_dir() and (current_path / constants.Config.FILE.name).exists(): new_path = current_path break @@ -62,7 +62,7 @@ def rename_app(new_app_name: str, loglevel: constants.LogLevel): if not constants.Config.FILE.exists(): console.error( - "No rxconfig.py found. Make sure you are in the root directory of your app." + f"No {constants.Config.FILE} found. Make sure you are in the root directory of your app." ) raise SystemExit(1) @@ -88,7 +88,7 @@ def rename_app(new_app_name: str, loglevel: constants.LogLevel): def rename_imports_and_app_name(file_path: str | Path, old_name: str, new_name: str): - """Rename imports the file using string replacement as well as app_name in rxconfig.py. + """Rename imports the file using string replacement as well as app_name in the config file. Args: file_path: The file to process.