##// END OF EJS Templates
ENH: Add dynamic initializers (_x_default methods) to traitlets.
Robert Kern -
Show More
@@ -129,6 +129,29 b' class TestTraitType(TestCase):'
129 a = A()
129 a = A()
130 self.assertRaises(TraitError, A.tt.error, a, 10)
130 self.assertRaises(TraitError, A.tt.error, a, 10)
131
131
132 def test_dynamic_initializer(self):
133 class A(HasTraits):
134 x = Int(10)
135 def _x_default(self):
136 return 11
137 class B(A):
138 x = Int(20)
139 class C(A):
140 def _x_default(self):
141 return 21
142
143 a = A()
144 self.assertEquals(a._trait_values, {})
145 self.assertEquals(a.x, 11)
146 self.assertEquals(a._trait_values, {'x': 11})
147 b = B()
148 self.assertEquals(b._trait_values, {'x': 20})
149 self.assertEquals(b.x, 20)
150 c = C()
151 self.assertEquals(c._trait_values, {})
152 self.assertEquals(c.x, 21)
153 self.assertEquals(c._trait_values, {'x': 21})
154
132
155
133 class TestHasTraitsMeta(TestCase):
156 class TestHasTraitsMeta(TestCase):
134
157
@@ -248,9 +248,21 b' class TraitType(object):'
248 default values must be delayed until the parent :class:`HasTraits`
248 default values must be delayed until the parent :class:`HasTraits`
249 class has been instantiated.
249 class has been instantiated.
250 """
250 """
251 # Check for a deferred initializer defined in the same class as the
252 # trait declaration or above.
253 mro = type(obj).mro()
254 meth_name = '_%s_default' % self.name
255 for cls in mro[:mro.index(self.this_class)+1]:
256 if meth_name in cls.__dict__:
257 break
258 else:
259 # We didn't find one. Do static initialization.
251 dv = self.get_default_value()
260 dv = self.get_default_value()
252 newdv = self._validate(obj, dv)
261 newdv = self._validate(obj, dv)
253 obj._trait_values[self.name] = newdv
262 obj._trait_values[self.name] = newdv
263 return
264 # Complete the dynamic initialization.
265 self.dynamic_initializer = cls.__dict__[meth_name]
254
266
255 def __get__(self, obj, cls=None):
267 def __get__(self, obj, cls=None):
256 """Get the value of the trait by self.name for the instance.
268 """Get the value of the trait by self.name for the instance.
@@ -265,7 +277,19 b' class TraitType(object):'
265 else:
277 else:
266 try:
278 try:
267 value = obj._trait_values[self.name]
279 value = obj._trait_values[self.name]
268 except:
280 except KeyError:
281 # Check for a dynamic initializer.
282 if hasattr(self, 'dynamic_initializer'):
283 value = self.dynamic_initializer(obj)
284 # FIXME: Do we really validate here?
285 value = self._validate(obj, value)
286 obj._trait_values[self.name] = value
287 return value
288 else:
289 raise TraitError('Unexpected error in TraitType: '
290 'both default value and dynamic initializer are '
291 'absent.')
292 except Exception:
269 # HasTraits should call set_default_value to populate
293 # HasTraits should call set_default_value to populate
270 # this. So this should never be reached.
294 # this. So this should never be reached.
271 raise TraitError('Unexpected error in TraitType: '
295 raise TraitError('Unexpected error in TraitType: '
@@ -294,6 +318,11 b' class TraitType(object):'
294 else:
318 else:
295 return value
319 return value
296
320
321 def set_dynamic_initializer(self, method):
322 """ Set the dynamic initializer method, if any.
323 """
324 self.dynamic_initializer = method
325
297 def info(self):
326 def info(self):
298 return self.info_text
327 return self.info_text
299
328
General Comments 0
You need to be logged in to leave comments. Login now