From 130414c9c248ca0bb27bdc02b7fd14d233627830 Mon Sep 17 00:00:00 2001 From: maximlt Date: Wed, 21 Jun 2023 02:15:30 +0200 Subject: [PATCH 1/3] compare instances to None --- param/parameterized.py | 8 ++++---- tests/testparamdepends.py | 21 +++++++++++++++++++++ 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/param/parameterized.py b/param/parameterized.py index 51b49f9c1..90601a28a 100644 --- a/param/parameterized.py +++ b/param/parameterized.py @@ -619,7 +619,7 @@ def _params_depended_on(minfo, dynamic=True, intermediate=True): deps, dynamic_deps = [], [] dinfo = getattr(minfo.method, "_dinfo", {}) for d in dinfo.get('dependencies', list(minfo.cls.param)): - ddeps, ddynamic_deps = (minfo.inst or minfo.cls).param._spec_to_obj(d, dynamic, intermediate) + ddeps, ddynamic_deps = (minfo.inst if minfo.inst is not None else minfo.cls).param._spec_to_obj(d, dynamic, intermediate) dynamic_deps += ddynamic_deps for dep in ddeps: if isinstance(dep, PInfo): @@ -1859,7 +1859,7 @@ def _update_deps(self_, attribute=None, init=False): init_methods.append(m) elif dynamic: for w in obj._dynamic_watchers.pop(method, []): - (w.inst or w.cls).param.unwatch(w) + (w.inst if w.inst is not None else w.cls).param.unwatch(w) else: continue @@ -1894,7 +1894,7 @@ def _resolve_dynamic_deps(self, obj, dynamic_dep, param_dep, attribute): subobj = getattr(subobj, subpath.split(':')[0], None) subobjs.append(subobj) - dep_obj = (param_dep.inst or param_dep.cls) + dep_obj = param_dep.inst if param_dep.inst is not None else param_dep.cls if dep_obj not in subobjs[:-1]: return None, None, param_dep.what @@ -1930,7 +1930,7 @@ def _watch_group(self_, obj, name, queued, group, attribute=None): on the old subobject and create watchers on the new subobject. """ dynamic_dep, param_dep = group[0] - dep_obj = (param_dep.inst or param_dep.cls) + dep_obj = param_dep.inst if param_dep.inst is not None else param_dep.cls params = [] for _, g in group: if g.name not in params: diff --git a/tests/testparamdepends.py b/tests/testparamdepends.py index 83f44ed64..ee3e214f1 100644 --- a/tests/testparamdepends.py +++ b/tests/testparamdepends.py @@ -820,6 +820,27 @@ def method1(self): assert method1_count == 0 assert method2_count == 1 + def test_param_depends_class_with_len(self): + # https://github.com/holoviz/param/issues/747 + + count = 0 + + class P(param.Parameterized): + x = param.Parameter() + + @param.depends('x', watch=True) + def debug(self): + nonlocal count + count += 1 + + # bool(P()) evaluates to False + def __len__(self): + return 0 + + p = P() + p.x = 1 + assert count == 1 + class TestParamDependsFunction(unittest.TestCase): From eecd2322494a7abcf1f0d70a0eb48de4aebadb05 Mon Sep 17 00:00:00 2001 From: Maxime Liquet <35924738+maximlt@users.noreply.github.com> Date: Thu, 22 Jun 2023 15:24:57 +0200 Subject: [PATCH 2/3] Apply suggestions from code review Co-authored-by: Philipp Rudiger --- param/parameterized.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/param/parameterized.py b/param/parameterized.py index 90601a28a..b0047d0fb 100644 --- a/param/parameterized.py +++ b/param/parameterized.py @@ -619,7 +619,7 @@ def _params_depended_on(minfo, dynamic=True, intermediate=True): deps, dynamic_deps = [], [] dinfo = getattr(minfo.method, "_dinfo", {}) for d in dinfo.get('dependencies', list(minfo.cls.param)): - ddeps, ddynamic_deps = (minfo.inst if minfo.inst is not None else minfo.cls).param._spec_to_obj(d, dynamic, intermediate) + ddeps, ddynamic_deps = (minfo.cls if minfo.inst is None else minfo.inst).param._spec_to_obj(d, dynamic, intermediate) dynamic_deps += ddynamic_deps for dep in ddeps: if isinstance(dep, PInfo): @@ -1859,7 +1859,7 @@ def _update_deps(self_, attribute=None, init=False): init_methods.append(m) elif dynamic: for w in obj._dynamic_watchers.pop(method, []): - (w.inst if w.inst is not None else w.cls).param.unwatch(w) + (w.cls if w.inst is None else w.inst).param.unwatch(w) else: continue @@ -1894,7 +1894,7 @@ def _resolve_dynamic_deps(self, obj, dynamic_dep, param_dep, attribute): subobj = getattr(subobj, subpath.split(':')[0], None) subobjs.append(subobj) - dep_obj = param_dep.inst if param_dep.inst is not None else param_dep.cls + dep_obj = param_dep.cls if param_dep.inst is None else param_dep.inst if dep_obj not in subobjs[:-1]: return None, None, param_dep.what @@ -1930,7 +1930,7 @@ def _watch_group(self_, obj, name, queued, group, attribute=None): on the old subobject and create watchers on the new subobject. """ dynamic_dep, param_dep = group[0] - dep_obj = param_dep.inst if param_dep.inst is not None else param_dep.cls + dep_obj = param_dep.cls if param_dep.inst is None else param_dep.inst params = [] for _, g in group: if g.name not in params: From 1fa4848ac5ebfa9f53de15ee03eee215fced6615 Mon Sep 17 00:00:00 2001 From: maximlt Date: Thu, 22 Jun 2023 15:36:58 +0200 Subject: [PATCH 3/3] fix linter --- param/parameterized.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/param/parameterized.py b/param/parameterized.py index b0047d0fb..a94717bc8 100644 --- a/param/parameterized.py +++ b/param/parameterized.py @@ -1930,7 +1930,7 @@ def _watch_group(self_, obj, name, queued, group, attribute=None): on the old subobject and create watchers on the new subobject. """ dynamic_dep, param_dep = group[0] - dep_obj = param_dep.cls if param_dep.inst is None else param_dep.inst + dep_obj = param_dep.cls if param_dep.inst is None else param_dep.inst params = [] for _, g in group: if g.name not in params: