param icon indicating copy to clipboard operation
param copied to clipboard

Provide more control over the call order of watched methods

Open sdc50 opened this issue 2 years ago • 9 comments

Between versions 1.11.1 and 1.12.1 the order in which methods that are decorated with param.depends are triggered was changed.

In [1]: import param

In [2]: class Test(param.Parameterized):
   ...:     s = param.String(default='default')
   ...: 
   ...:     @param.depends('s', watch=True)
   ...:     def on_s_update(self):
   ...:         print(self.s)
   ...: 
   ...: class Sub(Test):
   ...: 
   ...:     @param.depends('s', watch=True)
   ...:     def more_on_s_update(self):
   ...:         print(self.s.upper())
   ...: 
   ...: s = Sub()
   ...: s.s = 'test'
test
TEST

In [3]: param.__version__
Out[3]: '1.11.1'

vs.

image

Without a way to explicitly control the call order much of my code was in a delicate balance, and this has just wreaked havoc on it all.

There should be a way explicitly control the call order of depended on methods. In the past I had discussed with @philippjfr about adding a precedence argument to the depends decorator (and the watch method) so that callbacks can be sorted and called in a specified order when a parameter is triggered.

sdc50 avatar Apr 13 '22 16:04 sdc50

Thanks for the issue, suspect this was a regression introduced in 1.12. We should restore the original behavior AND add the precedence argument.

philippjfr avatar Apr 13 '22 16:04 philippjfr

Will reopen since the precedence proposal hadn't been added yet.

philippjfr avatar May 17 '22 23:05 philippjfr

I'm somewhat hesitant to add precedence as a reserved kwarg to depends since it's not an unlikely argument name. Any other suggestions?

philippjfr avatar May 26 '22 18:05 philippjfr

I guess priority has the same issue. But any compound word should be ok, e.g. call_prority or call_order or calling_order.

jbednar avatar May 26 '22 19:05 jbednar

Oh. I looked that up but could not find it, is it documented somewhere that there are reserved kwargs? Does this just apply to when @param.depends is used to decorate a function? As in:

import param

class P(param.Parameterized):

    x = param.String()
    w = param.String()


p = P()

@param.depends(x=p.param.x, watch=p.param.w)
def foo(x, watch):
    print(x)

p.x = 'test'

maximlt avatar May 30 '22 08:05 maximlt

I don't know if we explicitly discuss reserved kwargs, certainly we do discuss watch and now we'd be proposing to add another argument. I don't think there are any others but I might be wrong.

philippjfr avatar May 30 '22 08:05 philippjfr

Btw this is the error I get with the snippet above:

Traceback (most recent call last):
  File "mltmess/issue_arg_depends.py", line 15, in <module>
    p.x = 'test'
  File "/Users/mliquet/WORK/DEV/param/param/parameterized.py", line 367, in _f
    instance_param.__set__(obj, val)
  File "/Users/mliquet/WORK/DEV/param/param/parameterized.py", line 369, in _f
    return f(self, obj, val)
  File "/Users/mliquet/WORK/DEV/param/param/parameterized.py", line 1248, in __set__
    obj.param._call_watcher(watcher, event)
  File "/Users/mliquet/WORK/DEV/param/param/parameterized.py", line 2039, in _call_watcher
    self_._execute_watcher(watcher, (event,))
  File "/Users/mliquet/WORK/DEV/param/param/parameterized.py", line 2021, in _execute_watcher
    watcher.fn(*args, **kwargs)
  File "/Users/mliquet/WORK/DEV/param/param/parameterized.py", line 446, in cb
    return func(*args, **dep_kwargs)
TypeError: foo() missing 1 required positional argument: 'watch'

maximlt avatar May 30 '22 08:05 maximlt

Right we need to explicitly validate reserved kwargs.

philippjfr avatar May 30 '22 08:05 philippjfr

related discussion in this issue: https://github.com/holoviz/panel/issues/2556

sdc50 avatar Aug 22 '23 20:08 sdc50