diff --git a/reflex/vars/base.py b/reflex/vars/base.py index 8609d46cc30..9f665212224 100644 --- a/reflex/vars/base.py +++ b/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 @@ def __init__( 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 @@ def _replace( 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),