Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

watched nested dependencies throws AttributeError #673

Open
tjader opened this issue Dec 30, 2022 · 1 comment
Open

watched nested dependencies throws AttributeError #673

tjader opened this issue Dec 30, 2022 · 1 comment
Labels
type-bug Bug report
Milestone

Comments

@tjader
Copy link

tjader commented Dec 30, 2022

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.

@droumis droumis added this to the v1.12.x milestone Jan 16, 2023
@droumis droumis added the type-bug Bug report label Jan 16, 2023
@maximlt
Copy link
Member

maximlt commented Apr 4, 2023

Traceback from the shorter example above:

Traceback (most recent call last):
  File ".mltmess/issue_deepcopy.py", line 14, in <module>
    copy.deepcopy(B())
  File "/Users/mliquet/miniconda3/envs/panel38/lib/python3.8/copy.py", line 172, in deepcopy
    y = _reconstruct(x, memo, *rv)
  File "/Users/mliquet/miniconda3/envs/panel38/lib/python3.8/copy.py", line 270, in _reconstruct
    state = deepcopy(state, memo)
  File "/Users/mliquet/miniconda3/envs/panel38/lib/python3.8/copy.py", line 146, in deepcopy
    y = copier(x, memo)
  File "/Users/mliquet/miniconda3/envs/panel38/lib/python3.8/copy.py", line 230, in _deepcopy_dict
    y[deepcopy(key, memo)] = deepcopy(value, memo)
  File "/Users/mliquet/miniconda3/envs/panel38/lib/python3.8/copy.py", line 172, in deepcopy
    y = _reconstruct(x, memo, *rv)
  File "/Users/mliquet/miniconda3/envs/panel38/lib/python3.8/copy.py", line 296, in _reconstruct
    value = deepcopy(value, memo)
  File "/Users/mliquet/miniconda3/envs/panel38/lib/python3.8/copy.py", line 146, in deepcopy
    y = copier(x, memo)
  File "/Users/mliquet/miniconda3/envs/panel38/lib/python3.8/copy.py", line 205, in _deepcopy_list
    append(deepcopy(a, memo))
  File "/Users/mliquet/miniconda3/envs/panel38/lib/python3.8/copy.py", line 172, in deepcopy
    y = _reconstruct(x, memo, *rv)
  File "/Users/mliquet/miniconda3/envs/panel38/lib/python3.8/copy.py", line 264, in _reconstruct
    y = func(*args)
  File "/Users/mliquet/miniconda3/envs/panel38/lib/python3.8/copy.py", line 263, in <genexpr>
    args = (deepcopy(arg, memo) for arg in args)
  File "/Users/mliquet/miniconda3/envs/panel38/lib/python3.8/copy.py", line 172, in deepcopy
    y = _reconstruct(x, memo, *rv)
  File "/Users/mliquet/miniconda3/envs/panel38/lib/python3.8/copy.py", line 272, in _reconstruct
    y.__setstate__(state)
  File "/Users/mliquet/dev/param/param/parameterized.py", line 3305, in __setstate__
    watcher_args[2] = _m_caller(self, fn._watcher_name)
  File "/Users/mliquet/dev/param/param/parameterized.py", line 670, in _m_caller
    function = getattr(self, method_name)
AttributeError: 'A' object has no attribute 'y'

@maximlt maximlt modified the milestones: v1.12.x, v2.x Apr 4, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type-bug Bug report
Projects
None yet
Development

No branches or pull requests

3 participants