Skip to content

Commit

Permalink
better computed var static deps (#4729)
Browse files Browse the repository at this point in the history
* better computed var static deps

* typing and usability improvements for computed var static dependencies
  • Loading branch information
benedikt-bartscher authored Feb 3, 2025
1 parent 2b7e4d6 commit d6e08e9
Showing 1 changed file with 61 additions and 26 deletions.
87 changes: 61 additions & 26 deletions reflex/vars/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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,
Expand All @@ -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),
Expand Down

0 comments on commit d6e08e9

Please sign in to comment.