Enable real app AppHarness tests to not specify state=
(#2358)
This commit is contained in:
parent
51baa94ed5
commit
87844c3f7d
@ -7,5 +7,10 @@ from code.pages import *
|
|||||||
|
|
||||||
import reflex as rx
|
import reflex as rx
|
||||||
|
|
||||||
# Create the app and compile it.
|
|
||||||
|
class State(rx.State):
|
||||||
|
"""Define empty state to allow access to rx.State.router."""
|
||||||
|
|
||||||
|
|
||||||
|
# Create the app.
|
||||||
app = rx.App(style=styles.base_style)
|
app = rx.App(style=styles.base_style)
|
||||||
|
@ -63,6 +63,7 @@ from reflex.state import (
|
|||||||
State,
|
State,
|
||||||
StateManager,
|
StateManager,
|
||||||
StateUpdate,
|
StateUpdate,
|
||||||
|
code_uses_state_contexts,
|
||||||
)
|
)
|
||||||
from reflex.utils import console, exceptions, format, prerequisites, types
|
from reflex.utils import console, exceptions, format, prerequisites, types
|
||||||
from reflex.utils.imports import ImportVar
|
from reflex.utils.imports import ImportVar
|
||||||
@ -169,7 +170,8 @@ class App(Base):
|
|||||||
deprecation_version="0.3.5",
|
deprecation_version="0.3.5",
|
||||||
removal_version="0.4.0",
|
removal_version="0.4.0",
|
||||||
)
|
)
|
||||||
self.state = State
|
if len(State.class_subclasses) > 0:
|
||||||
|
self.state = State
|
||||||
# Get the config
|
# Get the config
|
||||||
config = get_config()
|
config = get_config()
|
||||||
|
|
||||||
@ -636,7 +638,11 @@ class App(Base):
|
|||||||
return
|
return
|
||||||
|
|
||||||
def compile_(self):
|
def compile_(self):
|
||||||
"""Compile the app and output it to the pages folder."""
|
"""Compile the app and output it to the pages folder.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
RuntimeError: When any page uses state, but no rx.State subclass is defined.
|
||||||
|
"""
|
||||||
# add the pages before the compile check so App know onload methods
|
# add the pages before the compile check so App know onload methods
|
||||||
for render, kwargs in DECORATED_PAGES:
|
for render, kwargs in DECORATED_PAGES:
|
||||||
self.add_page(render, **kwargs)
|
self.add_page(render, **kwargs)
|
||||||
@ -701,6 +707,16 @@ class App(Base):
|
|||||||
stateful_components_code,
|
stateful_components_code,
|
||||||
page_components,
|
page_components,
|
||||||
) = compiler.compile_stateful_components(self.pages.values())
|
) = compiler.compile_stateful_components(self.pages.values())
|
||||||
|
|
||||||
|
# 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
|
||||||
|
):
|
||||||
|
raise RuntimeError(
|
||||||
|
"To access rx.State in frontend components, at least one "
|
||||||
|
"subclass of rx.State must be defined in the app."
|
||||||
|
)
|
||||||
compile_results.append((stateful_components_path, stateful_components_code))
|
compile_results.append((stateful_components_path, stateful_components_code))
|
||||||
|
|
||||||
result_futures = []
|
result_futures = []
|
||||||
|
@ -2181,3 +2181,15 @@ class ImmutableMutableProxy(MutableProxy):
|
|||||||
return super()._mark_dirty(
|
return super()._mark_dirty(
|
||||||
wrapped=wrapped, instance=instance, args=args, kwargs=kwargs
|
wrapped=wrapped, instance=instance, args=args, kwargs=kwargs
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def code_uses_state_contexts(javascript_code: str) -> bool:
|
||||||
|
"""Check if the rendered Javascript uses state contexts.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
javascript_code: The Javascript code to check.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
True if the code attempts to access a member of StateContexts.
|
||||||
|
"""
|
||||||
|
return bool("useContext(StateContexts" in javascript_code)
|
||||||
|
@ -209,6 +209,8 @@ class AppHarness:
|
|||||||
reflex.config.get_config(reload=True)
|
reflex.config.get_config(reload=True)
|
||||||
# reset rx.State subclasses
|
# reset rx.State subclasses
|
||||||
State.class_subclasses.clear()
|
State.class_subclasses.clear()
|
||||||
|
# Ensure the AppHarness test does not skip State assignment due to running via pytest
|
||||||
|
os.environ.pop(reflex.constants.PYTEST_CURRENT_TEST, None)
|
||||||
# self.app_module.app.
|
# self.app_module.app.
|
||||||
self.app_module = reflex.utils.prerequisites.get_compiled_app(reload=True)
|
self.app_module = reflex.utils.prerequisites.get_compiled_app(reload=True)
|
||||||
self.app_instance = self.app_module.app
|
self.app_instance = self.app_module.app
|
||||||
|
@ -159,6 +159,11 @@ def get_app(reload: bool = False) -> ModuleType:
|
|||||||
sys.path.insert(0, os.getcwd())
|
sys.path.insert(0, os.getcwd())
|
||||||
app = __import__(module, fromlist=(constants.CompileVars.APP,))
|
app = __import__(module, fromlist=(constants.CompileVars.APP,))
|
||||||
if reload:
|
if reload:
|
||||||
|
from reflex.state import State
|
||||||
|
|
||||||
|
# Reset rx.State subclasses to avoid conflict when reloading.
|
||||||
|
State.class_subclasses.clear()
|
||||||
|
# Reload the app module.
|
||||||
importlib.reload(app)
|
importlib.reload(app)
|
||||||
|
|
||||||
return app
|
return app
|
||||||
|
Loading…
Reference in New Issue
Block a user