param icon indicating copy to clipboard operation
param copied to clipboard

Dependencies on a method name is not invoking

Open david6l34 opened this issue 2 years ago • 3 comments

ALL software version info

param.version : 1.13.0

Description of expected behavior and the observed behavior

Following the tutorial in the official reference https://pyviz-dev.github.io/param/user_guide/Dependencies_and_Watchers.html#dependency-specs Under dependency specs, it is stated that a method can depends on another method by another method's name.

However, cb4 does not execute after invoking cb3

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

# code goes here between backticks
import param

class C(param.Parameterized):
    _countries = {'Africa': ['Ghana', 'Togo', 'South Africa'],
                  'Asia'  : ['China', 'Thailand', 'Japan', 'Singapore'],
                  'Europe': ['Austria', 'Bulgaria', 'Greece', 'Switzerland']}
    
    continent = param.Selector(list(_countries.keys()), default='Asia')
    country = param.Selector(_countries['Asia'])
    
    @param.depends('continent', watch=True)
    def _update_countries(self):
        countries = self._countries[self.continent]
        self.param['country'].objects = countries
        if self.country not in countries:
            self.country = countries[0]

c = C()

class D(param.Parameterized):
    x = param.Number(7)
    s = param.String("never")
    i = param.Integer(-5)
    o = param.Selector(['red', 'green', 'blue'])
    n = param.ClassSelector(param.Parameterized, c, instantiate=False)                    
    
    @param.depends('x', 's', 'n.country', 's:constant', watch=True)
    def cb1(self):
        print(f"cb1 x={self.x} s={self.s} "
              f"param.s.constant={self.param.s.constant} n.country={self.n.country}")

    @param.depends('n.param', watch=True)
    def cb2(self):
        print(f"cb2 n={self.n}")

    @param.depends('x', 'i', watch=True)
    def cb3(self):
        print(f"cb3 x={self.x} i={self.i}")

    @param.depends('cb3', watch=True)
    def cb4(self):
        print(f"cb4 x={self.x} i={self.i}")

d = D()
d

Stack traceback and/or browser JavaScript console output

Screenshots or screencasts of the bug in action

image

Changing d.x works as expected but calling d.cb3 does not invoke d.cb4

david6l34 avatar Apr 10 '23 15:04 david6l34

This is not exactly what the doc says, as it adds that:

which means that it will now watch everything that method watches, and will then get invoked after that method is invoked

And this is exactly what happens in the code cell 128 above, cb4 has been marked to watch everything that cb3 depends on and is executed after cb3 is executed.

maximlt avatar Apr 17 '23 16:04 maximlt

Do you think the docs could be improved? Or do you see that as a feature request?

maximlt avatar Apr 17 '23 16:04 maximlt

I agree that it is reasonable to expect that the method would be invoked in this case, but the documentation already seems clear enough that it won't be. I'd favor closing this unless there is a clear proposal for clarifying the docs. Implementing the behavior requested would also be reasonable, but would be a clear change in semantics that seems dangerous to make since it's been like this for so long.

jbednar avatar Apr 17 '23 17:04 jbednar