浏览代码

classvars should not be backend vars (#3578)

* classvars should not be backend vars

* cleanup RESERVED_BACKEND_VAR_NAMES
benedikt-bartscher 10 月之前
父节点
当前提交
8e66c9b3c7
共有 4 个文件被更改,包括 25 次插入8 次删除
  1. 6 1
      integration/test_computed_vars.py
  2. 0 4
      reflex/state.py
  3. 16 2
      reflex/utils/types.py
  4. 3 1
      tests/utils/test_utils.py

+ 6 - 1
integration/test_computed_vars.py

@@ -15,7 +15,10 @@ def ComputedVars():
     """Test app for computed vars."""
     import reflex as rx
 
-    class State(rx.State):
+    class StateMixin(rx.State, mixin=True):
+        pass
+
+    class State(StateMixin, rx.State):
         count: int = 0
 
         # cached var with dep on count
@@ -57,6 +60,8 @@ def ComputedVars():
         def mark_dirty(self):
             self._mark_dirty()
 
+    assert State.backend_vars == {}
+
     def index() -> rx.Component:
         return rx.center(
             rx.vstack(

+ 0 - 4
reflex/state.py

@@ -201,10 +201,6 @@ def _no_chain_background_task(
 
 RESERVED_BACKEND_VAR_NAMES = {
     "_backend_vars",
-    "_computed_var_dependencies",
-    "_substate_var_dependencies",
-    "_always_dirty_computed_vars",
-    "_always_dirty_substates",
     "_was_touched",
 }
 

+ 16 - 2
reflex/utils/types.py

@@ -10,6 +10,7 @@ from functools import wraps
 from typing import (
     Any,
     Callable,
+    ClassVar,
     Dict,
     Iterable,
     List,
@@ -413,9 +414,22 @@ def is_backend_variable(name: str, cls: Type | None = None) -> bool:
     Returns:
         bool: The result of the check
     """
-    if cls is not None and name.startswith(f"_{cls.__name__}__"):
+    if not name.startswith("_"):
         return False
-    return name.startswith("_") and not name.startswith("__")
+
+    if name.startswith("__"):
+        return False
+
+    if cls is not None:
+        if name.startswith(f"_{cls.__name__}__"):
+            return False
+        hints = get_type_hints(cls)
+        if name in hints:
+            hint = get_origin(hints[name])
+            if hint == ClassVar:
+                return False
+
+    return True
 
 
 def check_type_in_allowed_types(value_type: Type, allowed_types: Iterable) -> bool:

+ 3 - 1
tests/utils/test_utils.py

@@ -1,7 +1,7 @@
 import os
 import typing
 from pathlib import Path
-from typing import Any, List, Literal, Union
+from typing import Any, ClassVar, List, Literal, Union
 
 import pytest
 import typer
@@ -149,6 +149,7 @@ def test_backend_variable_cls():
     class TestBackendVariable:
         """Test backend variable."""
 
+        _classvar: ClassVar[int] = 0
         _hidden: int = 0
         not_hidden: int = 0
         __dunderattr__: int = 0
@@ -159,6 +160,7 @@ def test_backend_variable_cls():
 @pytest.mark.parametrize(
     "input, output",
     [
+        ("_classvar", False),
         ("_hidden", True),
         ("not_hidden", False),
         ("__dundermethod__", False),