Reputation: 2981
I have some external objects listening/handling another object's traits. How can I get a list of the listeners/handlers to that objects traits? I have multiple objects listening to another's traits and I'd like to be able to query somehow and determine which ones are still connected.
Thanks!
Here's an example using the Enthought Traits module:
from traits.api import HasTraits,Str,Int,Float
class GenerateEvents ( HasTraits ):
name = Str
age = Int
weight = Float
class ListenEvents ( HasTraits ):
def _name_changed ( self, object, name, old, new ):
print "_name_changed:", object, name, old, new
def _age_changed ( self, object, name, old, new ):
print "_age_changed:", object, name, old, new
def _weight_changed ( self, object, name, old, new ):
print "_weight_changed:", object, name, old, new
class AnotherListenEvents ( HasTraits ):
def _name_changed ( self, object, name, old, new ):
print "Another _name_changed:", object, name, old, new
def _age_changed ( self, object, name, old, new ):
print "another _age_changed:", object, name, old, new
def _weight_changed ( self, object, name, old, new ):
print "another _weight_changed:", object, name, old, new
ge = GenerateEvents()
le = ListenEvents()
ale = AnotherListenEvents()
ge.set( name = 'Joe', age = 22, weight = 152.0 )
ge.add_trait_listener( le )
ge.add_trait_listener( ale )
ge.set( name = 'Mike', age = 34, weight = 178.0 )
Note that ge
has two listeners, le
and ale
. However, given ge
how could I find out what the listeners are? Note that listeners can added/removed dynamically in the code so they are not fixed.
I hope that clarifies a bit.
Upvotes: 2
Views: 375
Reputation: 114921
Take a look at Robert Kern's answer in this thread from the enthought-dev mailing list: http://enthought-dev.117412.n3.nabble.com/How-do-I-find-the-listeners-for-a-trait-td1716192.html
Here's a modified version of your code, with a couple functions added for retrieving and displaying the listeners. I added a static listener _age_changed
, a listener created with the on_trait_change
decorator, and a listener created with ge.on_trait_change(...)
.
from traits.api import (HasTraits, Str, Int, Float, on_trait_change,
TraitChangeNotifyWrapper)
from traits.trait_notifiers import StaticTraitChangeNotifyWrapper
def get_listeners(h):
"""
h must be a HasTraits instance.
Returns a dictionary whose keys are trait names and whose values
are lists of notifiers.
"""
listeners = {}
for name in h.traits():
notifiers = h.trait(name)._notifiers(0)
if notifiers is not None:
# Filter out the static listeners. Comment this out
# if you want to keep those.
notifiers = [notifier for notifier in notifiers
if not isinstance(notifier, StaticTraitChangeNotifyWrapper)]
listeners[name] = notifiers
return listeners
def print_listeners(listeners):
"""
Print the dictionary of listeners returned by `get_listeners(h)`.
"""
for name, notifiers in listeners.items():
print "trait '%s' has the following listeners:" % (name,)
for notifier in notifiers:
if notifier.name is None:
handler = notifier.handler
print " '%s' %r" % (handler.__name__, type(handler))
else:
print " '%s' on object %s" % (notifier.name, notifier.object)
class GenerateEvents ( HasTraits ):
name = Str
age = Int
weight = Float
def _age_changed(self, old):
print "age changed from ", old, "to", self.age
@on_trait_change('weight')
def do_something(self, obj, name, old, new):
print "do_something: name =", name
class ListenEvents ( HasTraits ):
def _name_changed ( self, object, name, old, new ):
print "_name_changed:", object, name, old, new
def _age_changed ( self, object, name, old, new ):
print "_age_changed:", object, name, old, new
def _weight_changed ( self, object, name, old, new ):
print "_weight_changed:", object, name, old, new
class AnotherListenEvents ( HasTraits ):
def _name_changed ( self, object, name, old, new ):
print "Another _name_changed:", object, name, old, new
def _age_changed ( self, object, name, old, new ):
print "another _age_changed:", object, name, old, new
def _weight_changed ( self, object, name, old, new ):
print "another _weight_changed:", object, name, old, new
def printit(foo):
print foo
ge = GenerateEvents()
le = ListenEvents()
ale = AnotherListenEvents()
ge.set( name = 'Joe', age = 22, weight = 152.0 )
ge.add_trait_listener( le )
ge.add_trait_listener( ale )
ge.set( name = 'Mike', age = 34, weight = 178.0 )
# Make the function `printit` a listener to ge.name.
ge.on_trait_change(printit, name='name')
Here's what you get when you run it (in ipython):
In [103]: run trait_listeners_question
age changed from 22 to 22
do_something: name = weight
age changed from 34 to 34
_age_changed: <__main__.GenerateEvents object at 0x2680950> age 22 34
another _age_changed: <__main__.GenerateEvents object at 0x2680950> age 22 34
_name_changed: <__main__.GenerateEvents object at 0x2680950> name Joe Mike
Another _name_changed: <__main__.GenerateEvents object at 0x2680950> name Joe Mike
do_something: name = weight
_weight_changed: <__main__.GenerateEvents object at 0x2680950> weight 152.0 178.0
another _weight_changed: <__main__.GenerateEvents object at 0x2680950> weight 152.0 178.0
In [104]: listeners = get_listeners(ge)
In [105]: print_listeners(listeners)
trait 'trait_added' has the following listeners:
'_trait_added_changed' on object <weakref at 0x2656d08; to 'ListenEvents' at 0x2680d70>
'_trait_added_changed' on object <weakref at 0x2656e68; to 'AnotherListenEvents' at 0x26808f0>
trait 'age' has the following listeners:
'_age_changed' on object <weakref at 0x2656c58; to 'ListenEvents' at 0x2680d70>
'_age_changed' on object <weakref at 0x2656db8; to 'AnotherListenEvents' at 0x26808f0>
trait 'ev' has the following listeners:
'_ev_changed' on object <weakref at 0x2656c00; to 'ListenEvents' at 0x2680d70>
trait 'name' has the following listeners:
'_name_changed' on object <weakref at 0x2656cb0; to 'ListenEvents' at 0x2680d70>
'_name_changed' on object <weakref at 0x2656e10; to 'AnotherListenEvents' at 0x26808f0>
'printit' <type 'function'>
trait 'weight' has the following listeners:
'do_something' on object <weakref at 0x2671368; to 'GenerateEvents' at 0x2680950>
'_weight_changed' on object <weakref at 0x2656ba8; to 'ListenEvents' at 0x2680d70>
'_weight_changed' on object <weakref at 0x2656d60; to 'AnotherListenEvents' at 0x26808f0>
Upvotes: 1