Skip to content

pm.depends(pn.state.param.busy) on a method #500

Open
@tomas16

Description

@tomas16

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 the watch 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 boolean busy, 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')

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions