Open
Description
ALL software version info
- param 1.10.1
- panel 0.11.3
- python 3.7.10
Description of expected behavior and the observed behavior
I'm trying to use @pm.depends(pn.state.param.busy, watch=True)
on an instance method of a class. When I modify a parameter, I expect the method to get called once with argument busy=True
and once with argument busy=False
.
Instead I'm seeing potentially 2 issues:
- Whenever I use
@pm.depends(pn.state.param.busy, watch=True)
, even on a normal function, the function or method gets called 4 times, with arguments busy = True/False/True/False. It doesn't seem to be due to thewatch
argument because when I remove it nothing gets called. - In case of a method, every call gets duplicated (for a total of 8) and in half the calls the
self
argument is the booleanbusy
, in the other half it's the expected object instance. I never get both in the same call.
See example code and output below.
Complete, minimal, self-contained example code that reproduces the issue
import panel as pn
import param as pm
from bokeh.server.server import Server
class A(pm.Parameterized):
value = pm.Integer()
def __init__(self):
super().__init__()
self.a = 1234
@pm.depends(pn.state.param.busy, watch=True)
def indicator_method(self, *args, **kwargs):
print("method", self, args, kwargs)
# @pm.depends(pn.state.param.busy, watch=True)
# def indicator_func(*args, **kwargs):
# print("func", args, kwargs)
def bkapp(doc):
a = A()
p = pn.Row(a.param)
doc.add_root(p.get_root())
if __name__ == '__main__':
port = 8901
server = Server({'/': bkapp}, num_procs=1, port=port)
server.start()
server.io_loop.add_callback(server.show, "/")
server.io_loop.start()
Output when changing value
Example as-is:
method True () {}
method <A A00097> () {}
method False () {}
method <A A00097> () {}
method True () {}
method <A A00097> () {}
method False () {}
method <A A00097> () {}
When commenting out the method and uncommenting the function:
func (True,) {}
func (False,) {}
func (True,) {}
func (False,) {}
Workaround for method vs function
Below two potential workarounds. The method still gets called 4 times though.
class A(pm.Parameterized):
value = pm.Integer()
def __init__(self):
super().__init__()
self.a = 1234
# Workaround 1
f = functools.partial(self.indicator.__func__, self)
pm.depends(pn.state.param.busy, watch=True)(f)
# # Workaround 2
# pn.state.param.watch(self.indicator, 'busy')
def indicator(self, busy):
print(self.a, busy)
Output (workaround 1):
1234 True
1234 False
1234 True
1234 False
Output (workaround 2):
1234 Event(what='value', name='busy', obj=state(servers=[]), cls=<class 'panel.io.state._state'>, old=False, new=True, type='changed')
1234 Event(what='value', name='busy', obj=state(servers=[]), cls=<class 'panel.io.state._state'>, old=True, new=False, type='changed')
1234 Event(what='value', name='busy', obj=state(servers=[]), cls=<class 'panel.io.state._state'>, old=False, new=True, type='changed')
1234 Event(what='value', name='busy', obj=state(servers=[]), cls=<class 'panel.io.state._state'>, old=True, new=False, type='changed')