瀏覽代碼

better computed var static deps (#4729)

* better computed var static deps

* typing and usability improvements for computed var static dependencies
benedikt-bartscher 3 月之前
父節點
當前提交
d6e08e90a8
共有 1 個文件被更改,包括 61 次插入26 次删除
  1. 61 26
      reflex/vars/base.py

+ 61 - 26
reflex/vars/base.py

@@ -1983,7 +1983,7 @@ class ComputedVar(Var[RETURN_TYPE]):
     _initial_value: RETURN_TYPE | types.Unset = dataclasses.field(default=types.Unset())
 
     # Explicit var dependencies to track
-    _static_deps: dict[str, set[str]] = dataclasses.field(default_factory=dict)
+    _static_deps: dict[str | None, set[str]] = dataclasses.field(default_factory=dict)
 
     # Whether var dependencies should be auto-determined
     _auto_deps: bool = dataclasses.field(default=True)
@@ -2053,39 +2053,72 @@ class ComputedVar(Var[RETURN_TYPE]):
 
         object.__setattr__(self, "_update_interval", interval)
 
-        _static_deps = {}
-        if isinstance(deps, dict):
-            # Assume a dict is coming from _replace, so no special processing.
-            _static_deps = deps
-        elif deps is not None:
-            for dep in deps:
-                if isinstance(dep, Var):
-                    state_name = (
-                        all_var_data.state
-                        if (all_var_data := dep._get_all_var_data())
-                        and all_var_data.state
-                        else None
-                    )
-                    if all_var_data is not None:
-                        var_name = all_var_data.field_name
-                    else:
-                        var_name = dep._js_expr
-                    _static_deps.setdefault(state_name, set()).add(var_name)
-                elif isinstance(dep, str) and dep != "":
-                    _static_deps.setdefault(None, set()).add(dep)
-                else:
-                    raise TypeError(
-                        "ComputedVar dependencies must be Var instances or var names (non-empty strings)."
-                    )
         object.__setattr__(
             self,
             "_static_deps",
-            _static_deps,
+            self._calculate_static_deps(deps),
         )
         object.__setattr__(self, "_auto_deps", auto_deps)
 
         object.__setattr__(self, "_fget", fget)
 
+    def _calculate_static_deps(
+        self,
+        deps: Union[List[Union[str, Var]], dict[str | None, set[str]]] | None = None,
+    ) -> dict[str | None, set[str]]:
+        """Calculate the static dependencies of the computed var from user input or existing dependencies.
+
+        Args:
+            deps: The user input dependencies or existing dependencies.
+
+        Returns:
+            The static dependencies.
+        """
+        if isinstance(deps, dict):
+            # Assume a dict is coming from _replace, so no special processing.
+            return deps
+        _static_deps = {}
+        if deps is not None:
+            for dep in deps:
+                _static_deps = self._add_static_dep(dep, _static_deps)
+        return _static_deps
+
+    def _add_static_dep(
+        self, dep: Union[str, Var], deps: dict[str | None, set[str]] | None = None
+    ) -> dict[str | None, set[str]]:
+        """Add a static dependency to the computed var or existing dependency set.
+
+        Args:
+            dep: The dependency to add.
+            deps: The existing dependency set.
+
+        Returns:
+            The updated dependency set.
+
+        Raises:
+            TypeError: If the computed var dependencies are not Var instances or var names.
+        """
+        if deps is None:
+            deps = self._static_deps
+        if isinstance(dep, Var):
+            state_name = (
+                all_var_data.state
+                if (all_var_data := dep._get_all_var_data()) and all_var_data.state
+                else None
+            )
+            if all_var_data is not None:
+                var_name = all_var_data.field_name
+            else:
+                var_name = dep._js_expr
+            deps.setdefault(state_name, set()).add(var_name)
+        elif isinstance(dep, str) and dep != "":
+            deps.setdefault(None, set()).add(dep)
+        else:
+            raise TypeError(
+                "ComputedVar dependencies must be Var instances or var names (non-empty strings)."
+            )
+        return deps
+
     @override
     def _replace(
         self,
@@ -2106,6 +2139,8 @@ class ComputedVar(Var[RETURN_TYPE]):
         Raises:
             TypeError: If kwargs contains keys that are not allowed.
         """
+        if "deps" in kwargs:
+            kwargs["deps"] = self._calculate_static_deps(kwargs["deps"])
         field_values = {
             "fget": kwargs.pop("fget", self._fget),
             "initial_value": kwargs.pop("initial_value", self._initial_value),