Show More
@@ -292,6 +292,13 b' class Widget(LoggingConfigurable):' | |||||
292 | True if the callback should be unregistered.""" |
|
292 | True if the callback should be unregistered.""" | |
293 | self._display_callbacks.register_callback(callback, remove=remove) |
|
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 | # Support methods |
|
303 | # Support methods | |
297 | #------------------------------------------------------------------------- |
|
304 | #------------------------------------------------------------------------- |
@@ -1563,3 +1563,55 b' class TestForwardDeclaredTypeList(TraitTestBase):' | |||||
1563 | ### |
|
1563 | ### | |
1564 | # End Forward Declaration Tests |
|
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 | else: |
|
804 | else: | |
805 | return trait.get_metadata(key, default) |
|
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 | # Actual TraitTypes implementations/subclasses |
|
814 | # Actual TraitTypes implementations/subclasses | |
809 | #----------------------------------------------------------------------------- |
|
815 | #----------------------------------------------------------------------------- |
General Comments 0
You need to be logged in to leave comments.
Login now