Skip to content

Commit

Permalink
Cache reactive parameters and root (#850)
Browse files Browse the repository at this point in the history
  • Loading branch information
philippjfr authored Sep 25, 2023
1 parent b122f2b commit 1027ba3
Showing 1 changed file with 36 additions and 25 deletions.
61 changes: 36 additions & 25 deletions param/reactive.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,10 @@ class Trigger(Parameterized):

value = Event()

def __init__(self, parameters, **params):
super().__init__(**params)
self.parameters = parameters


class reactive_ops:
"""
Expand Down Expand Up @@ -205,7 +209,11 @@ def where(self, x, y):
"""
xrefs = resolve_ref(x)
yrefs = resolve_ref(y)
trigger = Trigger()
if isinstance(self._reactive, rx):
params = self._reactive._params
else:
params = resolve_ref(self._reactive)
trigger = Trigger(parameters=params)
if xrefs:
def trigger_x(*args):
if self.resolve():
Expand All @@ -217,9 +225,9 @@ def trigger_y(*args):
trigger.param.trigger('value')
bind(trigger_y, *yrefs, watch=True)

def ternary(condition, event):
def ternary(condition, _):
return resolve_value(x) if condition else resolve_value(y)
return self.pipe(ternary, trigger.param.value)
return bind(ternary, self._reactive, trigger.param.value)

# Operations to get the output and set the input of an expression

Expand Down Expand Up @@ -540,6 +548,15 @@ def __init__(
self._prev = obj
else:
self._prev = prev
self._root = self._compute_root()
self._fn_params = self._compute_fn_params()
self._internal_params = self._compute_params()
# Filter params that external objects depend on, ensuring
# that Trigger parameters do not cause double execution
self._params = [
p for p in self._internal_params if not isinstance(p.owner, Trigger)
or any (p not in self._internal_params for p in p.owner.parameters)
]
self._setup_invalidations(depth)
self._kwargs = kwargs
self.rx = reactive_ops(self)
Expand Down Expand Up @@ -575,8 +592,15 @@ def _current(self):
self.rx.resolve()
return self._current_

@property
def _fn_params(self) -> list[Parameter]:
def _compute_root(self):
if self._prev is None:
return self
root = self
while root._prev is not None:
root = root._prev
return root

def _compute_fn_params(self) -> list[Parameter]:
if self._fn is None:
return []

Expand All @@ -592,17 +616,7 @@ def _fn_params(self) -> list[Parameter]:
kwargs = list(dinfo.get('kw', {}).values())
return args + kwargs

@property
def _root(self):
if self._prev is None:
return self
root = self
while root._prev is not None:
root = root._prev
return root

@property
def _params(self) -> list[Parameter]:
def _compute_params(self) -> list[Parameter]:
ps = self._fn_params

# Collect parameters on previous objects in chain
Expand All @@ -617,14 +631,11 @@ def _params(self) -> list[Parameter]:
return ps

# Accumulate dependencies in args and/or kwargs
ps += [
ref for arg in self._operation['args']
for ref in resolve_ref(arg)
]
ps += [
ref for arg in self._operation['kwargs'].values()
for ref in resolve_ref(arg)
]
for arg in list(self._operation['args'])+list(self._operation['kwargs'].values()):
for ref in resolve_ref(arg):
if ref not in ps:
ps.append(ref)

return ps

def _setup_invalidations(self, depth: int = 0):
Expand All @@ -649,7 +660,7 @@ def _setup_invalidations(self, depth: int = 0):
if self._fn is not None:
for _, params in full_groupby(self._fn_params, lambda x: id(x.owner)):
params[0].owner.param._watch(self._invalidate_obj, [p.name for p in params], precedence=-1)
for _, params in full_groupby(self._params, lambda x: id(x.owner)):
for _, params in full_groupby(self._internal_params, lambda x: id(x.owner)):
params[0].owner.param._watch(self._invalidate_current, [p.name for p in params], precedence=-1)

def _invalidate_current(self, *events):
Expand Down

0 comments on commit 1027ba3

Please sign in to comment.