Show More
@@ -292,6 +292,13 b' class Widget(LoggingConfigurable):' | |||
|
292 | 292 | True if the callback should be unregistered.""" |
|
293 | 293 | self._display_callbacks.register_callback(callback, remove=remove) |
|
294 | 294 | |
|
295 | def add_trait(self, traitname, trait): | |
|
296 | """Dynamically add a trait attribute to the Widget.""" | |
|
297 | super(Widget, self).add_trait(traitname, trait) | |
|
298 | if trait.get_metadata('sync'): | |
|
299 | self.keys.append(traitname) | |
|
300 | self.send_state(traitname) | |
|
301 | ||
|
295 | 302 | #------------------------------------------------------------------------- |
|
296 | 303 | # Support methods |
|
297 | 304 | #------------------------------------------------------------------------- |
@@ -1563,3 +1563,55 b' class TestForwardDeclaredTypeList(TraitTestBase):' | |||
|
1563 | 1563 | ### |
|
1564 | 1564 | # End Forward Declaration Tests |
|
1565 | 1565 | ### |
|
1566 | ||
|
1567 | class TestDynamicTraits(TestCase): | |
|
1568 | ||
|
1569 | def setUp(self): | |
|
1570 | self._notify1 = [] | |
|
1571 | ||
|
1572 | def notify1(self, name, old, new): | |
|
1573 | self._notify1.append((name, old, new)) | |
|
1574 | ||
|
1575 | def test_notify_all(self): | |
|
1576 | ||
|
1577 | class A(HasTraits): | |
|
1578 | pass | |
|
1579 | ||
|
1580 | a = A() | |
|
1581 | self.assertTrue(not hasattr(a, 'x')) | |
|
1582 | self.assertTrue(not hasattr(a, 'y')) | |
|
1583 | ||
|
1584 | # Dynamically add trait x. | |
|
1585 | a.add_trait('x', Int()) | |
|
1586 | self.assertTrue(hasattr(a, 'x')) | |
|
1587 | self.assertTrue(isinstance(a, (A, ))) | |
|
1588 | ||
|
1589 | # Dynamically add trait y. | |
|
1590 | a.add_trait('y', Float()) | |
|
1591 | self.assertTrue(hasattr(a, 'y')) | |
|
1592 | self.assertTrue(isinstance(a, (A, ))) | |
|
1593 | self.assertEqual(a.__class__.__name__, A.__name__) | |
|
1594 | ||
|
1595 | # Create a new instance and verify that x and y | |
|
1596 | # aren't defined. | |
|
1597 | b = A() | |
|
1598 | self.assertTrue(not hasattr(b, 'x')) | |
|
1599 | self.assertTrue(not hasattr(b, 'y')) | |
|
1600 | ||
|
1601 | # Verify that notification works like normal. | |
|
1602 | a.on_trait_change(self.notify1) | |
|
1603 | a.x = 0 | |
|
1604 | self.assertEqual(len(self._notify1), 0) | |
|
1605 | a.y = 0.0 | |
|
1606 | self.assertEqual(len(self._notify1), 0) | |
|
1607 | a.x = 10 | |
|
1608 | self.assertTrue(('x', 0, 10) in self._notify1) | |
|
1609 | a.y = 10.0 | |
|
1610 | self.assertTrue(('y', 0.0, 10.0) in self._notify1) | |
|
1611 | self.assertRaises(TraitError, setattr, a, 'x', 'bad string') | |
|
1612 | self.assertRaises(TraitError, setattr, a, 'y', 'bad string') | |
|
1613 | self._notify1 = [] | |
|
1614 | a.on_trait_change(self.notify1, remove=True) | |
|
1615 | a.x = 20 | |
|
1616 | a.y = 20.0 | |
|
1617 | self.assertEqual(len(self._notify1), 0) |
@@ -804,6 +804,12 b' class HasTraits(py3compat.with_metaclass(MetaHasTraits, object)):' | |||
|
804 | 804 | else: |
|
805 | 805 | return trait.get_metadata(key, default) |
|
806 | 806 | |
|
807 | def add_trait(self, traitname, trait): | |
|
808 | """Dynamically add a trait attribute to the HasTraits instance.""" | |
|
809 | self.__class__ = type(self.__class__.__name__, (self.__class__,), | |
|
810 | {traitname: trait}) | |
|
811 | trait.set_default_value(self) | |
|
812 | ||
|
807 | 813 | #----------------------------------------------------------------------------- |
|
808 | 814 | # Actual TraitTypes implementations/subclasses |
|
809 | 815 | #----------------------------------------------------------------------------- |
General Comments 0
You need to be logged in to leave comments.
Login now