Support backend-only state vars (#390)
This commit is contained in:
parent
2b7e2ecf30
commit
4971f6d814
@ -33,6 +33,9 @@ class State(Base, ABC):
|
||||
# Vars inherited by the parent state.
|
||||
inherited_vars: ClassVar[Dict[str, Var]] = {}
|
||||
|
||||
# Backend vars that are never sent to the client.
|
||||
backend_vars: ClassVar[Dict[str, Any]] = {}
|
||||
|
||||
# The parent state.
|
||||
parent_state: Optional[State] = None
|
||||
|
||||
@ -117,6 +120,12 @@ class State(Base, ABC):
|
||||
if parent_state is not None:
|
||||
cls.inherited_vars = parent_state.vars
|
||||
|
||||
cls.backend_vars = {
|
||||
name: value
|
||||
for name, value in cls.__dict__.items()
|
||||
if utils.is_backend_variable(name)
|
||||
}
|
||||
|
||||
# Set the base and computed vars.
|
||||
skip_vars = set(cls.inherited_vars) | {
|
||||
"parent_state",
|
||||
@ -409,6 +418,8 @@ class State(Base, ABC):
|
||||
# Get the var from the parent state.
|
||||
if name in super().__getattribute__("inherited_vars"):
|
||||
return getattr(super().__getattribute__("parent_state"), name)
|
||||
elif name in super().__getattribute__("backend_vars"):
|
||||
return super().__getattribute__("backend_vars").__getitem__(name)
|
||||
return super().__getattribute__(name)
|
||||
|
||||
def __setattr__(self, name: str, value: Any):
|
||||
@ -425,6 +436,10 @@ class State(Base, ABC):
|
||||
setattr(self.parent_state, name, value)
|
||||
return
|
||||
|
||||
if utils.is_backend_variable(name):
|
||||
self.backend_vars.__setitem__(name, value)
|
||||
return
|
||||
|
||||
# Set the attribute.
|
||||
super().__setattr__(name, value)
|
||||
|
||||
|
@ -1251,5 +1251,17 @@ def get_redis() -> Optional[Redis]:
|
||||
return Redis(host=redis_url, port=int(redis_port), db=0)
|
||||
|
||||
|
||||
def is_backend_variable(name: str) -> bool:
|
||||
"""Check if this variable name correspond to a backend variable.
|
||||
|
||||
Args:
|
||||
name (str): The name of the variable to check
|
||||
|
||||
Returns:
|
||||
bool: The result of the check
|
||||
"""
|
||||
return name.startswith("_") and not name.startswith("__")
|
||||
|
||||
|
||||
# Store this here for performance.
|
||||
StateBases = get_base_class(StateVar)
|
||||
|
@ -245,3 +245,15 @@ def test_setup_frontend(tmp_path, mocker):
|
||||
assert web_folder.exists()
|
||||
assert web_public_folder.exists()
|
||||
assert (web_public_folder / "favicon.ico").exists()
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"input, output",
|
||||
[
|
||||
("_hidden", True),
|
||||
("not_hidden", False),
|
||||
("__dundermethod__", False),
|
||||
],
|
||||
)
|
||||
def test_is_backend_variable(input, output):
|
||||
assert utils.is_backend_variable(input) == output
|
||||
|
Loading…
Reference in New Issue
Block a user