diff --git a/benchmarks/test_benchmark_compile_components.py b/benchmarks/test_benchmark_compile_components.py index 81d0c2e89..ba7e9c571 100644 --- a/benchmarks/test_benchmark_compile_components.py +++ b/benchmarks/test_benchmark_compile_components.py @@ -122,7 +122,7 @@ def AppWithTenComponentsOnePage(): def index() -> rx.Component: return rx.center(rx.vstack(*render_component(1))) - app = rx.App(state=rx.State) + app = rx.App(_state=rx.State) app.add_page(index) @@ -133,7 +133,7 @@ def AppWithHundredComponentOnePage(): def index() -> rx.Component: return rx.center(rx.vstack(*render_component(100))) - app = rx.App(state=rx.State) + app = rx.App(_state=rx.State) app.add_page(index) @@ -144,7 +144,7 @@ def AppWithThousandComponentsOnePage(): def index() -> rx.Component: return rx.center(rx.vstack(*render_component(1000))) - app = rx.App(state=rx.State) + app = rx.App(_state=rx.State) app.add_page(index) diff --git a/benchmarks/test_benchmark_compile_pages.py b/benchmarks/test_benchmark_compile_pages.py index 292882b74..a5c85810e 100644 --- a/benchmarks/test_benchmark_compile_pages.py +++ b/benchmarks/test_benchmark_compile_pages.py @@ -162,7 +162,7 @@ def AppWithOnePage(): height="100vh", ) - app = rx.App(state=rx.State) + app = rx.App(_state=rx.State) app.add_page(index) @@ -170,7 +170,7 @@ def AppWithTenPages(): """A reflex app with 10 pages.""" import reflex as rx - app = rx.App(state=rx.State) + app = rx.App(_state=rx.State) render_multiple_pages(app, 10) @@ -178,7 +178,7 @@ def AppWithHundredPages(): """A reflex app with 100 pages.""" import reflex as rx - app = rx.App(state=rx.State) + app = rx.App(_state=rx.State) render_multiple_pages(app, 100) @@ -186,7 +186,7 @@ def AppWithThousandPages(): """A reflex app with Thousand pages.""" import reflex as rx - app = rx.App(state=rx.State) + app = rx.App(_state=rx.State) render_multiple_pages(app, 1000) @@ -194,7 +194,7 @@ def AppWithTenThousandPages(): """A reflex app with ten thousand pages.""" import reflex as rx - app = rx.App(state=rx.State) + app = rx.App(_state=rx.State) render_multiple_pages(app, 10000) diff --git a/reflex/app.py b/reflex/app.py index 7e868e730..f0f4baaa4 100644 --- a/reflex/app.py +++ b/reflex/app.py @@ -251,36 +251,36 @@ class App(MiddlewareMixin, LifespanMixin): # Attributes to add to the html root tag of every page. html_custom_attrs: Optional[Dict[str, str]] = None - # A map from a route to an unevaluated page. PRIVATE. - unevaluated_pages: Dict[str, UnevaluatedPage] = dataclasses.field( + # A map from a route to an unevaluated page. + _unevaluated_pages: Dict[str, UnevaluatedPage] = dataclasses.field( default_factory=dict ) - # A map from a page route to the component to render. Users should use `add_page`. PRIVATE. - pages: Dict[str, Component] = dataclasses.field(default_factory=dict) + # A map from a page route to the component to render. Users should use `add_page`. + _pages: Dict[str, Component] = dataclasses.field(default_factory=dict) - # The backend API object. PRIVATE. - api: FastAPI = None # type: ignore + # The backend API object. + _api: FastAPI | None = None - # The state class to use for the app. PRIVATE. - state: Optional[Type[BaseState]] = None + # The state class to use for the app. + _state: Optional[Type[BaseState]] = None # Class to manage many client states. _state_manager: Optional[StateManager] = None - # Mapping from a route to event handlers to trigger when the page loads. PRIVATE. - load_events: Dict[str, List[IndividualEventType[[], Any]]] = dataclasses.field( + # Mapping from a route to event handlers to trigger when the page loads. + _load_events: Dict[str, List[IndividualEventType[[], Any]]] = dataclasses.field( default_factory=dict ) - # Admin dashboard to view and manage the database. PRIVATE. + # Admin dashboard to view and manage the database. admin_dash: Optional[AdminDash] = None - # The async server name space. PRIVATE. - event_namespace: Optional[EventNamespace] = None + # The async server name space. + _event_namespace: Optional[EventNamespace] = None - # Background tasks that are currently running. PRIVATE. - background_tasks: Set[asyncio.Task] = dataclasses.field(default_factory=set) + # Background tasks that are currently running. + _background_tasks: Set[asyncio.Task] = dataclasses.field(default_factory=set) # Frontend Error Handler Function frontend_exception_handler: Callable[[Exception], None] = ( @@ -292,6 +292,24 @@ class App(MiddlewareMixin, LifespanMixin): [Exception], Union[EventSpec, List[EventSpec], None] ] = default_backend_exception_handler + @property + def api(self) -> FastAPI | None: + """Get the backend api. + + Returns: + The backend api. + """ + return self._api + + @property + def event_namespace(self) -> EventNamespace | None: + """Get the event namespace. + + Returns: + The event namespace. + """ + return self._event_namespace + def __post_init__(self): """Initialize the app. @@ -311,7 +329,7 @@ class App(MiddlewareMixin, LifespanMixin): set_breakpoints(self.style.pop("breakpoints")) # Set up the API. - self.api = FastAPI(lifespan=self._run_lifespan_tasks) + self._api = FastAPI(lifespan=self._run_lifespan_tasks) self._add_cors() self._add_default_endpoints() @@ -334,8 +352,8 @@ class App(MiddlewareMixin, LifespanMixin): def _enable_state(self) -> None: """Enable state for the app.""" - if not self.state: - self.state = State + if not self._state: + self._state = State self._setup_state() def _setup_state(self) -> None: @@ -344,13 +362,13 @@ class App(MiddlewareMixin, LifespanMixin): Raises: RuntimeError: If the socket server is invalid. """ - if not self.state: + if not self._state: return config = get_config() # Set up the state manager. - self._state_manager = StateManager.create(state=self.state) + self._state_manager = StateManager.create(state=self._state) # Set up the Socket.IO AsyncServer. if not self.sio: @@ -381,12 +399,13 @@ class App(MiddlewareMixin, LifespanMixin): namespace = config.get_event_namespace() # Create the event namespace and attach the main app. Not related to any paths. - self.event_namespace = EventNamespace(namespace, self) + self._event_namespace = EventNamespace(namespace, self) # Register the event namespace with the socket. self.sio.register_namespace(self.event_namespace) # Mount the socket app with the API. - self.api.mount(str(constants.Endpoint.EVENT), socket_app) + if self.api: + self.api.mount(str(constants.Endpoint.EVENT), socket_app) # Check the exception handlers self._validate_exception_handlers() @@ -397,24 +416,35 @@ class App(MiddlewareMixin, LifespanMixin): Returns: The string representation of the app. """ - return f"" + return f"" def __call__(self) -> FastAPI: """Run the backend api instance. + Raises: + ValueError: If the app has not been initialized. + Returns: The backend api. """ + if not self.api: + raise ValueError("The app has not been initialized.") return self.api def _add_default_endpoints(self): """Add default api endpoints (ping).""" # To test the server. + if not self.api: + return + self.api.get(str(constants.Endpoint.PING))(ping) self.api.get(str(constants.Endpoint.HEALTH))(health) def _add_optional_endpoints(self): """Add optional api endpoints (_upload).""" + if not self.api: + return + if Upload.is_used: # To upload files. self.api.post(str(constants.Endpoint.UPLOAD))(upload(self)) @@ -432,6 +462,8 @@ class App(MiddlewareMixin, LifespanMixin): def _add_cors(self): """Add CORS middleware to the app.""" + if not self.api: + return self.api.add_middleware( cors.CORSMiddleware, allow_credentials=True, @@ -521,13 +553,13 @@ class App(MiddlewareMixin, LifespanMixin): # Check if the route given is valid verify_route_validity(route) - if route in self.unevaluated_pages and environment.RELOAD_CONFIG.is_set(): + if route in self._unevaluated_pages and environment.RELOAD_CONFIG.is_set(): # when the app is reloaded(typically for app harness tests), we should maintain # the latest render function of a route.This applies typically to decorated pages # since they are only added when app._compile is called. - self.unevaluated_pages.pop(route) + self._unevaluated_pages.pop(route) - if route in self.unevaluated_pages: + if route in self._unevaluated_pages: route_name = ( f"`{route}` or `/`" if route == constants.PageNames.INDEX_ROUTE @@ -540,15 +572,15 @@ class App(MiddlewareMixin, LifespanMixin): # Setup dynamic args for the route. # this state assignment is only required for tests using the deprecated state kwarg for App - state = self.state if self.state else State + state = self._state if self._state else State state.setup_dynamic_args(get_route_args(route)) if on_load: - self.load_events[route] = ( + self._load_events[route] = ( on_load if isinstance(on_load, list) else [on_load] ) - self.unevaluated_pages[route] = UnevaluatedPage( + self._unevaluated_pages[route] = UnevaluatedPage( component=component, route=route, title=title, @@ -563,10 +595,10 @@ class App(MiddlewareMixin, LifespanMixin): Args: route: The route of the page to compile. - save_page: If True, the compiled page is saved to self.pages. + save_page: If True, the compiled page is saved to self._pages. """ component, enable_state = compiler.compile_unevaluated_page( - route, self.unevaluated_pages[route], self.state, self.style, self.theme + route, self._unevaluated_pages[route], self._state, self.style, self.theme ) if enable_state: @@ -575,7 +607,7 @@ class App(MiddlewareMixin, LifespanMixin): # Add the page. self._check_routes_conflict(route) if save_page: - self.pages[route] = component + self._pages[route] = component def get_load_events(self, route: str) -> list[IndividualEventType[[], Any]]: """Get the load events for a route. @@ -589,7 +621,7 @@ class App(MiddlewareMixin, LifespanMixin): route = route.lstrip("/") if route == "": route = constants.PageNames.INDEX_ROUTE - return self.load_events.get(route, []) + return self._load_events.get(route, []) def _check_routes_conflict(self, new_route: str): """Verify if there is any conflict between the new route and any existing route. @@ -613,7 +645,7 @@ class App(MiddlewareMixin, LifespanMixin): constants.RouteRegex.SINGLE_CATCHALL_SEGMENT, constants.RouteRegex.DOUBLE_CATCHALL_SEGMENT, ) - for route in self.pages: + for route in self._pages: replaced_route = replace_brackets_with_keywords(route) for rw, r, nr in zip( replaced_route.split("/"), route.split("/"), new_route.split("/") @@ -671,6 +703,9 @@ class App(MiddlewareMixin, LifespanMixin): def _setup_admin_dash(self): """Setup the admin dash.""" # Get the admin dash. + if not self.api: + return + admin_dash = self.admin_dash if admin_dash and admin_dash.models: @@ -775,10 +810,10 @@ class App(MiddlewareMixin, LifespanMixin): def _setup_overlay_component(self): """If a State is not used and no overlay_component is specified, do not render the connection modal.""" - if self.state is None and self.overlay_component is default_overlay_component: + if self._state is None and self.overlay_component is default_overlay_component: self.overlay_component = None - for k, component in self.pages.items(): - self.pages[k] = self._add_overlay_to_component(component) + for k, component in self._pages.items(): + self._pages[k] = self._add_overlay_to_component(component) def _add_error_boundary_to_component(self, component: Component) -> Component: if self.error_boundary is None: @@ -790,14 +825,14 @@ class App(MiddlewareMixin, LifespanMixin): def _setup_error_boundary(self): """If a State is not used and no error_boundary is specified, do not render the error boundary.""" - if self.state is None and self.error_boundary is default_error_boundary: + if self._state is None and self.error_boundary is default_error_boundary: self.error_boundary = None - for k, component in self.pages.items(): + for k, component in self._pages.items(): # Skip the 404 page if k == constants.Page404.SLUG: continue - self.pages[k] = self._add_error_boundary_to_component(component) + self._pages[k] = self._add_error_boundary_to_component(component) def _apply_decorated_pages(self): """Add @rx.page decorated pages to the app. @@ -823,11 +858,11 @@ class App(MiddlewareMixin, LifespanMixin): Raises: VarDependencyError: When a computed var has an invalid dependency. """ - if not self.state: + if not self._state: return if not state: - state = self.state + state = self._state for var in state.computed_vars.values(): if not var._cache: @@ -853,13 +888,13 @@ class App(MiddlewareMixin, LifespanMixin): """ from reflex.utils.exceptions import ReflexRuntimeError - self.pages = {} + self._pages = {} def get_compilation_time() -> str: return str(datetime.now().time()).split(".")[0] # Render a default 404 page if the user didn't supply one - if constants.Page404.SLUG not in self.unevaluated_pages: + if constants.Page404.SLUG not in self._unevaluated_pages: self.add_page(route=constants.Page404.SLUG) # Fix up the style. @@ -877,7 +912,7 @@ class App(MiddlewareMixin, LifespanMixin): should_compile = self._should_compile() - for route in self.unevaluated_pages: + for route in self._unevaluated_pages: console.debug(f"Evaluating page: {route}") self._compile_page(route, save_page=should_compile) @@ -904,7 +939,7 @@ class App(MiddlewareMixin, LifespanMixin): progress.start() task = progress.add_task( f"[{get_compilation_time()}] Compiling:", - total=len(self.pages) + total=len(self._pages) + fixed_pages_within_executor + adhoc_steps_without_executor, ) @@ -923,7 +958,7 @@ class App(MiddlewareMixin, LifespanMixin): # This has to happen before compiling stateful components as that # prevents recursive functions from reaching all components. - for component in self.pages.values(): + for component in self._pages.values(): # Add component._get_all_imports() to all_imports. all_imports.update(component._get_all_imports()) @@ -938,12 +973,12 @@ class App(MiddlewareMixin, LifespanMixin): stateful_components_path, stateful_components_code, page_components, - ) = compiler.compile_stateful_components(self.pages.values()) + ) = compiler.compile_stateful_components(self._pages.values()) progress.advance(task) # Catch "static" apps (that do not define a rx.State subclass) which are trying to access rx.State. - if code_uses_state_contexts(stateful_components_code) and self.state is None: + if code_uses_state_contexts(stateful_components_code) and self._state is None: raise ReflexRuntimeError( "To access rx.State in frontend components, at least one " "subclass of rx.State must be defined in the app." @@ -980,10 +1015,10 @@ class App(MiddlewareMixin, LifespanMixin): max_workers=environment.REFLEX_COMPILE_THREADS.get() or None ) - for route, component in zip(self.pages, page_components): + for route, component in zip(self._pages, page_components): ExecutorSafeFunctions.COMPONENTS[route] = component - ExecutorSafeFunctions.STATE = self.state + ExecutorSafeFunctions.STATE = self._state with executor: result_futures = [] @@ -993,7 +1028,7 @@ class App(MiddlewareMixin, LifespanMixin): result_futures.append(f) # Compile the pre-compiled pages. - for route in self.pages: + for route in self._pages: _submit_work( ExecutorSafeFunctions.compile_page, route, @@ -1028,7 +1063,7 @@ class App(MiddlewareMixin, LifespanMixin): # Compile the contexts. compile_results.append( - compiler.compile_contexts(self.state, self.theme), + compiler.compile_contexts(self._state, self.theme), ) if self.theme is not None: # Fix #2992 by removing the top-level appearance prop @@ -1150,9 +1185,9 @@ class App(MiddlewareMixin, LifespanMixin): ) task = asyncio.create_task(_coro()) - self.background_tasks.add(task) + self._background_tasks.add(task) # Clean up task from background_tasks set when complete. - task.add_done_callback(self.background_tasks.discard) + task.add_done_callback(self._background_tasks.discard) return task def _validate_exception_handlers(self): diff --git a/reflex/testing.py b/reflex/testing.py index 00b29a1df..ec8b80f66 100644 --- a/reflex/testing.py +++ b/reflex/testing.py @@ -296,7 +296,7 @@ class AppHarness: self.app_instance = self.app_module.app if isinstance(self.app_instance._state_manager, StateManagerRedis): # Create our own redis connection for testing. - self.state_manager = StateManagerRedis.create(self.app_instance.state) + self.state_manager = StateManagerRedis.create(self.app_instance._state) else: self.state_manager = self.app_instance._state_manager @@ -324,7 +324,7 @@ class AppHarness: return _shutdown_redis def _start_backend(self, port=0): - if self.app_instance is None: + if self.app_instance is None or self.app_instance.api is None: raise RuntimeError("App was not initialized.") self.backend = uvicorn.Server( uvicorn.Config( @@ -353,12 +353,12 @@ class AppHarness: self.app_instance.state_manager, StateManagerRedis, ) - and self.app_instance.state is not None + and self.app_instance._state is not None ): with contextlib.suppress(RuntimeError): await self.app_instance.state_manager.close() self.app_instance._state_manager = StateManagerRedis.create( - state=self.app_instance.state, + state=self.app_instance._state, ) if not isinstance(self.app_instance.state_manager, StateManagerRedis): raise RuntimeError("Failed to reset state manager.") diff --git a/tests/integration/test_background_task.py b/tests/integration/test_background_task.py index d7fe20824..cb8fda019 100644 --- a/tests/integration/test_background_task.py +++ b/tests/integration/test_background_task.py @@ -172,7 +172,7 @@ def BackgroundTask(): rx.button("Reset", on_click=State.reset_counter, id="reset"), ) - app = rx.App(state=rx.State) + app = rx.App(_state=rx.State) app.add_page(index) @@ -288,7 +288,7 @@ def test_background_task( assert background_task._poll_for(lambda: counter.text == "620", timeout=40) # all tasks should have exited and cleaned up assert background_task._poll_for( - lambda: not background_task.app_instance.background_tasks # type: ignore + lambda: not background_task.app_instance._background_tasks # type: ignore ) diff --git a/tests/integration/test_call_script.py b/tests/integration/test_call_script.py index be0bafdbb..f57dd2850 100644 --- a/tests/integration/test_call_script.py +++ b/tests/integration/test_call_script.py @@ -188,7 +188,7 @@ def CallScript(): yield rx.call_script("inline_counter = 0; external_counter = 0") self.reset() - app = rx.App(state=rx.State) + app = rx.App(_state=rx.State) Path("assets/external.js").write_text(external_scripts) @app.add_page diff --git a/tests/integration/test_client_storage.py b/tests/integration/test_client_storage.py index 367409b1b..3618c779d 100644 --- a/tests/integration/test_client_storage.py +++ b/tests/integration/test_client_storage.py @@ -127,7 +127,7 @@ def ClientSide(): rx.box(ClientSideSubSubState.s1s, id="s1s"), ) - app = rx.App(state=rx.State) + app = rx.App(_state=rx.State) app.add_page(index) app.add_page(index, route="/foo") diff --git a/tests/integration/test_component_state.py b/tests/integration/test_component_state.py index 97624e7c5..381c1d23a 100644 --- a/tests/integration/test_component_state.py +++ b/tests/integration/test_component_state.py @@ -72,7 +72,7 @@ def ComponentStateApp(): State=_Counter, ) - app = rx.App(state=rx.State) # noqa + app = rx.App(_state=rx.State) # noqa @rx.page() def index(): diff --git a/tests/integration/test_connection_banner.py b/tests/integration/test_connection_banner.py index 18259fe3f..c2a912af6 100644 --- a/tests/integration/test_connection_banner.py +++ b/tests/integration/test_connection_banner.py @@ -36,7 +36,7 @@ def ConnectionBanner(): rx.button("Delay", id="delay", on_click=State.delay), ) - app = rx.App(state=rx.State) + app = rx.App(_state=rx.State) app.add_page(index) diff --git a/tests/integration/test_deploy_url.py b/tests/integration/test_deploy_url.py index 5c840d24d..8b5776260 100644 --- a/tests/integration/test_deploy_url.py +++ b/tests/integration/test_deploy_url.py @@ -26,7 +26,7 @@ def DeployUrlSample() -> None: rx.button("GOTO SELF", on_click=State.goto_self, id="goto_self") ) - app = rx.App(state=rx.State) + app = rx.App(_state=rx.State) app.add_page(index) diff --git a/tests/integration/test_dynamic_routes.py b/tests/integration/test_dynamic_routes.py index c210bde69..9032fd84c 100644 --- a/tests/integration/test_dynamic_routes.py +++ b/tests/integration/test_dynamic_routes.py @@ -138,7 +138,7 @@ def DynamicRoute(): def redirect_page(): return rx.fragment(rx.text("redirecting...")) - app = rx.App(state=rx.State) + app = rx.App(_state=rx.State) app.add_page(index, route="/page/[page_id]", on_load=DynamicState.on_load) # type: ignore app.add_page(index, route="/static/x", on_load=DynamicState.on_load) # type: ignore app.add_page(index) diff --git a/tests/integration/test_event_actions.py b/tests/integration/test_event_actions.py index 15f3c9877..cc8e97b09 100644 --- a/tests/integration/test_event_actions.py +++ b/tests/integration/test_event_actions.py @@ -156,7 +156,7 @@ def TestEventAction(): on_click=EventActionState.on_click("outer"), # type: ignore ) - app = rx.App(state=rx.State) + app = rx.App(_state=rx.State) app.add_page(index) diff --git a/tests/integration/test_event_chain.py b/tests/integration/test_event_chain.py index c4121ee94..5a933253a 100644 --- a/tests/integration/test_event_chain.py +++ b/tests/integration/test_event_chain.py @@ -144,7 +144,7 @@ def EventChain(): time.sleep(0.5) self.interim_value = "final" - app = rx.App(state=rx.State) + app = rx.App(_state=rx.State) token_input = rx.input( value=State.router.session.client_token, is_read_only=True, id="token" diff --git a/tests/integration/test_exception_handlers.py b/tests/integration/test_exception_handlers.py index a645d1de6..4d15bbf01 100644 --- a/tests/integration/test_exception_handlers.py +++ b/tests/integration/test_exception_handlers.py @@ -39,7 +39,7 @@ def TestApp(): """ print(1 / number) - app = rx.App(state=rx.State) + app = rx.App(_state=rx.State) @app.add_page def index(): diff --git a/tests/integration/test_form_submit.py b/tests/integration/test_form_submit.py index ea8750595..bdf54173c 100644 --- a/tests/integration/test_form_submit.py +++ b/tests/integration/test_form_submit.py @@ -30,7 +30,7 @@ def FormSubmit(form_component): def form_submit(self, form_data: Dict): self.form_data = form_data - app = rx.App(state=rx.State) + app = rx.App(_state=rx.State) @app.add_page def index(): @@ -90,7 +90,7 @@ def FormSubmitName(form_component): def form_submit(self, form_data: Dict): self.form_data = form_data - app = rx.App(state=rx.State) + app = rx.App(_state=rx.State) @app.add_page def index(): diff --git a/tests/integration/test_input.py b/tests/integration/test_input.py index e9fec7dc1..bddeca45f 100644 --- a/tests/integration/test_input.py +++ b/tests/integration/test_input.py @@ -16,7 +16,7 @@ def FullyControlledInput(): class State(rx.State): text: str = "initial" - app = rx.App(state=rx.State) + app = rx.App(_state=rx.State) @app.add_page def index(): diff --git a/tests/integration/test_login_flow.py b/tests/integration/test_login_flow.py index 1938672a3..7eb46ab39 100644 --- a/tests/integration/test_login_flow.py +++ b/tests/integration/test_login_flow.py @@ -45,7 +45,7 @@ def LoginSample(): rx.button("Do it", on_click=State.login, id="doit"), ) - app = rx.App(state=rx.State) + app = rx.App(_state=rx.State) app.add_page(index) app.add_page(login) diff --git a/tests/integration/test_server_side_event.py b/tests/integration/test_server_side_event.py index f04cc3beb..3050a4e36 100644 --- a/tests/integration/test_server_side_event.py +++ b/tests/integration/test_server_side_event.py @@ -38,7 +38,7 @@ def ServerSideEvent(): def set_value_return_c(self): return rx.set_value("c", "") - app = rx.App(state=rx.State) + app = rx.App(_state=rx.State) @app.add_page def index(): diff --git a/tests/integration/test_upload.py b/tests/integration/test_upload.py index 0331c15d6..07c3997b4 100644 --- a/tests/integration/test_upload.py +++ b/tests/integration/test_upload.py @@ -166,7 +166,7 @@ def UploadFile(): rx.text(UploadState.event_order.to_string(), id="event-order"), ) - app = rx.App(state=rx.State) + app = rx.App(_state=rx.State) app.add_page(index) diff --git a/tests/integration/test_var_operations.py b/tests/integration/test_var_operations.py index 7a7c8328d..86d68340a 100644 --- a/tests/integration/test_var_operations.py +++ b/tests/integration/test_var_operations.py @@ -39,7 +39,7 @@ def VarOperations(): dict2: Dict[int, int] = {3: 4} html_str: str = "
hello
" - app = rx.App(state=rx.State) + app = rx.App(_state=rx.State) @rx.memo def memo_comp(list1: List[int], int_var1: int, id: str): diff --git a/tests/integration/tests_playwright/test_datetime_operations.py b/tests/integration/tests_playwright/test_datetime_operations.py index fafd15c42..5e4506776 100644 --- a/tests/integration/tests_playwright/test_datetime_operations.py +++ b/tests/integration/tests_playwright/test_datetime_operations.py @@ -16,7 +16,7 @@ def DatetimeOperationsApp(): date2: datetime = datetime(2031, 1, 1) date3: datetime = datetime(2021, 1, 1) - app = rx.App(state=DtOperationsState) + app = rx.App(_state=DtOperationsState) @app.add_page def index(): diff --git a/tests/integration/tests_playwright/test_table.py b/tests/integration/tests_playwright/test_table.py index db716aa5b..bd399a840 100644 --- a/tests/integration/tests_playwright/test_table.py +++ b/tests/integration/tests_playwright/test_table.py @@ -20,7 +20,7 @@ def Table(): """App using table component.""" import reflex as rx - app = rx.App(state=rx.State) + app = rx.App(_state=rx.State) @app.add_page def index(): diff --git a/tests/units/middleware/test_hydrate_middleware.py b/tests/units/middleware/test_hydrate_middleware.py index 9ee8d8d25..7b02f8515 100644 --- a/tests/units/middleware/test_hydrate_middleware.py +++ b/tests/units/middleware/test_hydrate_middleware.py @@ -41,7 +41,7 @@ async def test_preprocess_no_events(hydrate_middleware, event1, mocker): mocker.patch("reflex.state.State.class_subclasses", {TestState}) state = State() update = await hydrate_middleware.preprocess( - app=App(state=State), + app=App(_state=State), event=event1, state=state, ) diff --git a/tests/units/test_app.py b/tests/units/test_app.py index f805f83ec..80e0be5fd 100644 --- a/tests/units/test_app.py +++ b/tests/units/test_app.py @@ -236,14 +236,14 @@ def test_add_page_default_route(app: App, index_page, about_page): index_page: The index page. about_page: The about page. """ - assert app.pages == {} - assert app.unevaluated_pages == {} + assert app._pages == {} + assert app._unevaluated_pages == {} app.add_page(index_page) app._compile_page("index") - assert app.pages.keys() == {"index"} + assert app._pages.keys() == {"index"} app.add_page(about_page) app._compile_page("about") - assert app.pages.keys() == {"index", "about"} + assert app._pages.keys() == {"index", "about"} def test_add_page_set_route(app: App, index_page, windows_platform: bool): @@ -255,10 +255,10 @@ def test_add_page_set_route(app: App, index_page, windows_platform: bool): windows_platform: Whether the system is windows. """ route = "test" if windows_platform else "/test" - assert app.unevaluated_pages == {} + assert app._unevaluated_pages == {} app.add_page(index_page, route=route) app._compile_page("test") - assert app.pages.keys() == {"test"} + assert app._pages.keys() == {"test"} def test_add_page_set_route_dynamic(index_page, windows_platform: bool): @@ -268,18 +268,18 @@ def test_add_page_set_route_dynamic(index_page, windows_platform: bool): index_page: The index page. windows_platform: Whether the system is windows. """ - app = App(state=EmptyState) - assert app.state is not None + app = App(_state=EmptyState) + assert app._state is not None route = "/test/[dynamic]" - assert app.unevaluated_pages == {} + assert app._unevaluated_pages == {} app.add_page(index_page, route=route) app._compile_page("test/[dynamic]") - assert app.pages.keys() == {"test/[dynamic]"} - assert "dynamic" in app.state.computed_vars - assert app.state.computed_vars["dynamic"]._deps(objclass=EmptyState) == { + assert app._pages.keys() == {"test/[dynamic]"} + assert "dynamic" in app._state.computed_vars + assert app._state.computed_vars["dynamic"]._deps(objclass=EmptyState) == { constants.ROUTER } - assert constants.ROUTER in app.state()._computed_var_dependencies + assert constants.ROUTER in app._state()._computed_var_dependencies def test_add_page_set_route_nested(app: App, index_page, windows_platform: bool): @@ -291,9 +291,9 @@ def test_add_page_set_route_nested(app: App, index_page, windows_platform: bool) windows_platform: Whether the system is windows. """ route = "test\\nested" if windows_platform else "/test/nested" - assert app.unevaluated_pages == {} + assert app._unevaluated_pages == {} app.add_page(index_page, route=route) - assert app.unevaluated_pages.keys() == {route.strip(os.path.sep)} + assert app._unevaluated_pages.keys() == {route.strip(os.path.sep)} def test_add_page_invalid_api_route(app: App, index_page): @@ -413,8 +413,8 @@ async def test_initialize_with_state(test_state: Type[ATestState], token: str): test_state: The default state. token: a Token. """ - app = App(state=test_state) - assert app.state == test_state + app = App(_state=test_state) + assert app._state == test_state # Get a state for a given token. state = await app.state_manager.get_state(_substate_key(token, test_state)) @@ -432,7 +432,7 @@ async def test_set_and_get_state(test_state): Args: test_state: The default state. """ - app = App(state=test_state) + app = App(_state=test_state) # Create two tokens. token1 = str(uuid.uuid4()) + f"_{test_state.get_full_name()}" @@ -827,7 +827,7 @@ async def test_upload_file_without_annotation(state, tmp_path, token): token: a Token. """ state._tmp_path = tmp_path - app = App(state=State) + app = App(_state=State) request_mock = unittest.mock.Mock() request_mock.headers = { @@ -861,7 +861,7 @@ async def test_upload_file_background(state, tmp_path, token): token: a Token. """ state._tmp_path = tmp_path - app = App(state=State) + app = App(_state=State) request_mock = unittest.mock.Mock() request_mock.headers = { @@ -938,8 +938,8 @@ def test_dynamic_arg_shadow( """ arg_name = "counter" route = f"/test/[{arg_name}]" - app = app_module_mock.app = App(state=DynamicState) - assert app.state is not None + app = app_module_mock.app = App(_state=DynamicState) + assert app._state is not None with pytest.raises(NameError): app.add_page(index_page, route=route, on_load=DynamicState.on_load) # type: ignore @@ -963,7 +963,7 @@ def test_multiple_dynamic_args( arg_name = "my_arg" route = f"/test/[{arg_name}]" route2 = f"/test2/[{arg_name}]" - app = app_module_mock.app = App(state=EmptyState) + app = app_module_mock.app = App(_state=EmptyState) app.add_page(index_page, route=route) app.add_page(index_page, route=route2) @@ -990,16 +990,16 @@ async def test_dynamic_route_var_route_change_completed_on_load( """ arg_name = "dynamic" route = f"/test/[{arg_name}]" - app = app_module_mock.app = App(state=DynamicState) - assert app.state is not None - assert arg_name not in app.state.vars + app = app_module_mock.app = App(_state=DynamicState) + assert app._state is not None + assert arg_name not in app._state.vars app.add_page(index_page, route=route, on_load=DynamicState.on_load) # type: ignore - assert arg_name in app.state.vars - assert arg_name in app.state.computed_vars - assert app.state.computed_vars[arg_name]._deps(objclass=DynamicState) == { + assert arg_name in app._state.vars + assert arg_name in app._state.computed_vars + assert app._state.computed_vars[arg_name]._deps(objclass=DynamicState) == { constants.ROUTER } - assert constants.ROUTER in app.state()._computed_var_dependencies + assert constants.ROUTER in app._state()._computed_var_dependencies substate_token = _substate_key(token, DynamicState) sid = "mock_sid" @@ -1174,7 +1174,7 @@ async def test_process_events(mocker, token: str): "headers": {}, "ip": "127.0.0.1", } - app = App(state=GenState) + app = App(_state=GenState) mocker.patch.object(app, "_postprocess", AsyncMock()) event = Event( @@ -1220,7 +1220,7 @@ def test_overlay_component( overlay_component: The overlay_component to pass to App. exp_page_child: The type of the expected child in the page fragment. """ - app = App(state=state, overlay_component=overlay_component) + app = App(_state=state, overlay_component=overlay_component) app._setup_overlay_component() if exp_page_child is None: assert app.overlay_component is None @@ -1243,7 +1243,7 @@ def test_overlay_component( # overlay components are wrapped during compile only app._compile_page("test") app._setup_overlay_component() - page = app.pages["test"] + page = app._pages["test"] if exp_page_child is not None: assert len(page.children) == 3 @@ -1361,52 +1361,52 @@ def test_app_wrap_priority(compilable_app: tuple[App, Path]): def test_app_state_determination(): """Test that the stateless status of an app is determined correctly.""" a1 = App() - assert a1.state is None + assert a1._state is None # No state, no router, no event handlers. a1.add_page(rx.box("Index"), route="/") - assert a1.state is None + assert a1._state is None # Add a page with `on_load` enables state. a1.add_page(rx.box("About"), route="/about", on_load=rx.console_log("")) a1._compile_page("about") - assert a1.state is not None + assert a1._state is not None a2 = App() - assert a2.state is None + assert a2._state is None # Referencing a state Var enables state. a2.add_page(rx.box(rx.text(GenState.value)), route="/") a2._compile_page("index") - assert a2.state is not None + assert a2._state is not None a3 = App() - assert a3.state is None + assert a3._state is None # Referencing router enables state. a3.add_page(rx.box(rx.text(State.router.page.full_path)), route="/") a3._compile_page("index") - assert a3.state is not None + assert a3._state is not None a4 = App() - assert a4.state is None + assert a4._state is None a4.add_page(rx.box(rx.button("Click", on_click=rx.console_log(""))), route="/") - assert a4.state is None + assert a4._state is None a4.add_page( rx.box(rx.button("Click", on_click=DynamicState.on_counter)), route="/page2" ) a4._compile_page("page2") - assert a4.state is not None + assert a4._state is not None def test_raise_on_state(): """Test that the state is set.""" # state kwargs is deprecated, we just make sure the app is created anyway. - _app = App(state=State) - assert _app.state is not None - assert issubclass(_app.state, State) + _app = App(_state=State) + assert _app._state is not None + assert issubclass(_app._state, State) def test_call_app(): @@ -1473,7 +1473,7 @@ def test_add_page_component_returning_tuple(): app._compile_page("index") app._compile_page("page2") - fragment_wrapper = app.pages["index"].children[0] + fragment_wrapper = app._pages["index"].children[0] assert isinstance(fragment_wrapper, Fragment) first_text = fragment_wrapper.children[0] assert isinstance(first_text, Text) @@ -1483,7 +1483,7 @@ def test_add_page_component_returning_tuple(): assert str(second_text.children[0].contents) == '"second"' # type: ignore # Test page with trailing comma. - page2_fragment_wrapper = app.pages["page2"].children[0] + page2_fragment_wrapper = app._pages["page2"].children[0] assert isinstance(page2_fragment_wrapper, Fragment) third_text = page2_fragment_wrapper.children[0] assert isinstance(third_text, Text) @@ -1557,7 +1557,7 @@ def test_app_with_valid_var_dependencies(compilable_app: tuple[App, Path]): def bar(self) -> str: return "bar" - app.state = ValidDepState + app._state = ValidDepState app._compile() @@ -1569,7 +1569,7 @@ def test_app_with_invalid_var_dependencies(compilable_app: tuple[App, Path]): def bar(self) -> str: return "bar" - app.state = InvalidDepState + app._state = InvalidDepState with pytest.raises(exceptions.VarDependencyError): app._compile() diff --git a/tests/units/test_route.py b/tests/units/test_route.py index 851c9cf35..62f1788d3 100644 --- a/tests/units/test_route.py +++ b/tests/units/test_route.py @@ -89,7 +89,7 @@ def app(): ], ) def test_check_routes_conflict_invalid(mocker, app, route1, route2): - mocker.patch.object(app, "pages", {route1: []}) + mocker.patch.object(app, "_pages", {route1: []}) with pytest.raises(ValueError): app._check_routes_conflict(route2) @@ -117,6 +117,6 @@ def test_check_routes_conflict_invalid(mocker, app, route1, route2): ], ) def test_check_routes_conflict_valid(mocker, app, route1, route2): - mocker.patch.object(app, "pages", {route1: []}) + mocker.patch.object(app, "_pages", {route1: []}) # test that running this does not throw an error. app._check_routes_conflict(route2) diff --git a/tests/units/test_state.py b/tests/units/test_state.py index b1e73a1f0..dfb068626 100644 --- a/tests/units/test_state.py +++ b/tests/units/test_state.py @@ -1907,12 +1907,12 @@ def mock_app_simple(monkeypatch) -> rx.App: Returns: The app, after mocking out prerequisites.get_app() """ - app = App(state=TestState) + app = App(_state=TestState) app_module = Mock() setattr(app_module, CompileVars.APP, app) - app.state = TestState + app._state = TestState app.event_namespace.emit = CopyingAsyncMock() # type: ignore def _mock_get_app(*args, **kwargs): @@ -2153,7 +2153,7 @@ async def test_background_task_no_block(mock_app: rx.App, token: str): token: A token. """ router_data = {"query": {}} - mock_app.state_manager.state = mock_app.state = BackgroundTaskState + mock_app.state_manager.state = mock_app._state = BackgroundTaskState async for update in rx.app.process( # type: ignore mock_app, Event( @@ -2171,7 +2171,7 @@ async def test_background_task_no_block(mock_app: rx.App, token: str): # wait for the coroutine to start await asyncio.sleep(0.5 if CI else 0.1) - assert len(mock_app.background_tasks) == 1 + assert len(mock_app._background_tasks) == 1 # Process another normal event async for update in rx.app.process( # type: ignore @@ -2203,9 +2203,9 @@ async def test_background_task_no_block(mock_app: rx.App, token: str): ) # Explicit wait for background tasks - for task in tuple(mock_app.background_tasks): + for task in tuple(mock_app._background_tasks): await task - assert not mock_app.background_tasks + assert not mock_app._background_tasks exp_order = [ "background_task:start", @@ -2280,7 +2280,7 @@ async def test_background_task_reset(mock_app: rx.App, token: str): token: A token. """ router_data = {"query": {}} - mock_app.state_manager.state = mock_app.state = BackgroundTaskState + mock_app.state_manager.state = mock_app._state = BackgroundTaskState async for update in rx.app.process( # type: ignore mock_app, Event( @@ -2297,9 +2297,9 @@ async def test_background_task_reset(mock_app: rx.App, token: str): assert update == StateUpdate() # Explicit wait for background tasks - for task in tuple(mock_app.background_tasks): + for task in tuple(mock_app._background_tasks): await task - assert not mock_app.background_tasks + assert not mock_app._background_tasks assert ( await mock_app.state_manager.get_state( @@ -2884,7 +2884,7 @@ async def test_preprocess(app_module_mock, token, test_state, expected, mocker): "reflex.state.State.class_subclasses", {test_state, OnLoadInternalState} ) app = app_module_mock.app = App( - state=State, load_events={"index": [test_state.test_handler]} + _state=State, _load_events={"index": [test_state.test_handler]} ) async with app.state_manager.modify_state(_substate_key(token, State)) as state: state.router_data = {"simulate": "hydrate"} @@ -2931,8 +2931,8 @@ async def test_preprocess_multiple_load_events(app_module_mock, token, mocker): "reflex.state.State.class_subclasses", {OnLoadState, OnLoadInternalState} ) app = app_module_mock.app = App( - state=State, - load_events={"index": [OnLoadState.test_handler, OnLoadState.test_handler]}, + _state=State, + _load_events={"index": [OnLoadState.test_handler, OnLoadState.test_handler]}, ) async with app.state_manager.modify_state(_substate_key(token, State)) as state: state.router_data = {"simulate": "hydrate"} @@ -2977,7 +2977,7 @@ async def test_get_state(mock_app: rx.App, token: str): mock_app: An app that will be returned by `get_app()` token: A token. """ - mock_app.state_manager.state = mock_app.state = TestState + mock_app.state_manager.state = mock_app._state = TestState # Get instance of ChildState2. test_state = await mock_app.state_manager.get_state( @@ -3147,7 +3147,7 @@ async def test_get_state_from_sibling_not_cached(mock_app: rx.App, token: str): pass - mock_app.state_manager.state = mock_app.state = Parent + mock_app.state_manager.state = mock_app._state = Parent # Get the top level state via unconnected sibling. root = await mock_app.state_manager.get_state(_substate_key(token, Child)) diff --git a/tests/units/test_state_tree.py b/tests/units/test_state_tree.py index 6fe828819..70ef71cb8 100644 --- a/tests/units/test_state_tree.py +++ b/tests/units/test_state_tree.py @@ -222,7 +222,7 @@ async def state_manager_redis( Yields: A state manager instance """ - app_module_mock.app = rx.App(state=Root) + app_module_mock.app = rx.App(_state=Root) state_manager = app_module_mock.app.state_manager if not isinstance(state_manager, StateManagerRedis): diff --git a/tests/units/test_testing.py b/tests/units/test_testing.py index 83a03ad83..8c8f1461b 100644 --- a/tests/units/test_testing.py +++ b/tests/units/test_testing.py @@ -23,7 +23,7 @@ def test_app_harness(tmp_path): class State(rx.State): pass - app = rx.App(state=State) + app = rx.App(_state=State) app.add_page(lambda: rx.text("Basic App"), route="/", title="index") app._compile()