Support backend-only state vars (#390)

This commit is contained in:
Thomas Brandého 2023-01-30 03:55:34 +01:00 committed by GitHub
parent 2b7e2ecf30
commit 4971f6d814
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 39 additions and 0 deletions

View File

@ -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)

View File

@ -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)

View File

@ -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