Skip to content

Commit efc40bb

Browse files
authored
Fix repeated Property triggering in subclasses (#1587) (#1588)
(cherry picked from commit c903296)
1 parent cb33473 commit efc40bb

File tree

3 files changed

+42
-7
lines changed

3 files changed

+42
-7
lines changed

CHANGES.rst

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,20 @@
11
Traits CHANGELOG
22
================
33

4+
Release 6.3.2
5+
-------------
6+
7+
Released: XXXX-XX-XX
8+
9+
Traits 6.3.2 is a bugfix release.
10+
11+
Fixes
12+
~~~~~
13+
14+
* Fix that ``Property`` traits using ``observe`` metadata could be fired
15+
twice in subclasses. (#1587)
16+
17+
418
Release 6.3.1
519
-------------
620

traits/has_traits.py

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -559,8 +559,7 @@ def update_traits_class_dict(class_name, bases, class_dict):
559559

560560
observer_states = getattr(value, "_observe_inputs", None)
561561
if observer_states is not None:
562-
stack = observers.setdefault(name, [])
563-
stack.extend(observer_states)
562+
observers[name] = observer_states
564563

565564
elif isinstance(value, property):
566565
class_traits[name] = generic_trait
@@ -613,9 +612,8 @@ def update_traits_class_dict(class_name, bases, class_dict):
613612

614613
# Merge observer information:
615614
for name, states in base_dict[ObserverTraits].items():
616-
if name not in class_traits and name not in class_dict:
617-
stack = observers.setdefault(name, [])
618-
stack.extend(states)
615+
if (name not in class_traits) and (name not in class_dict):
616+
observers[name] = states
619617

620618
# Merge base traits:
621619
for name, value in base_dict.get(BaseTraits).items():
@@ -758,8 +756,7 @@ def update_traits_class_dict(class_name, bases, class_dict):
758756
property_name=name,
759757
cached=trait.cached,
760758
)
761-
stack = observers.setdefault(name, [])
762-
stack.append(observer_state)
759+
observers[name] = [observer_state]
763760

764761
# Add processed traits back into class_dict.
765762
class_dict[BaseTraits] = base_traits

traits/tests/test_observe.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
Int,
2626
List,
2727
observe,
28+
Property,
2829
Set,
2930
Str,
3031
Undefined,
@@ -882,3 +883,26 @@ def test_anytrait_unobserve(self):
882883

883884
# No additional events.
884885
self.assertEqual(len(events), 2)
886+
887+
def test_property_subclass_observe(self):
888+
# Regression test for enthought/traits#1586
889+
class Base(HasTraits):
890+
bar = Int()
891+
892+
foo = Property(Int(), observe="bar")
893+
894+
def _get_foo(self):
895+
return self.bar
896+
897+
class Derived(Base):
898+
pass
899+
900+
events = []
901+
902+
obj = Derived(bar=3)
903+
obj.observe(events.append, "foo")
904+
905+
# Changing bar should result in a single event.
906+
self.assertEqual(len(events), 0)
907+
obj.bar = 5
908+
self.assertEqual(len(events), 1)

0 commit comments

Comments
 (0)