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

Add API to access watchers #780

Closed
maximlt opened this issue Jun 30, 2023 · 1 comment · Fixed by #797
Closed

Add API to access watchers #780

maximlt opened this issue Jun 30, 2023 · 1 comment · Fixed by #797
Labels
type-feature Feature request
Milestone

Comments

@maximlt
Copy link
Member

maximlt commented Jun 30, 2023

Following @philippjfr's comment in #766 (comment), we have identified the need to provide an API to access watchers.

More precisely, it seems like we do not have an API to access watchers on an instance, which are currently available through the private attribute _param_watchers:

import param

class P(param.Parameterized):
    x = param.Parameter()
    
    @param.depends('x', watch=True)
    def d(self): pass

p = P()
print(p._param_watchers)
# {'x': {'value': [Watcher(inst=P(name='P00005', x=None), cls=<class '__main__.P'>, fn=<function _m_caller.<locals>.caller at 0x118fa5c10>, mode='args', onlychanged=True, parameter_names=('x',), what='value', queued=False, precedence=-1)]}}
print(p.param['x'].watchers)
# {}

There is a sort of public API to access the watchers set on class Parameters:

import param

class P(param.Parameterized):
    x = param.Parameter()

P.param.watch(lambda e: print(e), 'x')
print(P.param['x'].watchers)
# {'value': [Watcher(inst=None, cls=<class '__main__.P'>, fn=<function <lambda> at 0x103f3b1f0>, mode='args', onlychanged=True, parameter_names=('x',), what='value', queued=False, precedence=0)]}

There is the public .param.watchers that under the hood returns the watchers queue defined on _parameters_state, that holds transient data:

import param

class P(param.Parameterized):
    x = param.Parameter()
    
    @param.depends('x', watch=True)
    def d(self): pass

p = P()
p._param_watchers

print('start', p.param.watchers)
with param.parameterized.batch_call_watchers(p):
    print('   start cm', p.param.watchers)
    p.x = 1
    p.x = 2
    p.x = 3
    print('   end cm', p.param.watchers)
print('end', p.param.watchers)

Output:

start []
   start cm []
   end cm [Watcher(inst=P(name='P00005', x=3), cls=<class '__main__.P'>, fn=<function _m_caller.<locals>.caller at 0x118fa5c10>, mode='args', onlychanged=True, parameter_names=('x',), what='value', queued=False, precedence=-1)]
end []

Among those _param_watchers is likely the one the most required by users. It's accessed in Panel and Lumen, I've found one other usage on Github https://github.com/grepler/sqlmodel-panel-poc/blob/bf8b3ab1b3e31476f6fcbb451a7dc78fb555d29d/helpers.py#L215.

@maximlt maximlt added the type-feature Feature request label Jun 30, 2023
@maximlt maximlt added this to the 2.0 milestone Jun 30, 2023
@maximlt
Copy link
Member Author

maximlt commented Jul 10, 2023

Do you have any opinion on this @philippjfr ? It seems it's unfortunate that .param.watchers is already used, as it seems more like an internal API made public.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type-feature Feature request
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant