fix is_backend_variable for dunder prefixed variables (#2391)

This commit is contained in:
benedikt-bartscher 2024-01-17 02:37:05 +01:00 committed by GitHub
parent 0bb9a021a2
commit 1aca1b677f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 24 additions and 6 deletions

View File

@ -315,7 +315,7 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
cls.new_backend_vars = { cls.new_backend_vars = {
name: value name: value
for name, value in cls.__dict__.items() for name, value in cls.__dict__.items()
if types.is_backend_variable(name) if types.is_backend_variable(name, cls)
and name not in cls.inherited_backend_vars and name not in cls.inherited_backend_vars
and not isinstance(value, FunctionType) and not isinstance(value, FunctionType)
} }
@ -878,7 +878,10 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
setattr(self.parent_state, name, value) setattr(self.parent_state, name, value)
return return
if types.is_backend_variable(name) and name not in RESERVED_BACKEND_VAR_NAMES: if (
types.is_backend_variable(name, self.__class__)
and name not in RESERVED_BACKEND_VAR_NAMES
):
self._backend_vars.__setitem__(name, value) self._backend_vars.__setitem__(name, value)
self.dirty_vars.add(name) self.dirty_vars.add(name)
self._mark_dirty() self._mark_dirty()
@ -1177,7 +1180,7 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
subdelta = { subdelta = {
prop: getattr(self, prop) prop: getattr(self, prop)
for prop in delta_vars for prop in delta_vars
if not types.is_backend_variable(prop) if not types.is_backend_variable(prop, self.__class__)
} }
if len(subdelta) > 0: if len(subdelta) > 0:
delta[self.get_full_name()] = subdelta delta[self.get_full_name()] = subdelta

View File

@ -251,15 +251,18 @@ def is_valid_var_type(type_: Type) -> bool:
return _issubclass(type_, StateVar) or serializers.has_serializer(type_) return _issubclass(type_, StateVar) or serializers.has_serializer(type_)
def is_backend_variable(name: str) -> bool: def is_backend_variable(name: str, cls: Type | None = None) -> bool:
"""Check if this variable name correspond to a backend variable. """Check if this variable name correspond to a backend variable.
Args: Args:
name: The name of the variable to check name: The name of the variable to check
cls: The class of the variable to check
Returns: Returns:
bool: The result of the check bool: The result of the check
""" """
if cls is not None and name.startswith(f"_{cls.__name__}__"):
return False
return name.startswith("_") and not name.startswith("__") return name.startswith("_") and not name.startswith("__")

View File

@ -144,6 +144,18 @@ def test_setup_frontend(tmp_path, mocker):
assert (web_public_folder / "favicon.ico").exists() assert (web_public_folder / "favicon.ico").exists()
@pytest.fixture
def test_backend_variable_cls():
class TestBackendVariable:
"""Test backend variable."""
_hidden: int = 0
not_hidden: int = 0
__dunderattr__: int = 0
return TestBackendVariable
@pytest.mark.parametrize( @pytest.mark.parametrize(
"input, output", "input, output",
[ [
@ -152,8 +164,8 @@ def test_setup_frontend(tmp_path, mocker):
("__dundermethod__", False), ("__dundermethod__", False),
], ],
) )
def test_is_backend_variable(input, output): def test_is_backend_variable(test_backend_variable_cls, input, output):
assert types.is_backend_variable(input) == output assert types.is_backend_variable(input, test_backend_variable_cls) == output
@pytest.mark.parametrize( @pytest.mark.parametrize(