Skip to content

Commit

Permalink
Merge pull request ipython#4412 from jdfreder/traitlet_notify_fix
Browse files Browse the repository at this point in the history
Fix traitlet _notify_trait by-ref issue

This fixes a problem with the existing traitlet machinery, where anytrait values get added to the notifiers list every time the _notify_trait function is called.

The bug is that each time the traitlet changes, the anytrait callbacks will each be called N times, where N is the number of times the traitlet has been changed (in the current application instance).
  • Loading branch information
minrk committed Oct 21, 2013
2 parents a537e3d + 70e22fc commit 9abb8f6
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 3 deletions.
38 changes: 38 additions & 0 deletions IPython/utils/tests/test_traitlets.py
Original file line number Diff line number Diff line change
Expand Up @@ -363,6 +363,44 @@ class A(HasTraits):

self.assertEqual(len(a._trait_notifiers['a']),0)

def test_notify_only_once(self):

class A(HasTraits):
listen_to = ['a']

a = Int(0)
b = 0

def __init__(self, **kwargs):
super(A, self).__init__(**kwargs)
self.on_trait_change(self.listener1, ['a'])

def listener1(self, name, old, new):
self.b += 1

class B(A):

c = 0
d = 0

def __init__(self, **kwargs):
super(B, self).__init__(**kwargs)
self.on_trait_change(self.listener2)

def listener2(self, name, old, new):
self.c += 1

def _a_changed(self, name, old, new):
self.d += 1

b = B()
b.a += 1
self.assertEqual(b.b, b.c)
self.assertEqual(b.b, b.d)
b.a += 1
self.assertEqual(b.b, b.c)
self.assertEqual(b.b, b.d)


class TestHasTraits(TestCase):

Expand Down
6 changes: 3 additions & 3 deletions IPython/utils/traitlets.py
Original file line number Diff line number Diff line change
Expand Up @@ -435,9 +435,9 @@ def __init__(self, *args, **kw):
def _notify_trait(self, name, old_value, new_value):

# First dynamic ones
callables = self._trait_notifiers.get(name,[])
more_callables = self._trait_notifiers.get('anytrait',[])
callables.extend(more_callables)
callables = []
callables.extend(self._trait_notifiers.get(name,[]))
callables.extend(self._trait_notifiers.get('anytrait',[]))

# Now static ones
try:
Expand Down

0 comments on commit 9abb8f6

Please sign in to comment.