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.
|
# Vars inherited by the parent state.
|
||||||
inherited_vars: ClassVar[Dict[str, Var]] = {}
|
inherited_vars: ClassVar[Dict[str, Var]] = {}
|
||||||
|
|
||||||
|
# Backend vars that are never sent to the client.
|
||||||
|
backend_vars: ClassVar[Dict[str, Any]] = {}
|
||||||
|
|
||||||
# The parent state.
|
# The parent state.
|
||||||
parent_state: Optional[State] = None
|
parent_state: Optional[State] = None
|
||||||
|
|
||||||
@ -117,6 +120,12 @@ class State(Base, ABC):
|
|||||||
if parent_state is not None:
|
if parent_state is not None:
|
||||||
cls.inherited_vars = parent_state.vars
|
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.
|
# Set the base and computed vars.
|
||||||
skip_vars = set(cls.inherited_vars) | {
|
skip_vars = set(cls.inherited_vars) | {
|
||||||
"parent_state",
|
"parent_state",
|
||||||
@ -409,6 +418,8 @@ class State(Base, ABC):
|
|||||||
# Get the var from the parent state.
|
# Get the var from the parent state.
|
||||||
if name in super().__getattribute__("inherited_vars"):
|
if name in super().__getattribute__("inherited_vars"):
|
||||||
return getattr(super().__getattribute__("parent_state"), name)
|
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)
|
return super().__getattribute__(name)
|
||||||
|
|
||||||
def __setattr__(self, name: str, value: Any):
|
def __setattr__(self, name: str, value: Any):
|
||||||
@ -425,6 +436,10 @@ class State(Base, ABC):
|
|||||||
setattr(self.parent_state, name, value)
|
setattr(self.parent_state, name, value)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
if utils.is_backend_variable(name):
|
||||||
|
self.backend_vars.__setitem__(name, value)
|
||||||
|
return
|
||||||
|
|
||||||
# Set the attribute.
|
# Set the attribute.
|
||||||
super().__setattr__(name, value)
|
super().__setattr__(name, value)
|
||||||
|
|
||||||
|
@ -1251,5 +1251,17 @@ def get_redis() -> Optional[Redis]:
|
|||||||
return Redis(host=redis_url, port=int(redis_port), db=0)
|
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.
|
# Store this here for performance.
|
||||||
StateBases = get_base_class(StateVar)
|
StateBases = get_base_class(StateVar)
|
||||||
|
@ -245,3 +245,15 @@ def test_setup_frontend(tmp_path, mocker):
|
|||||||
assert web_folder.exists()
|
assert web_folder.exists()
|
||||||
assert web_public_folder.exists()
|
assert web_public_folder.exists()
|
||||||
assert (web_public_folder / "favicon.ico").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