diff --git a/reflex/reflex.py b/reflex/reflex.py index 7b74071f3..1e4d57f28 100644 --- a/reflex/reflex.py +++ b/reflex/reflex.py @@ -18,6 +18,7 @@ from reflex import constants from reflex.config import environment, get_config from reflex.custom_components.custom_components import custom_components_cli from reflex.utils import console, telemetry +from reflex.utils.exec import set_env_mode # Disable typer+rich integration for help panels typer.core.rich = None # type: ignore @@ -136,7 +137,7 @@ def _run( """Run the app in the given directory.""" # Set env mode in the environment # This must be set before importing modules that contain rx.State subclasses - environment.REFLEX_ENV_MODE.set(env) + set_env_mode(env) from reflex.state import reset_disk_state_manager from reflex.utils import build, exec, prerequisites, processes @@ -318,7 +319,7 @@ def export( """Export the app to a zip file.""" # Set env mode in the environment # This must be set before importing modules that contain rx.State subclasses - environment.REFLEX_ENV_MODE.set(constants.Env.PROD) + set_env_mode(constants.Env.PROD) from reflex.utils import export as export_utils from reflex.utils import prerequisites @@ -668,7 +669,7 @@ def deployv2( """Deploy the app to the Reflex hosting service.""" # Set env mode in the environment # This must be set before importing modules that contain rx.State subclasses - environment.REFLEX_ENV_MODE.set(constants.Env.PROD) + set_env_mode(constants.Env.PROD) from reflex_cli.v2 import cli as hosting_cli from reflex_cli.v2.utils import dependency diff --git a/reflex/state.py b/reflex/state.py index c1e423f9e..c25ff745f 100644 --- a/reflex/state.py +++ b/reflex/state.py @@ -554,18 +554,23 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow): if parent_state is not None: cls.inherited_vars = parent_state.vars cls.inherited_backend_vars = parent_state.backend_vars + else: + # Track class_subclasses of the BaseState + parent_state = BaseState - # Check if another substate class with the same name has already been defined. - if cls.get_name() in set( - c.get_name() for c in parent_state.class_subclasses - ): - # This should not happen, since we have added module prefix to state names in #3214 - raise StateValueError( - f"The substate class '{cls.get_name()}' has been defined multiple times. " - "Shadowing substate classes is not allowed." - ) - # Track this new subclass in the parent state's subclasses set. - parent_state.class_subclasses.add(cls) + # Check if another substate class with the same name has already been defined. + #if not _reflex_internal_reinit and cls.get_name() in set( + if cls.get_name() in set( + c.get_name() for c in parent_state.class_subclasses + ): + breakpoint() + # This should not happen, since we have added module prefix to state names in #3214 + raise StateValueError( + f"The substate class '{cls.get_name()}' has been defined multiple times. " + "Shadowing substate classes is not allowed." + ) + # Track this new subclass in the parent state's subclasses set. + parent_state.class_subclasses.add(cls) # Get computed vars. computed_vars = cls._get_computed_vars() @@ -970,6 +975,21 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow): name = ".".join((parent_state.get_full_name(), name)) return name + @classmethod + def _reset_name_cache(cls): + """Reset `get_name` and `get_full_name` cache to use minified state names.""" + subclasses = sorted(cls.class_subclasses, key=lambda x: x.__name__) + cls.get_name.cache_clear() + cls.get_full_name.cache_clear() + if cls is BaseState: + cls.class_subclasses.clear() + else: + cls.__init_subclass__() + print(f"REINIT {cls.__name__} ({cls.get_full_name()})") + print(minified_state_names) + for subcls in subclasses: + subcls._reset_name_cache() + @classmethod @functools.lru_cache() def get_class_substate(cls, path: Sequence[str] | str) -> Type[BaseState]: @@ -1658,6 +1678,8 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow): raise ValueError( "The value of state cannot be None when processing an event." ) + if name not in substate.event_handlers: + breakpoint() handler = substate.event_handlers[name] # For background tasks, proxy the state diff --git a/reflex/utils/exec.py b/reflex/utils/exec.py index 5291de095..56c16f712 100644 --- a/reflex/utils/exec.py +++ b/reflex/utils/exec.py @@ -497,6 +497,19 @@ def is_prod_mode() -> bool: return current_mode == constants.Env.PROD +def set_env_mode(mode: constants.Env): + """Mark the app as running in dev or prod mode. + + Args: + mode: The mode to set the app to. + """ + environment.REFLEX_ENV_MODE.set(mode) + from reflex.state import BaseState + + # Ensure that minified names are or are not used based on the mode. + BaseState._reset_name_cache() + + def is_frontend_only() -> bool: """Check if the app is running in frontend-only mode.