Show More
@@ -20,7 +20,7 b' Authors:' | |||
|
20 | 20 | # Imports |
|
21 | 21 | #----------------------------------------------------------------------------- |
|
22 | 22 | |
|
23 | ||
|
23 | from copy import deepcopy | |
|
24 | 24 | from weakref import WeakValueDictionary |
|
25 | 25 | |
|
26 | 26 | from IPython.utils.ipstruct import Struct |
@@ -134,7 +134,7 b' class Component(HasTraitlets):' | |||
|
134 | 134 | name : str |
|
135 | 135 | The unique name of the component. If empty, then a unique |
|
136 | 136 | one will be autogenerated. |
|
137 |
config : |
|
|
137 | config : Struct | |
|
138 | 138 | If this is empty, self.config = parent.config, otherwise |
|
139 | 139 | self.config = config and root.config is ignored. This argument |
|
140 | 140 | should only be used to *override* the automatic inheritance of |
@@ -165,10 +165,10 b' class Component(HasTraitlets):' | |||
|
165 | 165 | self.root = self # This is the default, it is set when parent is set |
|
166 | 166 | self.parent = parent |
|
167 | 167 | if config is not None: |
|
168 | self.config = config | |
|
168 | self.config = deepcopy(config) | |
|
169 | 169 | else: |
|
170 | 170 | if self.parent is not None: |
|
171 | self.config = self.parent.config | |
|
171 | self.config = deepcopy(self.parent.config) | |
|
172 | 172 | |
|
173 | 173 | #------------------------------------------------------------------------- |
|
174 | 174 | # Static traitlet notifiations |
@@ -193,7 +193,18 b' class Component(HasTraitlets):' | |||
|
193 | 193 | if not self.parent.root is new: |
|
194 | 194 | raise ComponentError("Error in setting the root attribute: " |
|
195 | 195 | "root != parent.root") |
|
196 | ||
|
196 | ||
|
197 | def _config_changed(self, name, old, new): | |
|
198 | # Get all traitlets with a config_key metadata entry | |
|
199 | traitlets = self.traitlets(config_key=lambda v: True) | |
|
200 | for k, v in traitlets.items(): | |
|
201 | try: | |
|
202 | config_value = new[v.get_metadata('config_key')] | |
|
203 | except KeyError: | |
|
204 | pass | |
|
205 | else: | |
|
206 | setattr(self, k, config_value) | |
|
207 | ||
|
197 | 208 | @property |
|
198 | 209 | def children(self): |
|
199 | 210 | """A list of all my child components.""" |
@@ -24,7 +24,7 b' from unittest import TestCase' | |||
|
24 | 24 | |
|
25 | 25 | from IPython.core.component import Component, ComponentError |
|
26 | 26 | from IPython.utils.traitlets import ( |
|
27 | TraitletError | |
|
27 | TraitletError, Int, Float, Str | |
|
28 | 28 | ) |
|
29 | 29 | from IPython.utils.ipstruct import Struct |
|
30 | 30 | |
@@ -147,6 +147,30 b' class TestComponentConfig(TestCase):' | |||
|
147 | 147 | self.assertEquals(c1.config, config) |
|
148 | 148 | self.assertEquals(c2.config, config) |
|
149 | 149 | self.assertEquals(c3.config, config) |
|
150 | # Test that we always make copies | |
|
151 | self.assert_(c1.config is not config) | |
|
152 | self.assert_(c2.config is not config) | |
|
153 | self.assert_(c3.config is not config) | |
|
154 | self.assert_(c1.config is not c2.config) | |
|
155 | self.assert_(c2.config is not c3.config) | |
|
156 | ||
|
157 | def test_inheritance(self): | |
|
158 | class MyComponent(Component): | |
|
159 | a = Int(1, config_key='A') | |
|
160 | b = Float(1.0, config_key='B') | |
|
161 | c = Str('no config') | |
|
162 | config = Struct() | |
|
163 | config.A = 2 | |
|
164 | config.B = 2.0 | |
|
165 | c1 = MyComponent(None, config=config) | |
|
166 | c2 = MyComponent(c1) | |
|
167 | self.assertEquals(c1.a, config.A) | |
|
168 | self.assertEquals(c1.b, config.B) | |
|
169 | self.assertEquals(c2.a, config.A) | |
|
170 | self.assertEquals(c2.b, config.B) | |
|
171 | c4 = MyComponent(c2, config=Struct()) | |
|
172 | self.assertEquals(c4.a, 1) | |
|
173 | self.assertEquals(c4.b, 1.0) | |
|
150 | 174 | |
|
151 | 175 | class TestComponentName(TestCase): |
|
152 | 176 |
@@ -42,7 +42,7 b' class Struct(dict):' | |||
|
42 | 42 | * Intelligent merging. |
|
43 | 43 | * Overloaded operators. |
|
44 | 44 | """ |
|
45 | ||
|
45 | _allownew = True | |
|
46 | 46 | def __init__(self, *args, **kw): |
|
47 | 47 | """Initialize with a dictionary, another Struct, or data. |
|
48 | 48 |
@@ -327,15 +327,37 b' class TestHasTraitletsNotify(TestCase):' | |||
|
327 | 327 | self.assertEquals(len(a._traitlet_notifiers['a']),0) |
|
328 | 328 | |
|
329 | 329 | |
|
330 |
class TestTraitlet |
|
|
330 | class TestHasTraitlets(TestCase): | |
|
331 | 331 | |
|
332 |
def test_ |
|
|
332 | def test_traitlet_names(self): | |
|
333 | 333 | class A(HasTraitlets): |
|
334 |
|
|
|
335 |
|
|
|
334 | i = Int | |
|
335 | f = Float | |
|
336 | a = A() | |
|
337 | self.assertEquals(a.traitlet_names(),['i','f']) | |
|
338 | ||
|
339 | def test_traitlet_metadata(self): | |
|
340 | class A(HasTraitlets): | |
|
341 | i = Int(config_key='MY_VALUE') | |
|
336 | 342 | a = A() |
|
337 |
self.assertEquals(a.traitlet_ |
|
|
343 | self.assertEquals(a.traitlet_metadata('i','config_key'), 'MY_VALUE') | |
|
338 | 344 | |
|
345 | def test_traitlets(self): | |
|
346 | class A(HasTraitlets): | |
|
347 | i = Int | |
|
348 | f = Float | |
|
349 | a = A() | |
|
350 | self.assertEquals(a.traitlets(), dict(i=A.i, f=A.f)) | |
|
351 | ||
|
352 | def test_traitlets_metadata(self): | |
|
353 | class A(HasTraitlets): | |
|
354 | i = Int(config_key='VALUE1', other_thing='VALUE2') | |
|
355 | f = Float(config_key='VALUE3', other_thing='VALUE2') | |
|
356 | a = A() | |
|
357 | # traitlets = a.traitlets(config_key=lambda v: True) | |
|
358 | # self.assertEquals(traitlets, dict(i=A.i, f=A.f)) | |
|
359 | traitlets = a.traitlets(config_key='VALUE1', other_thing='VALUE2') | |
|
360 | self.assertEquals(traitlets, dict(i=A.i)) | |
|
339 | 361 | |
|
340 | 362 | #----------------------------------------------------------------------------- |
|
341 | 363 | # Tests for specific traitlet types |
@@ -52,7 +52,7 b' Authors:' | |||
|
52 | 52 | import inspect |
|
53 | 53 | import sys |
|
54 | 54 | import types |
|
55 | from types import InstanceType, ClassType | |
|
55 | from types import InstanceType, ClassType, FunctionType | |
|
56 | 56 | |
|
57 | 57 | ClassTypes = (ClassType, type) |
|
58 | 58 | |
@@ -133,6 +133,18 b' def parse_notifier_name(name):' | |||
|
133 | 133 | assert isinstance(n, str), "names must be strings" |
|
134 | 134 | return name |
|
135 | 135 | |
|
136 | ||
|
137 | class _SimpleTest: | |
|
138 | def __init__ ( self, value ): self.value = value | |
|
139 | def __call__ ( self, test ): | |
|
140 | print test, self.value | |
|
141 | return test == self.value | |
|
142 | def __repr__(self): | |
|
143 | return "<SimpleTest(%r)" % self.value | |
|
144 | def __str__(self): | |
|
145 | return self.__repr__() | |
|
146 | ||
|
147 | ||
|
136 | 148 | #----------------------------------------------------------------------------- |
|
137 | 149 | # Base TraitletType for all traitlets |
|
138 | 150 | #----------------------------------------------------------------------------- |
@@ -166,7 +178,16 b' class TraitletType(object):' | |||
|
166 | 178 | """ |
|
167 | 179 | if default_value is not NoDefaultSpecified: |
|
168 | 180 | self.default_value = default_value |
|
169 | self.metadata.update(metadata) | |
|
181 | ||
|
182 | if len(metadata) > 0: | |
|
183 | if len(self.metadata) > 0: | |
|
184 | self._metadata = self.metadata.copy() | |
|
185 | self._metadata.update(metadata) | |
|
186 | else: | |
|
187 | self._metadata = metadata | |
|
188 | else: | |
|
189 | self._metadata = self.metadata | |
|
190 | ||
|
170 | 191 | self.init() |
|
171 | 192 | |
|
172 | 193 | def init(self): |
@@ -238,6 +259,12 b' class TraitletType(object):' | |||
|
238 | 259 | % (self.name, self.info(), repr_type(value)) |
|
239 | 260 | raise TraitletError(e) |
|
240 | 261 | |
|
262 | def get_metadata(self, key): | |
|
263 | return getattr(self, '_metadata', {}).get(key, None) | |
|
264 | ||
|
265 | def set_metadata(self, key, value): | |
|
266 | getattr(self, '_metadata', {})[key] = value | |
|
267 | ||
|
241 | 268 | |
|
242 | 269 | #----------------------------------------------------------------------------- |
|
243 | 270 | # The HasTraitlets implementation |
@@ -303,7 +330,6 b' class HasTraitlets(object):' | |||
|
303 | 330 | for key in dir(cls): |
|
304 | 331 | value = getattr(cls, key) |
|
305 | 332 | if isinstance(value, TraitletType): |
|
306 | # print 'value: ', value | |
|
307 | 333 | value.set_default_value(inst) |
|
308 | 334 | return inst |
|
309 | 335 | |
@@ -408,10 +434,44 b' class HasTraitlets(object):' | |||
|
408 | 434 | for n in names: |
|
409 | 435 | self._add_notifiers(handler, n) |
|
410 | 436 | |
|
411 | def traitlet_names(self): | |
|
437 | def traitlet_names(self, **metadata): | |
|
412 | 438 | """Get a list of all the names of this classes traitlets.""" |
|
413 | return [memb[0] for memb in inspect.getmembers(self.__class__) if isinstance(memb[1], TraitletType)] | |
|
439 | return self.traitlets(**metadata).keys() | |
|
414 | 440 | |
|
441 | def traitlets(self, **metadata): | |
|
442 | """Get a list of all the traitlets of this class. | |
|
443 | ||
|
444 | The TraitletTypes returned don't know anything about the values | |
|
445 | that the various HasTraitlet's instances are holding. | |
|
446 | """ | |
|
447 | traitlets = dict([memb for memb in inspect.getmembers(self.__class__) if \ | |
|
448 | isinstance(memb[1], TraitletType)]) | |
|
449 | if len(metadata) == 0: | |
|
450 | return traitlets | |
|
451 | ||
|
452 | for meta_name, meta_eval in metadata.items(): | |
|
453 | if type(meta_eval) is not FunctionType: | |
|
454 | metadata[meta_name] = _SimpleTest(meta_eval) | |
|
455 | ||
|
456 | result = {} | |
|
457 | for name, traitlet in traitlets.items(): | |
|
458 | for meta_name, meta_eval in metadata.items(): | |
|
459 | if not meta_eval(traitlet.get_metadata(meta_name)): | |
|
460 | break | |
|
461 | else: | |
|
462 | result[name] = traitlet | |
|
463 | ||
|
464 | return result | |
|
465 | ||
|
466 | def traitlet_metadata(self, traitletname, key): | |
|
467 | """Get metadata values for traitlet by key.""" | |
|
468 | try: | |
|
469 | traitlet = getattr(self.__class__, traitletname) | |
|
470 | except AttributeError: | |
|
471 | raise TraitletError("Class %s does not have a traitlet named %s" % | |
|
472 | (self.__class__.__name__, traitletname)) | |
|
473 | else: | |
|
474 | return traitlet.get_metadata(key) | |
|
415 | 475 | |
|
416 | 476 | #----------------------------------------------------------------------------- |
|
417 | 477 | # Actual TraitletTypes implementations/subclasses |
General Comments 0
You need to be logged in to leave comments.
Login now