holoviz / holoviz/param

watched nested dependencies throws AttributeError

Open
#673 1 comment 0 reactions 0 assignees View on GitHub
type-bug
Dominant language
Python
Stars
521
Forks
86
Avg merge
1d 13h
Merged PRs (30d)
35

Description

Thanks for contacting us! Please read and follow these instructions carefully, then delete this introductory text to keep your issue easy to read. Note that the issue tracker is NOT the place for usage questions and technical assistance; post those at [Discourse](https://discourse.holoviz.org) instead. Issues without the required information below may be closed immediately.

#### ALL software version info
(this library, plus any other relevant software, e.g. bokeh, python, notebook, OS, browser, etc)
param v 1.12.3
Reproducible at least on on python 3.10 on Ubuntu.
#### Description of expected behavior and the observed behavior
The error below is thrown when I try nested parameterized dependencies, where there is a watch on a nested dependency. I would expect that the watch flag should work in these circumstances.

#### Complete, minimal, self-contained example code that reproduces the issue

```
import param

class A(param.Parameterized):
x=param.Number(default=0)

class B(param.Parameterized):
a=param.ClassSelector(A, default=A())

@param.depends('a.x', watch=True)
def y(self):
pass

class C(param.Parameterized):
b=param.ClassSelector(B, default=B())

c = C()

```

#### Stack traceback and/or browser JavaScript console output
```traceback (most recent call last):
File "/home/mats/miniconda3/envs/quant/lib/python3.10/site-packages/IPython/core/interactiveshell.py", line 3398, in run_code
exec(code_obj, self.user_global_ns, self.user_ns)
File "", line 1, in
runfile('/home/mats/.config/JetBrains/PyCharm2022.2/scratches/scratch_2.py', wdir='/home/mats/.config/JetBrains/PyCharm2022.2/scratches')
File "/home/mats/.local/share/JetBrains/Toolbox/apps/PyCharm-P/ch-0/222.4345.23/plugins/python/helpers/pydev/_pydev_bundle/pydev_umd.py", line 198, in runfile
pydev_imports.execfile(filename, global_vars, local_vars) # execute the script
File "/home/mats/.local/share/JetBrains/Toolbox/apps/PyCharm-P/ch-0/222.4345.23/plugins/python/helpers/pydev/_pydev_imps/_pydev_execfile.py", line 18, in execfile
exec(compile(contents+"\n", file, 'exec'), glob, loc)
File "/home/mats/.config/JetBrains/PyCharm2022.2/scratches/scratch_2.py", line 20, in
c = C()
File "/home/mats/miniconda3/envs/quant/lib/python3.10/site-packages/param/parameterized.py", line 3173, in __init__
self.param._setup_params(**params)
File "/home/mats/miniconda3/envs/quant/lib/python3.10/site-packages/param/parameterized.py", line 1387, in override_initialization
fn(parameterized_instance, *args, **kw)
File "/home/mats/miniconda3/envs/quant/lib/python3.10/site-packages/param/parameterized.py", line 1633, in _setup_params
self.param._instantiate_param(p)
File "/home/mats/miniconda3/envs/quant/lib/python3.10/site-packages/param/parameterized.py", line 1688, in _instantiate_param
new_object = copy.deepcopy(param_obj.default)
File "/home/mats/miniconda3/envs/quant/lib/python3.10/copy.py", line 172, in deepcopy
y = _reconstruct(x, memo, *rv)
File "/home/mats/miniconda3/envs/quant/lib/python3.10/copy.py", line 271, in _reconstruct
state = deepcopy(state, memo)
File "/home/mats/miniconda3/envs/quant/lib/python3.10/copy.py", line 146, in deepcopy
y = copier(x, memo)
File "/home/mats/miniconda3/envs/quant/lib/python3.10/copy.py", line 231, in _deepcopy_dict
y[deepcopy(key, memo)] = deepcopy(value, memo)
File "/home/mats/miniconda3/envs/quant/lib/python3.10/copy.py", line 172, in deepcopy
y = _reconstruct(x, memo, *rv)
File "/home/mats/miniconda3/envs/quant/lib/python3.10/copy.py", line 297, in _reconstruct
value = deepcopy(value, memo)
File "/home/mats/miniconda3/envs/quant/lib/python3.10/copy.py", line 146, in deepcopy
y = copier(x, memo)
File "/home/mats/miniconda3/envs/quant/lib/python3.10/copy.py", line 206, in _deepcopy_list
append(deepcopy(a, memo))
File "/home/mats/miniconda3/envs/quant/lib/python3.10/copy.py", line 172, in deepcopy
y = _reconstruct(x, memo, *rv)
File "/home/mats/miniconda3/envs/quant/lib/python3.10/copy.py", line 265, in _reconstruct
y = func(*args)
File "/home/mats/miniconda3/envs/quant/lib/python3.10/copy.py", line 264, in
args = (deepcopy(arg, memo) for arg in args)
File "/home/mats/miniconda3/envs/quant/lib/python3.10/copy.py", line 172, in deepcopy
y = _reconstruct(x, memo, *rv)
File "/home/mats/miniconda3/envs/quant/lib/python3.10/copy.py", line 273, in _reconstruct
y.__setstate__(state)
File "/home/mats/miniconda3/envs/quant/lib/python3.10/site-packages/param/parameterized.py", line 3227, in __setstate__
watcher_args[2] = _m_caller(self, fn._watcher_name)
File "/home/mats/miniconda3/envs/quant/lib/python3.10/site-packages/param/parameterized.py", line 661, in _m_caller
function = getattr(self, method_name)
AttributeError: 'A' object has no attribute 'y'
```

When a default value is given to a ClassSelector (like in C above), a deepcopy of that default value happens, and it is the deepcopy that is causing the exception, so a shorter example wold be to just do:
```
import param
import copy

class A(param.Parameterized):
x=param.Number(default=0)

class B(param.Parameterized):
a=param.ClassSelector(A, default=A())

@param.depends('a.x', watch=True)
def y(self):
pass

copy.deepcopy(B())

```

Removing the "watch" flag removes the issue, but I also lose the watched updates that I need.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.