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 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
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 "<ipython-input-2-c31ab72dd48f>", line 1, in <cell line: 1>
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 <module>
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 <genexpr>
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.