浏览代码

fix is_backend_variable for dunder prefixed variables (#2391)

benedikt-bartscher 1 年之前
父节点
当前提交
1aca1b677f
共有 3 个文件被更改,包括 24 次插入6 次删除
  1. 6 3
      reflex/state.py
  2. 4 1
      reflex/utils/types.py
  3. 14 2
      tests/utils/test_utils.py

+ 6 - 3
reflex/state.py

@@ -315,7 +315,7 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
         cls.new_backend_vars = {
             name: value
             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 not isinstance(value, FunctionType)
         }
@@ -878,7 +878,10 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
             setattr(self.parent_state, name, value)
             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.dirty_vars.add(name)
             self._mark_dirty()
@@ -1177,7 +1180,7 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
         subdelta = {
             prop: getattr(self, prop)
             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:
             delta[self.get_full_name()] = subdelta

+ 4 - 1
reflex/utils/types.py

@@ -251,15 +251,18 @@ def is_valid_var_type(type_: Type) -> bool:
     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.
 
     Args:
         name: The name of the variable to check
+        cls: The class of the variable to check
 
     Returns:
         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("__")
 
 

+ 14 - 2
tests/utils/test_utils.py

@@ -144,6 +144,18 @@ def test_setup_frontend(tmp_path, mocker):
     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(
     "input, output",
     [
@@ -152,8 +164,8 @@ def test_setup_frontend(tmp_path, mocker):
         ("__dundermethod__", False),
     ],
 )
-def test_is_backend_variable(input, output):
-    assert types.is_backend_variable(input) == output
+def test_is_backend_variable(test_backend_variable_cls, input, output):
+    assert types.is_backend_variable(input, test_backend_variable_cls) == output
 
 
 @pytest.mark.parametrize(