##// END OF EJS Templates
unidirectional link of traitlets
Sylvain Corlay -
Show More
@@ -1,1567 +1,1618 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """
2 """
3 A lightweight Traits like module.
3 A lightweight Traits like module.
4
4
5 This is designed to provide a lightweight, simple, pure Python version of
5 This is designed to provide a lightweight, simple, pure Python version of
6 many of the capabilities of enthought.traits. This includes:
6 many of the capabilities of enthought.traits. This includes:
7
7
8 * Validation
8 * Validation
9 * Type specification with defaults
9 * Type specification with defaults
10 * Static and dynamic notification
10 * Static and dynamic notification
11 * Basic predefined types
11 * Basic predefined types
12 * An API that is similar to enthought.traits
12 * An API that is similar to enthought.traits
13
13
14 We don't support:
14 We don't support:
15
15
16 * Delegation
16 * Delegation
17 * Automatic GUI generation
17 * Automatic GUI generation
18 * A full set of trait types. Most importantly, we don't provide container
18 * A full set of trait types. Most importantly, we don't provide container
19 traits (list, dict, tuple) that can trigger notifications if their
19 traits (list, dict, tuple) that can trigger notifications if their
20 contents change.
20 contents change.
21 * API compatibility with enthought.traits
21 * API compatibility with enthought.traits
22
22
23 There are also some important difference in our design:
23 There are also some important difference in our design:
24
24
25 * enthought.traits does not validate default values. We do.
25 * enthought.traits does not validate default values. We do.
26
26
27 We choose to create this module because we need these capabilities, but
27 We choose to create this module because we need these capabilities, but
28 we need them to be pure Python so they work in all Python implementations,
28 we need them to be pure Python so they work in all Python implementations,
29 including Jython and IronPython.
29 including Jython and IronPython.
30
30
31 Inheritance diagram:
31 Inheritance diagram:
32
32
33 .. inheritance-diagram:: IPython.utils.traitlets
33 .. inheritance-diagram:: IPython.utils.traitlets
34 :parts: 3
34 :parts: 3
35 """
35 """
36
36
37 # Copyright (c) IPython Development Team.
37 # Copyright (c) IPython Development Team.
38 # Distributed under the terms of the Modified BSD License.
38 # Distributed under the terms of the Modified BSD License.
39 #
39 #
40 # Adapted from enthought.traits, Copyright (c) Enthought, Inc.,
40 # Adapted from enthought.traits, Copyright (c) Enthought, Inc.,
41 # also under the terms of the Modified BSD License.
41 # also under the terms of the Modified BSD License.
42
42
43 import contextlib
43 import contextlib
44 import inspect
44 import inspect
45 import re
45 import re
46 import sys
46 import sys
47 import types
47 import types
48 from types import FunctionType
48 from types import FunctionType
49 try:
49 try:
50 from types import ClassType, InstanceType
50 from types import ClassType, InstanceType
51 ClassTypes = (ClassType, type)
51 ClassTypes = (ClassType, type)
52 except:
52 except:
53 ClassTypes = (type,)
53 ClassTypes = (type,)
54
54
55 from .importstring import import_item
55 from .importstring import import_item
56 from IPython.utils import py3compat
56 from IPython.utils import py3compat
57 from IPython.utils import eventful
57 from IPython.utils import eventful
58 from IPython.utils.py3compat import iteritems
58 from IPython.utils.py3compat import iteritems
59 from IPython.testing.skipdoctest import skip_doctest
59 from IPython.testing.skipdoctest import skip_doctest
60
60
61 SequenceTypes = (list, tuple, set, frozenset)
61 SequenceTypes = (list, tuple, set, frozenset)
62
62
63 #-----------------------------------------------------------------------------
63 #-----------------------------------------------------------------------------
64 # Basic classes
64 # Basic classes
65 #-----------------------------------------------------------------------------
65 #-----------------------------------------------------------------------------
66
66
67
67
68 class NoDefaultSpecified ( object ): pass
68 class NoDefaultSpecified ( object ): pass
69 NoDefaultSpecified = NoDefaultSpecified()
69 NoDefaultSpecified = NoDefaultSpecified()
70
70
71
71
72 class Undefined ( object ): pass
72 class Undefined ( object ): pass
73 Undefined = Undefined()
73 Undefined = Undefined()
74
74
75 class TraitError(Exception):
75 class TraitError(Exception):
76 pass
76 pass
77
77
78 #-----------------------------------------------------------------------------
78 #-----------------------------------------------------------------------------
79 # Utilities
79 # Utilities
80 #-----------------------------------------------------------------------------
80 #-----------------------------------------------------------------------------
81
81
82
82
83 def class_of ( object ):
83 def class_of ( object ):
84 """ Returns a string containing the class name of an object with the
84 """ Returns a string containing the class name of an object with the
85 correct indefinite article ('a' or 'an') preceding it (e.g., 'an Image',
85 correct indefinite article ('a' or 'an') preceding it (e.g., 'an Image',
86 'a PlotValue').
86 'a PlotValue').
87 """
87 """
88 if isinstance( object, py3compat.string_types ):
88 if isinstance( object, py3compat.string_types ):
89 return add_article( object )
89 return add_article( object )
90
90
91 return add_article( object.__class__.__name__ )
91 return add_article( object.__class__.__name__ )
92
92
93
93
94 def add_article ( name ):
94 def add_article ( name ):
95 """ Returns a string containing the correct indefinite article ('a' or 'an')
95 """ Returns a string containing the correct indefinite article ('a' or 'an')
96 prefixed to the specified string.
96 prefixed to the specified string.
97 """
97 """
98 if name[:1].lower() in 'aeiou':
98 if name[:1].lower() in 'aeiou':
99 return 'an ' + name
99 return 'an ' + name
100
100
101 return 'a ' + name
101 return 'a ' + name
102
102
103
103
104 def repr_type(obj):
104 def repr_type(obj):
105 """ Return a string representation of a value and its type for readable
105 """ Return a string representation of a value and its type for readable
106 error messages.
106 error messages.
107 """
107 """
108 the_type = type(obj)
108 the_type = type(obj)
109 if (not py3compat.PY3) and the_type is InstanceType:
109 if (not py3compat.PY3) and the_type is InstanceType:
110 # Old-style class.
110 # Old-style class.
111 the_type = obj.__class__
111 the_type = obj.__class__
112 msg = '%r %r' % (obj, the_type)
112 msg = '%r %r' % (obj, the_type)
113 return msg
113 return msg
114
114
115
115
116 def is_trait(t):
116 def is_trait(t):
117 """ Returns whether the given value is an instance or subclass of TraitType.
117 """ Returns whether the given value is an instance or subclass of TraitType.
118 """
118 """
119 return (isinstance(t, TraitType) or
119 return (isinstance(t, TraitType) or
120 (isinstance(t, type) and issubclass(t, TraitType)))
120 (isinstance(t, type) and issubclass(t, TraitType)))
121
121
122
122
123 def parse_notifier_name(name):
123 def parse_notifier_name(name):
124 """Convert the name argument to a list of names.
124 """Convert the name argument to a list of names.
125
125
126 Examples
126 Examples
127 --------
127 --------
128
128
129 >>> parse_notifier_name('a')
129 >>> parse_notifier_name('a')
130 ['a']
130 ['a']
131 >>> parse_notifier_name(['a','b'])
131 >>> parse_notifier_name(['a','b'])
132 ['a', 'b']
132 ['a', 'b']
133 >>> parse_notifier_name(None)
133 >>> parse_notifier_name(None)
134 ['anytrait']
134 ['anytrait']
135 """
135 """
136 if isinstance(name, str):
136 if isinstance(name, str):
137 return [name]
137 return [name]
138 elif name is None:
138 elif name is None:
139 return ['anytrait']
139 return ['anytrait']
140 elif isinstance(name, (list, tuple)):
140 elif isinstance(name, (list, tuple)):
141 for n in name:
141 for n in name:
142 assert isinstance(n, str), "names must be strings"
142 assert isinstance(n, str), "names must be strings"
143 return name
143 return name
144
144
145
145
146 class _SimpleTest:
146 class _SimpleTest:
147 def __init__ ( self, value ): self.value = value
147 def __init__ ( self, value ): self.value = value
148 def __call__ ( self, test ):
148 def __call__ ( self, test ):
149 return test == self.value
149 return test == self.value
150 def __repr__(self):
150 def __repr__(self):
151 return "<SimpleTest(%r)" % self.value
151 return "<SimpleTest(%r)" % self.value
152 def __str__(self):
152 def __str__(self):
153 return self.__repr__()
153 return self.__repr__()
154
154
155
155
156 def getmembers(object, predicate=None):
156 def getmembers(object, predicate=None):
157 """A safe version of inspect.getmembers that handles missing attributes.
157 """A safe version of inspect.getmembers that handles missing attributes.
158
158
159 This is useful when there are descriptor based attributes that for
159 This is useful when there are descriptor based attributes that for
160 some reason raise AttributeError even though they exist. This happens
160 some reason raise AttributeError even though they exist. This happens
161 in zope.inteface with the __provides__ attribute.
161 in zope.inteface with the __provides__ attribute.
162 """
162 """
163 results = []
163 results = []
164 for key in dir(object):
164 for key in dir(object):
165 try:
165 try:
166 value = getattr(object, key)
166 value = getattr(object, key)
167 except AttributeError:
167 except AttributeError:
168 pass
168 pass
169 else:
169 else:
170 if not predicate or predicate(value):
170 if not predicate or predicate(value):
171 results.append((key, value))
171 results.append((key, value))
172 results.sort()
172 results.sort()
173 return results
173 return results
174
174
175 @skip_doctest
175 @skip_doctest
176 class link(object):
176 class link(object):
177 """Link traits from different objects together so they remain in sync.
177 """Link traits from different objects together so they remain in sync.
178
178
179 Parameters
179 Parameters
180 ----------
180 ----------
181 obj : pairs of objects/attributes
181 obj : pairs of objects/attributes
182
182
183 Examples
183 Examples
184 --------
184 --------
185
185
186 >>> c = link((obj1, 'value'), (obj2, 'value'), (obj3, 'value'))
186 >>> c = link((obj1, 'value'), (obj2, 'value'), (obj3, 'value'))
187 >>> obj1.value = 5 # updates other objects as well
187 >>> obj1.value = 5 # updates other objects as well
188 """
188 """
189 updating = False
189 updating = False
190 def __init__(self, *args):
190 def __init__(self, *args):
191 if len(args) < 2:
191 if len(args) < 2:
192 raise TypeError('At least two traitlets must be provided.')
192 raise TypeError('At least two traitlets must be provided.')
193
193
194 self.objects = {}
194 self.objects = {}
195 initial = getattr(args[0][0], args[0][1])
195 initial = getattr(args[0][0], args[0][1])
196 for obj,attr in args:
196 for obj,attr in args:
197 if getattr(obj, attr) != initial:
197 if getattr(obj, attr) != initial:
198 setattr(obj, attr, initial)
198 setattr(obj, attr, initial)
199
199
200 callback = self._make_closure(obj,attr)
200 callback = self._make_closure(obj,attr)
201 obj.on_trait_change(callback, attr)
201 obj.on_trait_change(callback, attr)
202 self.objects[(obj,attr)] = callback
202 self.objects[(obj,attr)] = callback
203
203
204 @contextlib.contextmanager
204 @contextlib.contextmanager
205 def _busy_updating(self):
205 def _busy_updating(self):
206 self.updating = True
206 self.updating = True
207 try:
207 try:
208 yield
208 yield
209 finally:
209 finally:
210 self.updating = False
210 self.updating = False
211
211
212 def _make_closure(self, sending_obj, sending_attr):
212 def _make_closure(self, sending_obj, sending_attr):
213 def update(name, old, new):
213 def update(name, old, new):
214 self._update(sending_obj, sending_attr, new)
214 self._update(sending_obj, sending_attr, new)
215 return update
215 return update
216
216
217 def _update(self, sending_obj, sending_attr, new):
217 def _update(self, sending_obj, sending_attr, new):
218 if self.updating:
218 if self.updating:
219 return
219 return
220 with self._busy_updating():
220 with self._busy_updating():
221 for obj,attr in self.objects.keys():
221 for obj,attr in self.objects.keys():
222 if obj is not sending_obj or attr != sending_attr:
222 if obj is not sending_obj or attr != sending_attr:
223 setattr(obj, attr, new)
223 setattr(obj, attr, new)
224
224
225 def unlink(self):
225 def unlink(self):
226 for key, callback in self.objects.items():
226 for key, callback in self.objects.items():
227 (obj,attr) = key
227 (obj,attr) = key
228 obj.on_trait_change(callback, attr, remove=True)
228 obj.on_trait_change(callback, attr, remove=True)
229
229
230 @skip_doctest
231 class unilink(object):
232 """Link the trait of a source object with traits of target objects.
233
234 Parameters
235 ----------
236 source : pair of object, name
237 targets : pairs of objects/attributes
238
239 Examples
240 --------
241
242 >>> c = unilink((src, 'value'), (tgt1, 'value'), (tgt2, 'value'))
243 >>> src.value = 5 # updates target objects
244 >>> tgt1.value = 6 # does not update other objects
245 """
246 updating = False
247
248 def __init__(self, source, *targets):
249 self.source = source
250 self.targets = targets
251
252 # Update current value
253 src_attr_value = getattr(source[0], source[1])
254 for obj, attr in targets:
255 if getattr(obj, attr) != src_attr_value:
256 setattr(obj, attr, src_attr_value)
257
258 # Wire
259 self.source[0].on_trait_change(self._update, self.source[1])
260
261 @contextlib.contextmanager
262 def _busy_updating(self):
263 self.updating = True
264 try:
265 yield
266 finally:
267 self.updating = False
268
269 def _update(self, name, old, new):
270 if self.updating:
271 return
272 with self._busy_updating():
273 for obj, attr in self.targets:
274 setattr(obj, attr, new)
275
276 def unlink(self):
277 self.source[0].on_trait_change(self.update, self.source[1], remove=True)
278 self.source = None
279 self.targets = []
280
230 #-----------------------------------------------------------------------------
281 #-----------------------------------------------------------------------------
231 # Base TraitType for all traits
282 # Base TraitType for all traits
232 #-----------------------------------------------------------------------------
283 #-----------------------------------------------------------------------------
233
284
234
285
235 class TraitType(object):
286 class TraitType(object):
236 """A base class for all trait descriptors.
287 """A base class for all trait descriptors.
237
288
238 Notes
289 Notes
239 -----
290 -----
240 Our implementation of traits is based on Python's descriptor
291 Our implementation of traits is based on Python's descriptor
241 prototol. This class is the base class for all such descriptors. The
292 prototol. This class is the base class for all such descriptors. The
242 only magic we use is a custom metaclass for the main :class:`HasTraits`
293 only magic we use is a custom metaclass for the main :class:`HasTraits`
243 class that does the following:
294 class that does the following:
244
295
245 1. Sets the :attr:`name` attribute of every :class:`TraitType`
296 1. Sets the :attr:`name` attribute of every :class:`TraitType`
246 instance in the class dict to the name of the attribute.
297 instance in the class dict to the name of the attribute.
247 2. Sets the :attr:`this_class` attribute of every :class:`TraitType`
298 2. Sets the :attr:`this_class` attribute of every :class:`TraitType`
248 instance in the class dict to the *class* that declared the trait.
299 instance in the class dict to the *class* that declared the trait.
249 This is used by the :class:`This` trait to allow subclasses to
300 This is used by the :class:`This` trait to allow subclasses to
250 accept superclasses for :class:`This` values.
301 accept superclasses for :class:`This` values.
251 """
302 """
252
303
253
304
254 metadata = {}
305 metadata = {}
255 default_value = Undefined
306 default_value = Undefined
256 allow_none = False
307 allow_none = False
257 info_text = 'any value'
308 info_text = 'any value'
258
309
259 def __init__(self, default_value=NoDefaultSpecified, allow_none=None, **metadata):
310 def __init__(self, default_value=NoDefaultSpecified, allow_none=None, **metadata):
260 """Create a TraitType.
311 """Create a TraitType.
261 """
312 """
262 if default_value is not NoDefaultSpecified:
313 if default_value is not NoDefaultSpecified:
263 self.default_value = default_value
314 self.default_value = default_value
264 if allow_none is not None:
315 if allow_none is not None:
265 self.allow_none = allow_none
316 self.allow_none = allow_none
266
317
267 if len(metadata) > 0:
318 if len(metadata) > 0:
268 if len(self.metadata) > 0:
319 if len(self.metadata) > 0:
269 self._metadata = self.metadata.copy()
320 self._metadata = self.metadata.copy()
270 self._metadata.update(metadata)
321 self._metadata.update(metadata)
271 else:
322 else:
272 self._metadata = metadata
323 self._metadata = metadata
273 else:
324 else:
274 self._metadata = self.metadata
325 self._metadata = self.metadata
275
326
276 self.init()
327 self.init()
277
328
278 def init(self):
329 def init(self):
279 pass
330 pass
280
331
281 def get_default_value(self):
332 def get_default_value(self):
282 """Create a new instance of the default value."""
333 """Create a new instance of the default value."""
283 return self.default_value
334 return self.default_value
284
335
285 def instance_init(self, obj):
336 def instance_init(self, obj):
286 """This is called by :meth:`HasTraits.__new__` to finish init'ing.
337 """This is called by :meth:`HasTraits.__new__` to finish init'ing.
287
338
288 Some stages of initialization must be delayed until the parent
339 Some stages of initialization must be delayed until the parent
289 :class:`HasTraits` instance has been created. This method is
340 :class:`HasTraits` instance has been created. This method is
290 called in :meth:`HasTraits.__new__` after the instance has been
341 called in :meth:`HasTraits.__new__` after the instance has been
291 created.
342 created.
292
343
293 This method trigger the creation and validation of default values
344 This method trigger the creation and validation of default values
294 and also things like the resolution of str given class names in
345 and also things like the resolution of str given class names in
295 :class:`Type` and :class`Instance`.
346 :class:`Type` and :class`Instance`.
296
347
297 Parameters
348 Parameters
298 ----------
349 ----------
299 obj : :class:`HasTraits` instance
350 obj : :class:`HasTraits` instance
300 The parent :class:`HasTraits` instance that has just been
351 The parent :class:`HasTraits` instance that has just been
301 created.
352 created.
302 """
353 """
303 self.set_default_value(obj)
354 self.set_default_value(obj)
304
355
305 def set_default_value(self, obj):
356 def set_default_value(self, obj):
306 """Set the default value on a per instance basis.
357 """Set the default value on a per instance basis.
307
358
308 This method is called by :meth:`instance_init` to create and
359 This method is called by :meth:`instance_init` to create and
309 validate the default value. The creation and validation of
360 validate the default value. The creation and validation of
310 default values must be delayed until the parent :class:`HasTraits`
361 default values must be delayed until the parent :class:`HasTraits`
311 class has been instantiated.
362 class has been instantiated.
312 """
363 """
313 # Check for a deferred initializer defined in the same class as the
364 # Check for a deferred initializer defined in the same class as the
314 # trait declaration or above.
365 # trait declaration or above.
315 mro = type(obj).mro()
366 mro = type(obj).mro()
316 meth_name = '_%s_default' % self.name
367 meth_name = '_%s_default' % self.name
317 for cls in mro[:mro.index(self.this_class)+1]:
368 for cls in mro[:mro.index(self.this_class)+1]:
318 if meth_name in cls.__dict__:
369 if meth_name in cls.__dict__:
319 break
370 break
320 else:
371 else:
321 # We didn't find one. Do static initialization.
372 # We didn't find one. Do static initialization.
322 dv = self.get_default_value()
373 dv = self.get_default_value()
323 newdv = self._validate(obj, dv)
374 newdv = self._validate(obj, dv)
324 obj._trait_values[self.name] = newdv
375 obj._trait_values[self.name] = newdv
325 return
376 return
326 # Complete the dynamic initialization.
377 # Complete the dynamic initialization.
327 obj._trait_dyn_inits[self.name] = meth_name
378 obj._trait_dyn_inits[self.name] = meth_name
328
379
329 def __get__(self, obj, cls=None):
380 def __get__(self, obj, cls=None):
330 """Get the value of the trait by self.name for the instance.
381 """Get the value of the trait by self.name for the instance.
331
382
332 Default values are instantiated when :meth:`HasTraits.__new__`
383 Default values are instantiated when :meth:`HasTraits.__new__`
333 is called. Thus by the time this method gets called either the
384 is called. Thus by the time this method gets called either the
334 default value or a user defined value (they called :meth:`__set__`)
385 default value or a user defined value (they called :meth:`__set__`)
335 is in the :class:`HasTraits` instance.
386 is in the :class:`HasTraits` instance.
336 """
387 """
337 if obj is None:
388 if obj is None:
338 return self
389 return self
339 else:
390 else:
340 try:
391 try:
341 value = obj._trait_values[self.name]
392 value = obj._trait_values[self.name]
342 except KeyError:
393 except KeyError:
343 # Check for a dynamic initializer.
394 # Check for a dynamic initializer.
344 if self.name in obj._trait_dyn_inits:
395 if self.name in obj._trait_dyn_inits:
345 method = getattr(obj, obj._trait_dyn_inits[self.name])
396 method = getattr(obj, obj._trait_dyn_inits[self.name])
346 value = method()
397 value = method()
347 # FIXME: Do we really validate here?
398 # FIXME: Do we really validate here?
348 value = self._validate(obj, value)
399 value = self._validate(obj, value)
349 obj._trait_values[self.name] = value
400 obj._trait_values[self.name] = value
350 return value
401 return value
351 else:
402 else:
352 raise TraitError('Unexpected error in TraitType: '
403 raise TraitError('Unexpected error in TraitType: '
353 'both default value and dynamic initializer are '
404 'both default value and dynamic initializer are '
354 'absent.')
405 'absent.')
355 except Exception:
406 except Exception:
356 # HasTraits should call set_default_value to populate
407 # HasTraits should call set_default_value to populate
357 # this. So this should never be reached.
408 # this. So this should never be reached.
358 raise TraitError('Unexpected error in TraitType: '
409 raise TraitError('Unexpected error in TraitType: '
359 'default value not set properly')
410 'default value not set properly')
360 else:
411 else:
361 return value
412 return value
362
413
363 def __set__(self, obj, value):
414 def __set__(self, obj, value):
364 new_value = self._validate(obj, value)
415 new_value = self._validate(obj, value)
365 old_value = self.__get__(obj)
416 old_value = self.__get__(obj)
366 obj._trait_values[self.name] = new_value
417 obj._trait_values[self.name] = new_value
367 try:
418 try:
368 silent = bool(old_value == new_value)
419 silent = bool(old_value == new_value)
369 except:
420 except:
370 # if there is an error in comparing, default to notify
421 # if there is an error in comparing, default to notify
371 silent = False
422 silent = False
372 if silent is not True:
423 if silent is not True:
373 # we explicitly compare silent to True just in case the equality
424 # we explicitly compare silent to True just in case the equality
374 # comparison above returns something other than True/False
425 # comparison above returns something other than True/False
375 obj._notify_trait(self.name, old_value, new_value)
426 obj._notify_trait(self.name, old_value, new_value)
376
427
377 def _validate(self, obj, value):
428 def _validate(self, obj, value):
378 if value is None and self.allow_none:
429 if value is None and self.allow_none:
379 return value
430 return value
380 if hasattr(self, 'validate'):
431 if hasattr(self, 'validate'):
381 return self.validate(obj, value)
432 return self.validate(obj, value)
382 elif hasattr(self, 'is_valid_for'):
433 elif hasattr(self, 'is_valid_for'):
383 valid = self.is_valid_for(value)
434 valid = self.is_valid_for(value)
384 if valid:
435 if valid:
385 return value
436 return value
386 else:
437 else:
387 raise TraitError('invalid value for type: %r' % value)
438 raise TraitError('invalid value for type: %r' % value)
388 elif hasattr(self, 'value_for'):
439 elif hasattr(self, 'value_for'):
389 return self.value_for(value)
440 return self.value_for(value)
390 else:
441 else:
391 return value
442 return value
392
443
393 def info(self):
444 def info(self):
394 return self.info_text
445 return self.info_text
395
446
396 def error(self, obj, value):
447 def error(self, obj, value):
397 if obj is not None:
448 if obj is not None:
398 e = "The '%s' trait of %s instance must be %s, but a value of %s was specified." \
449 e = "The '%s' trait of %s instance must be %s, but a value of %s was specified." \
399 % (self.name, class_of(obj),
450 % (self.name, class_of(obj),
400 self.info(), repr_type(value))
451 self.info(), repr_type(value))
401 else:
452 else:
402 e = "The '%s' trait must be %s, but a value of %r was specified." \
453 e = "The '%s' trait must be %s, but a value of %r was specified." \
403 % (self.name, self.info(), repr_type(value))
454 % (self.name, self.info(), repr_type(value))
404 raise TraitError(e)
455 raise TraitError(e)
405
456
406 def get_metadata(self, key):
457 def get_metadata(self, key):
407 return getattr(self, '_metadata', {}).get(key, None)
458 return getattr(self, '_metadata', {}).get(key, None)
408
459
409 def set_metadata(self, key, value):
460 def set_metadata(self, key, value):
410 getattr(self, '_metadata', {})[key] = value
461 getattr(self, '_metadata', {})[key] = value
411
462
412
463
413 #-----------------------------------------------------------------------------
464 #-----------------------------------------------------------------------------
414 # The HasTraits implementation
465 # The HasTraits implementation
415 #-----------------------------------------------------------------------------
466 #-----------------------------------------------------------------------------
416
467
417
468
418 class MetaHasTraits(type):
469 class MetaHasTraits(type):
419 """A metaclass for HasTraits.
470 """A metaclass for HasTraits.
420
471
421 This metaclass makes sure that any TraitType class attributes are
472 This metaclass makes sure that any TraitType class attributes are
422 instantiated and sets their name attribute.
473 instantiated and sets their name attribute.
423 """
474 """
424
475
425 def __new__(mcls, name, bases, classdict):
476 def __new__(mcls, name, bases, classdict):
426 """Create the HasTraits class.
477 """Create the HasTraits class.
427
478
428 This instantiates all TraitTypes in the class dict and sets their
479 This instantiates all TraitTypes in the class dict and sets their
429 :attr:`name` attribute.
480 :attr:`name` attribute.
430 """
481 """
431 # print "MetaHasTraitlets (mcls, name): ", mcls, name
482 # print "MetaHasTraitlets (mcls, name): ", mcls, name
432 # print "MetaHasTraitlets (bases): ", bases
483 # print "MetaHasTraitlets (bases): ", bases
433 # print "MetaHasTraitlets (classdict): ", classdict
484 # print "MetaHasTraitlets (classdict): ", classdict
434 for k,v in iteritems(classdict):
485 for k,v in iteritems(classdict):
435 if isinstance(v, TraitType):
486 if isinstance(v, TraitType):
436 v.name = k
487 v.name = k
437 elif inspect.isclass(v):
488 elif inspect.isclass(v):
438 if issubclass(v, TraitType):
489 if issubclass(v, TraitType):
439 vinst = v()
490 vinst = v()
440 vinst.name = k
491 vinst.name = k
441 classdict[k] = vinst
492 classdict[k] = vinst
442 return super(MetaHasTraits, mcls).__new__(mcls, name, bases, classdict)
493 return super(MetaHasTraits, mcls).__new__(mcls, name, bases, classdict)
443
494
444 def __init__(cls, name, bases, classdict):
495 def __init__(cls, name, bases, classdict):
445 """Finish initializing the HasTraits class.
496 """Finish initializing the HasTraits class.
446
497
447 This sets the :attr:`this_class` attribute of each TraitType in the
498 This sets the :attr:`this_class` attribute of each TraitType in the
448 class dict to the newly created class ``cls``.
499 class dict to the newly created class ``cls``.
449 """
500 """
450 for k, v in iteritems(classdict):
501 for k, v in iteritems(classdict):
451 if isinstance(v, TraitType):
502 if isinstance(v, TraitType):
452 v.this_class = cls
503 v.this_class = cls
453 super(MetaHasTraits, cls).__init__(name, bases, classdict)
504 super(MetaHasTraits, cls).__init__(name, bases, classdict)
454
505
455 class HasTraits(py3compat.with_metaclass(MetaHasTraits, object)):
506 class HasTraits(py3compat.with_metaclass(MetaHasTraits, object)):
456
507
457 def __new__(cls, *args, **kw):
508 def __new__(cls, *args, **kw):
458 # This is needed because object.__new__ only accepts
509 # This is needed because object.__new__ only accepts
459 # the cls argument.
510 # the cls argument.
460 new_meth = super(HasTraits, cls).__new__
511 new_meth = super(HasTraits, cls).__new__
461 if new_meth is object.__new__:
512 if new_meth is object.__new__:
462 inst = new_meth(cls)
513 inst = new_meth(cls)
463 else:
514 else:
464 inst = new_meth(cls, **kw)
515 inst = new_meth(cls, **kw)
465 inst._trait_values = {}
516 inst._trait_values = {}
466 inst._trait_notifiers = {}
517 inst._trait_notifiers = {}
467 inst._trait_dyn_inits = {}
518 inst._trait_dyn_inits = {}
468 # Here we tell all the TraitType instances to set their default
519 # Here we tell all the TraitType instances to set their default
469 # values on the instance.
520 # values on the instance.
470 for key in dir(cls):
521 for key in dir(cls):
471 # Some descriptors raise AttributeError like zope.interface's
522 # Some descriptors raise AttributeError like zope.interface's
472 # __provides__ attributes even though they exist. This causes
523 # __provides__ attributes even though they exist. This causes
473 # AttributeErrors even though they are listed in dir(cls).
524 # AttributeErrors even though they are listed in dir(cls).
474 try:
525 try:
475 value = getattr(cls, key)
526 value = getattr(cls, key)
476 except AttributeError:
527 except AttributeError:
477 pass
528 pass
478 else:
529 else:
479 if isinstance(value, TraitType):
530 if isinstance(value, TraitType):
480 value.instance_init(inst)
531 value.instance_init(inst)
481
532
482 return inst
533 return inst
483
534
484 def __init__(self, *args, **kw):
535 def __init__(self, *args, **kw):
485 # Allow trait values to be set using keyword arguments.
536 # Allow trait values to be set using keyword arguments.
486 # We need to use setattr for this to trigger validation and
537 # We need to use setattr for this to trigger validation and
487 # notifications.
538 # notifications.
488 for key, value in iteritems(kw):
539 for key, value in iteritems(kw):
489 setattr(self, key, value)
540 setattr(self, key, value)
490
541
491 def _notify_trait(self, name, old_value, new_value):
542 def _notify_trait(self, name, old_value, new_value):
492
543
493 # First dynamic ones
544 # First dynamic ones
494 callables = []
545 callables = []
495 callables.extend(self._trait_notifiers.get(name,[]))
546 callables.extend(self._trait_notifiers.get(name,[]))
496 callables.extend(self._trait_notifiers.get('anytrait',[]))
547 callables.extend(self._trait_notifiers.get('anytrait',[]))
497
548
498 # Now static ones
549 # Now static ones
499 try:
550 try:
500 cb = getattr(self, '_%s_changed' % name)
551 cb = getattr(self, '_%s_changed' % name)
501 except:
552 except:
502 pass
553 pass
503 else:
554 else:
504 callables.append(cb)
555 callables.append(cb)
505
556
506 # Call them all now
557 # Call them all now
507 for c in callables:
558 for c in callables:
508 # Traits catches and logs errors here. I allow them to raise
559 # Traits catches and logs errors here. I allow them to raise
509 if callable(c):
560 if callable(c):
510 argspec = inspect.getargspec(c)
561 argspec = inspect.getargspec(c)
511 nargs = len(argspec[0])
562 nargs = len(argspec[0])
512 # Bound methods have an additional 'self' argument
563 # Bound methods have an additional 'self' argument
513 # I don't know how to treat unbound methods, but they
564 # I don't know how to treat unbound methods, but they
514 # can't really be used for callbacks.
565 # can't really be used for callbacks.
515 if isinstance(c, types.MethodType):
566 if isinstance(c, types.MethodType):
516 offset = -1
567 offset = -1
517 else:
568 else:
518 offset = 0
569 offset = 0
519 if nargs + offset == 0:
570 if nargs + offset == 0:
520 c()
571 c()
521 elif nargs + offset == 1:
572 elif nargs + offset == 1:
522 c(name)
573 c(name)
523 elif nargs + offset == 2:
574 elif nargs + offset == 2:
524 c(name, new_value)
575 c(name, new_value)
525 elif nargs + offset == 3:
576 elif nargs + offset == 3:
526 c(name, old_value, new_value)
577 c(name, old_value, new_value)
527 else:
578 else:
528 raise TraitError('a trait changed callback '
579 raise TraitError('a trait changed callback '
529 'must have 0-3 arguments.')
580 'must have 0-3 arguments.')
530 else:
581 else:
531 raise TraitError('a trait changed callback '
582 raise TraitError('a trait changed callback '
532 'must be callable.')
583 'must be callable.')
533
584
534
585
535 def _add_notifiers(self, handler, name):
586 def _add_notifiers(self, handler, name):
536 if name not in self._trait_notifiers:
587 if name not in self._trait_notifiers:
537 nlist = []
588 nlist = []
538 self._trait_notifiers[name] = nlist
589 self._trait_notifiers[name] = nlist
539 else:
590 else:
540 nlist = self._trait_notifiers[name]
591 nlist = self._trait_notifiers[name]
541 if handler not in nlist:
592 if handler not in nlist:
542 nlist.append(handler)
593 nlist.append(handler)
543
594
544 def _remove_notifiers(self, handler, name):
595 def _remove_notifiers(self, handler, name):
545 if name in self._trait_notifiers:
596 if name in self._trait_notifiers:
546 nlist = self._trait_notifiers[name]
597 nlist = self._trait_notifiers[name]
547 try:
598 try:
548 index = nlist.index(handler)
599 index = nlist.index(handler)
549 except ValueError:
600 except ValueError:
550 pass
601 pass
551 else:
602 else:
552 del nlist[index]
603 del nlist[index]
553
604
554 def on_trait_change(self, handler, name=None, remove=False):
605 def on_trait_change(self, handler, name=None, remove=False):
555 """Setup a handler to be called when a trait changes.
606 """Setup a handler to be called when a trait changes.
556
607
557 This is used to setup dynamic notifications of trait changes.
608 This is used to setup dynamic notifications of trait changes.
558
609
559 Static handlers can be created by creating methods on a HasTraits
610 Static handlers can be created by creating methods on a HasTraits
560 subclass with the naming convention '_[traitname]_changed'. Thus,
611 subclass with the naming convention '_[traitname]_changed'. Thus,
561 to create static handler for the trait 'a', create the method
612 to create static handler for the trait 'a', create the method
562 _a_changed(self, name, old, new) (fewer arguments can be used, see
613 _a_changed(self, name, old, new) (fewer arguments can be used, see
563 below).
614 below).
564
615
565 Parameters
616 Parameters
566 ----------
617 ----------
567 handler : callable
618 handler : callable
568 A callable that is called when a trait changes. Its
619 A callable that is called when a trait changes. Its
569 signature can be handler(), handler(name), handler(name, new)
620 signature can be handler(), handler(name), handler(name, new)
570 or handler(name, old, new).
621 or handler(name, old, new).
571 name : list, str, None
622 name : list, str, None
572 If None, the handler will apply to all traits. If a list
623 If None, the handler will apply to all traits. If a list
573 of str, handler will apply to all names in the list. If a
624 of str, handler will apply to all names in the list. If a
574 str, the handler will apply just to that name.
625 str, the handler will apply just to that name.
575 remove : bool
626 remove : bool
576 If False (the default), then install the handler. If True
627 If False (the default), then install the handler. If True
577 then unintall it.
628 then unintall it.
578 """
629 """
579 if remove:
630 if remove:
580 names = parse_notifier_name(name)
631 names = parse_notifier_name(name)
581 for n in names:
632 for n in names:
582 self._remove_notifiers(handler, n)
633 self._remove_notifiers(handler, n)
583 else:
634 else:
584 names = parse_notifier_name(name)
635 names = parse_notifier_name(name)
585 for n in names:
636 for n in names:
586 self._add_notifiers(handler, n)
637 self._add_notifiers(handler, n)
587
638
588 @classmethod
639 @classmethod
589 def class_trait_names(cls, **metadata):
640 def class_trait_names(cls, **metadata):
590 """Get a list of all the names of this class' traits.
641 """Get a list of all the names of this class' traits.
591
642
592 This method is just like the :meth:`trait_names` method,
643 This method is just like the :meth:`trait_names` method,
593 but is unbound.
644 but is unbound.
594 """
645 """
595 return cls.class_traits(**metadata).keys()
646 return cls.class_traits(**metadata).keys()
596
647
597 @classmethod
648 @classmethod
598 def class_traits(cls, **metadata):
649 def class_traits(cls, **metadata):
599 """Get a `dict` of all the traits of this class. The dictionary
650 """Get a `dict` of all the traits of this class. The dictionary
600 is keyed on the name and the values are the TraitType objects.
651 is keyed on the name and the values are the TraitType objects.
601
652
602 This method is just like the :meth:`traits` method, but is unbound.
653 This method is just like the :meth:`traits` method, but is unbound.
603
654
604 The TraitTypes returned don't know anything about the values
655 The TraitTypes returned don't know anything about the values
605 that the various HasTrait's instances are holding.
656 that the various HasTrait's instances are holding.
606
657
607 The metadata kwargs allow functions to be passed in which
658 The metadata kwargs allow functions to be passed in which
608 filter traits based on metadata values. The functions should
659 filter traits based on metadata values. The functions should
609 take a single value as an argument and return a boolean. If
660 take a single value as an argument and return a boolean. If
610 any function returns False, then the trait is not included in
661 any function returns False, then the trait is not included in
611 the output. This does not allow for any simple way of
662 the output. This does not allow for any simple way of
612 testing that a metadata name exists and has any
663 testing that a metadata name exists and has any
613 value because get_metadata returns None if a metadata key
664 value because get_metadata returns None if a metadata key
614 doesn't exist.
665 doesn't exist.
615 """
666 """
616 traits = dict([memb for memb in getmembers(cls) if
667 traits = dict([memb for memb in getmembers(cls) if
617 isinstance(memb[1], TraitType)])
668 isinstance(memb[1], TraitType)])
618
669
619 if len(metadata) == 0:
670 if len(metadata) == 0:
620 return traits
671 return traits
621
672
622 for meta_name, meta_eval in metadata.items():
673 for meta_name, meta_eval in metadata.items():
623 if type(meta_eval) is not FunctionType:
674 if type(meta_eval) is not FunctionType:
624 metadata[meta_name] = _SimpleTest(meta_eval)
675 metadata[meta_name] = _SimpleTest(meta_eval)
625
676
626 result = {}
677 result = {}
627 for name, trait in traits.items():
678 for name, trait in traits.items():
628 for meta_name, meta_eval in metadata.items():
679 for meta_name, meta_eval in metadata.items():
629 if not meta_eval(trait.get_metadata(meta_name)):
680 if not meta_eval(trait.get_metadata(meta_name)):
630 break
681 break
631 else:
682 else:
632 result[name] = trait
683 result[name] = trait
633
684
634 return result
685 return result
635
686
636 def trait_names(self, **metadata):
687 def trait_names(self, **metadata):
637 """Get a list of all the names of this class' traits."""
688 """Get a list of all the names of this class' traits."""
638 return self.traits(**metadata).keys()
689 return self.traits(**metadata).keys()
639
690
640 def traits(self, **metadata):
691 def traits(self, **metadata):
641 """Get a `dict` of all the traits of this class. The dictionary
692 """Get a `dict` of all the traits of this class. The dictionary
642 is keyed on the name and the values are the TraitType objects.
693 is keyed on the name and the values are the TraitType objects.
643
694
644 The TraitTypes returned don't know anything about the values
695 The TraitTypes returned don't know anything about the values
645 that the various HasTrait's instances are holding.
696 that the various HasTrait's instances are holding.
646
697
647 The metadata kwargs allow functions to be passed in which
698 The metadata kwargs allow functions to be passed in which
648 filter traits based on metadata values. The functions should
699 filter traits based on metadata values. The functions should
649 take a single value as an argument and return a boolean. If
700 take a single value as an argument and return a boolean. If
650 any function returns False, then the trait is not included in
701 any function returns False, then the trait is not included in
651 the output. This does not allow for any simple way of
702 the output. This does not allow for any simple way of
652 testing that a metadata name exists and has any
703 testing that a metadata name exists and has any
653 value because get_metadata returns None if a metadata key
704 value because get_metadata returns None if a metadata key
654 doesn't exist.
705 doesn't exist.
655 """
706 """
656 traits = dict([memb for memb in getmembers(self.__class__) if
707 traits = dict([memb for memb in getmembers(self.__class__) if
657 isinstance(memb[1], TraitType)])
708 isinstance(memb[1], TraitType)])
658
709
659 if len(metadata) == 0:
710 if len(metadata) == 0:
660 return traits
711 return traits
661
712
662 for meta_name, meta_eval in metadata.items():
713 for meta_name, meta_eval in metadata.items():
663 if type(meta_eval) is not FunctionType:
714 if type(meta_eval) is not FunctionType:
664 metadata[meta_name] = _SimpleTest(meta_eval)
715 metadata[meta_name] = _SimpleTest(meta_eval)
665
716
666 result = {}
717 result = {}
667 for name, trait in traits.items():
718 for name, trait in traits.items():
668 for meta_name, meta_eval in metadata.items():
719 for meta_name, meta_eval in metadata.items():
669 if not meta_eval(trait.get_metadata(meta_name)):
720 if not meta_eval(trait.get_metadata(meta_name)):
670 break
721 break
671 else:
722 else:
672 result[name] = trait
723 result[name] = trait
673
724
674 return result
725 return result
675
726
676 def trait_metadata(self, traitname, key):
727 def trait_metadata(self, traitname, key):
677 """Get metadata values for trait by key."""
728 """Get metadata values for trait by key."""
678 try:
729 try:
679 trait = getattr(self.__class__, traitname)
730 trait = getattr(self.__class__, traitname)
680 except AttributeError:
731 except AttributeError:
681 raise TraitError("Class %s does not have a trait named %s" %
732 raise TraitError("Class %s does not have a trait named %s" %
682 (self.__class__.__name__, traitname))
733 (self.__class__.__name__, traitname))
683 else:
734 else:
684 return trait.get_metadata(key)
735 return trait.get_metadata(key)
685
736
686 #-----------------------------------------------------------------------------
737 #-----------------------------------------------------------------------------
687 # Actual TraitTypes implementations/subclasses
738 # Actual TraitTypes implementations/subclasses
688 #-----------------------------------------------------------------------------
739 #-----------------------------------------------------------------------------
689
740
690 #-----------------------------------------------------------------------------
741 #-----------------------------------------------------------------------------
691 # TraitTypes subclasses for handling classes and instances of classes
742 # TraitTypes subclasses for handling classes and instances of classes
692 #-----------------------------------------------------------------------------
743 #-----------------------------------------------------------------------------
693
744
694
745
695 class ClassBasedTraitType(TraitType):
746 class ClassBasedTraitType(TraitType):
696 """A trait with error reporting for Type, Instance and This."""
747 """A trait with error reporting for Type, Instance and This."""
697
748
698 def error(self, obj, value):
749 def error(self, obj, value):
699 kind = type(value)
750 kind = type(value)
700 if (not py3compat.PY3) and kind is InstanceType:
751 if (not py3compat.PY3) and kind is InstanceType:
701 msg = 'class %s' % value.__class__.__name__
752 msg = 'class %s' % value.__class__.__name__
702 else:
753 else:
703 msg = '%s (i.e. %s)' % ( str( kind )[1:-1], repr( value ) )
754 msg = '%s (i.e. %s)' % ( str( kind )[1:-1], repr( value ) )
704
755
705 if obj is not None:
756 if obj is not None:
706 e = "The '%s' trait of %s instance must be %s, but a value of %s was specified." \
757 e = "The '%s' trait of %s instance must be %s, but a value of %s was specified." \
707 % (self.name, class_of(obj),
758 % (self.name, class_of(obj),
708 self.info(), msg)
759 self.info(), msg)
709 else:
760 else:
710 e = "The '%s' trait must be %s, but a value of %r was specified." \
761 e = "The '%s' trait must be %s, but a value of %r was specified." \
711 % (self.name, self.info(), msg)
762 % (self.name, self.info(), msg)
712
763
713 raise TraitError(e)
764 raise TraitError(e)
714
765
715
766
716 class Type(ClassBasedTraitType):
767 class Type(ClassBasedTraitType):
717 """A trait whose value must be a subclass of a specified class."""
768 """A trait whose value must be a subclass of a specified class."""
718
769
719 def __init__ (self, default_value=None, klass=None, allow_none=True, **metadata ):
770 def __init__ (self, default_value=None, klass=None, allow_none=True, **metadata ):
720 """Construct a Type trait
771 """Construct a Type trait
721
772
722 A Type trait specifies that its values must be subclasses of
773 A Type trait specifies that its values must be subclasses of
723 a particular class.
774 a particular class.
724
775
725 If only ``default_value`` is given, it is used for the ``klass`` as
776 If only ``default_value`` is given, it is used for the ``klass`` as
726 well.
777 well.
727
778
728 Parameters
779 Parameters
729 ----------
780 ----------
730 default_value : class, str or None
781 default_value : class, str or None
731 The default value must be a subclass of klass. If an str,
782 The default value must be a subclass of klass. If an str,
732 the str must be a fully specified class name, like 'foo.bar.Bah'.
783 the str must be a fully specified class name, like 'foo.bar.Bah'.
733 The string is resolved into real class, when the parent
784 The string is resolved into real class, when the parent
734 :class:`HasTraits` class is instantiated.
785 :class:`HasTraits` class is instantiated.
735 klass : class, str, None
786 klass : class, str, None
736 Values of this trait must be a subclass of klass. The klass
787 Values of this trait must be a subclass of klass. The klass
737 may be specified in a string like: 'foo.bar.MyClass'.
788 may be specified in a string like: 'foo.bar.MyClass'.
738 The string is resolved into real class, when the parent
789 The string is resolved into real class, when the parent
739 :class:`HasTraits` class is instantiated.
790 :class:`HasTraits` class is instantiated.
740 allow_none : boolean
791 allow_none : boolean
741 Indicates whether None is allowed as an assignable value. Even if
792 Indicates whether None is allowed as an assignable value. Even if
742 ``False``, the default value may be ``None``.
793 ``False``, the default value may be ``None``.
743 """
794 """
744 if default_value is None:
795 if default_value is None:
745 if klass is None:
796 if klass is None:
746 klass = object
797 klass = object
747 elif klass is None:
798 elif klass is None:
748 klass = default_value
799 klass = default_value
749
800
750 if not (inspect.isclass(klass) or isinstance(klass, py3compat.string_types)):
801 if not (inspect.isclass(klass) or isinstance(klass, py3compat.string_types)):
751 raise TraitError("A Type trait must specify a class.")
802 raise TraitError("A Type trait must specify a class.")
752
803
753 self.klass = klass
804 self.klass = klass
754
805
755 super(Type, self).__init__(default_value, allow_none=allow_none, **metadata)
806 super(Type, self).__init__(default_value, allow_none=allow_none, **metadata)
756
807
757 def validate(self, obj, value):
808 def validate(self, obj, value):
758 """Validates that the value is a valid object instance."""
809 """Validates that the value is a valid object instance."""
759 if isinstance(value, py3compat.string_types):
810 if isinstance(value, py3compat.string_types):
760 try:
811 try:
761 value = import_item(value)
812 value = import_item(value)
762 except ImportError:
813 except ImportError:
763 raise TraitError("The '%s' trait of %s instance must be a type, but "
814 raise TraitError("The '%s' trait of %s instance must be a type, but "
764 "%r could not be imported" % (self.name, obj, value))
815 "%r could not be imported" % (self.name, obj, value))
765 try:
816 try:
766 if issubclass(value, self.klass):
817 if issubclass(value, self.klass):
767 return value
818 return value
768 except:
819 except:
769 pass
820 pass
770
821
771 self.error(obj, value)
822 self.error(obj, value)
772
823
773 def info(self):
824 def info(self):
774 """ Returns a description of the trait."""
825 """ Returns a description of the trait."""
775 if isinstance(self.klass, py3compat.string_types):
826 if isinstance(self.klass, py3compat.string_types):
776 klass = self.klass
827 klass = self.klass
777 else:
828 else:
778 klass = self.klass.__name__
829 klass = self.klass.__name__
779 result = 'a subclass of ' + klass
830 result = 'a subclass of ' + klass
780 if self.allow_none:
831 if self.allow_none:
781 return result + ' or None'
832 return result + ' or None'
782 return result
833 return result
783
834
784 def instance_init(self, obj):
835 def instance_init(self, obj):
785 self._resolve_classes()
836 self._resolve_classes()
786 super(Type, self).instance_init(obj)
837 super(Type, self).instance_init(obj)
787
838
788 def _resolve_classes(self):
839 def _resolve_classes(self):
789 if isinstance(self.klass, py3compat.string_types):
840 if isinstance(self.klass, py3compat.string_types):
790 self.klass = import_item(self.klass)
841 self.klass = import_item(self.klass)
791 if isinstance(self.default_value, py3compat.string_types):
842 if isinstance(self.default_value, py3compat.string_types):
792 self.default_value = import_item(self.default_value)
843 self.default_value = import_item(self.default_value)
793
844
794 def get_default_value(self):
845 def get_default_value(self):
795 return self.default_value
846 return self.default_value
796
847
797
848
798 class DefaultValueGenerator(object):
849 class DefaultValueGenerator(object):
799 """A class for generating new default value instances."""
850 """A class for generating new default value instances."""
800
851
801 def __init__(self, *args, **kw):
852 def __init__(self, *args, **kw):
802 self.args = args
853 self.args = args
803 self.kw = kw
854 self.kw = kw
804
855
805 def generate(self, klass):
856 def generate(self, klass):
806 return klass(*self.args, **self.kw)
857 return klass(*self.args, **self.kw)
807
858
808
859
809 class Instance(ClassBasedTraitType):
860 class Instance(ClassBasedTraitType):
810 """A trait whose value must be an instance of a specified class.
861 """A trait whose value must be an instance of a specified class.
811
862
812 The value can also be an instance of a subclass of the specified class.
863 The value can also be an instance of a subclass of the specified class.
813
864
814 Subclasses can declare default classes by overriding the klass attribute
865 Subclasses can declare default classes by overriding the klass attribute
815 """
866 """
816
867
817 klass = None
868 klass = None
818
869
819 def __init__(self, klass=None, args=None, kw=None,
870 def __init__(self, klass=None, args=None, kw=None,
820 allow_none=True, **metadata ):
871 allow_none=True, **metadata ):
821 """Construct an Instance trait.
872 """Construct an Instance trait.
822
873
823 This trait allows values that are instances of a particular
874 This trait allows values that are instances of a particular
824 class or its sublclasses. Our implementation is quite different
875 class or its sublclasses. Our implementation is quite different
825 from that of enthough.traits as we don't allow instances to be used
876 from that of enthough.traits as we don't allow instances to be used
826 for klass and we handle the ``args`` and ``kw`` arguments differently.
877 for klass and we handle the ``args`` and ``kw`` arguments differently.
827
878
828 Parameters
879 Parameters
829 ----------
880 ----------
830 klass : class, str
881 klass : class, str
831 The class that forms the basis for the trait. Class names
882 The class that forms the basis for the trait. Class names
832 can also be specified as strings, like 'foo.bar.Bar'.
883 can also be specified as strings, like 'foo.bar.Bar'.
833 args : tuple
884 args : tuple
834 Positional arguments for generating the default value.
885 Positional arguments for generating the default value.
835 kw : dict
886 kw : dict
836 Keyword arguments for generating the default value.
887 Keyword arguments for generating the default value.
837 allow_none : bool
888 allow_none : bool
838 Indicates whether None is allowed as a value.
889 Indicates whether None is allowed as a value.
839
890
840 Notes
891 Notes
841 -----
892 -----
842 If both ``args`` and ``kw`` are None, then the default value is None.
893 If both ``args`` and ``kw`` are None, then the default value is None.
843 If ``args`` is a tuple and ``kw`` is a dict, then the default is
894 If ``args`` is a tuple and ``kw`` is a dict, then the default is
844 created as ``klass(*args, **kw)``. If exactly one of ``args`` or ``kw`` is
895 created as ``klass(*args, **kw)``. If exactly one of ``args`` or ``kw`` is
845 None, the None is replaced by ``()`` or ``{}``, respectively.
896 None, the None is replaced by ``()`` or ``{}``, respectively.
846 """
897 """
847 if klass is None:
898 if klass is None:
848 klass = self.klass
899 klass = self.klass
849
900
850 if (klass is not None) and (inspect.isclass(klass) or isinstance(klass, py3compat.string_types)):
901 if (klass is not None) and (inspect.isclass(klass) or isinstance(klass, py3compat.string_types)):
851 self.klass = klass
902 self.klass = klass
852 else:
903 else:
853 raise TraitError('The klass attribute must be a class'
904 raise TraitError('The klass attribute must be a class'
854 ' not: %r' % klass)
905 ' not: %r' % klass)
855
906
856 # self.klass is a class, so handle default_value
907 # self.klass is a class, so handle default_value
857 if args is None and kw is None:
908 if args is None and kw is None:
858 default_value = None
909 default_value = None
859 else:
910 else:
860 if args is None:
911 if args is None:
861 # kw is not None
912 # kw is not None
862 args = ()
913 args = ()
863 elif kw is None:
914 elif kw is None:
864 # args is not None
915 # args is not None
865 kw = {}
916 kw = {}
866
917
867 if not isinstance(kw, dict):
918 if not isinstance(kw, dict):
868 raise TraitError("The 'kw' argument must be a dict or None.")
919 raise TraitError("The 'kw' argument must be a dict or None.")
869 if not isinstance(args, tuple):
920 if not isinstance(args, tuple):
870 raise TraitError("The 'args' argument must be a tuple or None.")
921 raise TraitError("The 'args' argument must be a tuple or None.")
871
922
872 default_value = DefaultValueGenerator(*args, **kw)
923 default_value = DefaultValueGenerator(*args, **kw)
873
924
874 super(Instance, self).__init__(default_value, allow_none=allow_none, **metadata)
925 super(Instance, self).__init__(default_value, allow_none=allow_none, **metadata)
875
926
876 def validate(self, obj, value):
927 def validate(self, obj, value):
877 if isinstance(value, self.klass):
928 if isinstance(value, self.klass):
878 return value
929 return value
879 else:
930 else:
880 self.error(obj, value)
931 self.error(obj, value)
881
932
882 def info(self):
933 def info(self):
883 if isinstance(self.klass, py3compat.string_types):
934 if isinstance(self.klass, py3compat.string_types):
884 klass = self.klass
935 klass = self.klass
885 else:
936 else:
886 klass = self.klass.__name__
937 klass = self.klass.__name__
887 result = class_of(klass)
938 result = class_of(klass)
888 if self.allow_none:
939 if self.allow_none:
889 return result + ' or None'
940 return result + ' or None'
890
941
891 return result
942 return result
892
943
893 def instance_init(self, obj):
944 def instance_init(self, obj):
894 self._resolve_classes()
945 self._resolve_classes()
895 super(Instance, self).instance_init(obj)
946 super(Instance, self).instance_init(obj)
896
947
897 def _resolve_classes(self):
948 def _resolve_classes(self):
898 if isinstance(self.klass, py3compat.string_types):
949 if isinstance(self.klass, py3compat.string_types):
899 self.klass = import_item(self.klass)
950 self.klass = import_item(self.klass)
900
951
901 def get_default_value(self):
952 def get_default_value(self):
902 """Instantiate a default value instance.
953 """Instantiate a default value instance.
903
954
904 This is called when the containing HasTraits classes'
955 This is called when the containing HasTraits classes'
905 :meth:`__new__` method is called to ensure that a unique instance
956 :meth:`__new__` method is called to ensure that a unique instance
906 is created for each HasTraits instance.
957 is created for each HasTraits instance.
907 """
958 """
908 dv = self.default_value
959 dv = self.default_value
909 if isinstance(dv, DefaultValueGenerator):
960 if isinstance(dv, DefaultValueGenerator):
910 return dv.generate(self.klass)
961 return dv.generate(self.klass)
911 else:
962 else:
912 return dv
963 return dv
913
964
914
965
915 class This(ClassBasedTraitType):
966 class This(ClassBasedTraitType):
916 """A trait for instances of the class containing this trait.
967 """A trait for instances of the class containing this trait.
917
968
918 Because how how and when class bodies are executed, the ``This``
969 Because how how and when class bodies are executed, the ``This``
919 trait can only have a default value of None. This, and because we
970 trait can only have a default value of None. This, and because we
920 always validate default values, ``allow_none`` is *always* true.
971 always validate default values, ``allow_none`` is *always* true.
921 """
972 """
922
973
923 info_text = 'an instance of the same type as the receiver or None'
974 info_text = 'an instance of the same type as the receiver or None'
924
975
925 def __init__(self, **metadata):
976 def __init__(self, **metadata):
926 super(This, self).__init__(None, **metadata)
977 super(This, self).__init__(None, **metadata)
927
978
928 def validate(self, obj, value):
979 def validate(self, obj, value):
929 # What if value is a superclass of obj.__class__? This is
980 # What if value is a superclass of obj.__class__? This is
930 # complicated if it was the superclass that defined the This
981 # complicated if it was the superclass that defined the This
931 # trait.
982 # trait.
932 if isinstance(value, self.this_class) or (value is None):
983 if isinstance(value, self.this_class) or (value is None):
933 return value
984 return value
934 else:
985 else:
935 self.error(obj, value)
986 self.error(obj, value)
936
987
937
988
938 #-----------------------------------------------------------------------------
989 #-----------------------------------------------------------------------------
939 # Basic TraitTypes implementations/subclasses
990 # Basic TraitTypes implementations/subclasses
940 #-----------------------------------------------------------------------------
991 #-----------------------------------------------------------------------------
941
992
942
993
943 class Any(TraitType):
994 class Any(TraitType):
944 default_value = None
995 default_value = None
945 info_text = 'any value'
996 info_text = 'any value'
946
997
947
998
948 class Int(TraitType):
999 class Int(TraitType):
949 """An int trait."""
1000 """An int trait."""
950
1001
951 default_value = 0
1002 default_value = 0
952 info_text = 'an int'
1003 info_text = 'an int'
953
1004
954 def validate(self, obj, value):
1005 def validate(self, obj, value):
955 if isinstance(value, int):
1006 if isinstance(value, int):
956 return value
1007 return value
957 self.error(obj, value)
1008 self.error(obj, value)
958
1009
959 class CInt(Int):
1010 class CInt(Int):
960 """A casting version of the int trait."""
1011 """A casting version of the int trait."""
961
1012
962 def validate(self, obj, value):
1013 def validate(self, obj, value):
963 try:
1014 try:
964 return int(value)
1015 return int(value)
965 except:
1016 except:
966 self.error(obj, value)
1017 self.error(obj, value)
967
1018
968 if py3compat.PY3:
1019 if py3compat.PY3:
969 Long, CLong = Int, CInt
1020 Long, CLong = Int, CInt
970 Integer = Int
1021 Integer = Int
971 else:
1022 else:
972 class Long(TraitType):
1023 class Long(TraitType):
973 """A long integer trait."""
1024 """A long integer trait."""
974
1025
975 default_value = 0
1026 default_value = 0
976 info_text = 'a long'
1027 info_text = 'a long'
977
1028
978 def validate(self, obj, value):
1029 def validate(self, obj, value):
979 if isinstance(value, long):
1030 if isinstance(value, long):
980 return value
1031 return value
981 if isinstance(value, int):
1032 if isinstance(value, int):
982 return long(value)
1033 return long(value)
983 self.error(obj, value)
1034 self.error(obj, value)
984
1035
985
1036
986 class CLong(Long):
1037 class CLong(Long):
987 """A casting version of the long integer trait."""
1038 """A casting version of the long integer trait."""
988
1039
989 def validate(self, obj, value):
1040 def validate(self, obj, value):
990 try:
1041 try:
991 return long(value)
1042 return long(value)
992 except:
1043 except:
993 self.error(obj, value)
1044 self.error(obj, value)
994
1045
995 class Integer(TraitType):
1046 class Integer(TraitType):
996 """An integer trait.
1047 """An integer trait.
997
1048
998 Longs that are unnecessary (<= sys.maxint) are cast to ints."""
1049 Longs that are unnecessary (<= sys.maxint) are cast to ints."""
999
1050
1000 default_value = 0
1051 default_value = 0
1001 info_text = 'an integer'
1052 info_text = 'an integer'
1002
1053
1003 def validate(self, obj, value):
1054 def validate(self, obj, value):
1004 if isinstance(value, int):
1055 if isinstance(value, int):
1005 return value
1056 return value
1006 if isinstance(value, long):
1057 if isinstance(value, long):
1007 # downcast longs that fit in int:
1058 # downcast longs that fit in int:
1008 # note that int(n > sys.maxint) returns a long, so
1059 # note that int(n > sys.maxint) returns a long, so
1009 # we don't need a condition on this cast
1060 # we don't need a condition on this cast
1010 return int(value)
1061 return int(value)
1011 if sys.platform == "cli":
1062 if sys.platform == "cli":
1012 from System import Int64
1063 from System import Int64
1013 if isinstance(value, Int64):
1064 if isinstance(value, Int64):
1014 return int(value)
1065 return int(value)
1015 self.error(obj, value)
1066 self.error(obj, value)
1016
1067
1017
1068
1018 class Float(TraitType):
1069 class Float(TraitType):
1019 """A float trait."""
1070 """A float trait."""
1020
1071
1021 default_value = 0.0
1072 default_value = 0.0
1022 info_text = 'a float'
1073 info_text = 'a float'
1023
1074
1024 def validate(self, obj, value):
1075 def validate(self, obj, value):
1025 if isinstance(value, float):
1076 if isinstance(value, float):
1026 return value
1077 return value
1027 if isinstance(value, int):
1078 if isinstance(value, int):
1028 return float(value)
1079 return float(value)
1029 self.error(obj, value)
1080 self.error(obj, value)
1030
1081
1031
1082
1032 class CFloat(Float):
1083 class CFloat(Float):
1033 """A casting version of the float trait."""
1084 """A casting version of the float trait."""
1034
1085
1035 def validate(self, obj, value):
1086 def validate(self, obj, value):
1036 try:
1087 try:
1037 return float(value)
1088 return float(value)
1038 except:
1089 except:
1039 self.error(obj, value)
1090 self.error(obj, value)
1040
1091
1041 class Complex(TraitType):
1092 class Complex(TraitType):
1042 """A trait for complex numbers."""
1093 """A trait for complex numbers."""
1043
1094
1044 default_value = 0.0 + 0.0j
1095 default_value = 0.0 + 0.0j
1045 info_text = 'a complex number'
1096 info_text = 'a complex number'
1046
1097
1047 def validate(self, obj, value):
1098 def validate(self, obj, value):
1048 if isinstance(value, complex):
1099 if isinstance(value, complex):
1049 return value
1100 return value
1050 if isinstance(value, (float, int)):
1101 if isinstance(value, (float, int)):
1051 return complex(value)
1102 return complex(value)
1052 self.error(obj, value)
1103 self.error(obj, value)
1053
1104
1054
1105
1055 class CComplex(Complex):
1106 class CComplex(Complex):
1056 """A casting version of the complex number trait."""
1107 """A casting version of the complex number trait."""
1057
1108
1058 def validate (self, obj, value):
1109 def validate (self, obj, value):
1059 try:
1110 try:
1060 return complex(value)
1111 return complex(value)
1061 except:
1112 except:
1062 self.error(obj, value)
1113 self.error(obj, value)
1063
1114
1064 # We should always be explicit about whether we're using bytes or unicode, both
1115 # We should always be explicit about whether we're using bytes or unicode, both
1065 # for Python 3 conversion and for reliable unicode behaviour on Python 2. So
1116 # for Python 3 conversion and for reliable unicode behaviour on Python 2. So
1066 # we don't have a Str type.
1117 # we don't have a Str type.
1067 class Bytes(TraitType):
1118 class Bytes(TraitType):
1068 """A trait for byte strings."""
1119 """A trait for byte strings."""
1069
1120
1070 default_value = b''
1121 default_value = b''
1071 info_text = 'a bytes object'
1122 info_text = 'a bytes object'
1072
1123
1073 def validate(self, obj, value):
1124 def validate(self, obj, value):
1074 if isinstance(value, bytes):
1125 if isinstance(value, bytes):
1075 return value
1126 return value
1076 self.error(obj, value)
1127 self.error(obj, value)
1077
1128
1078
1129
1079 class CBytes(Bytes):
1130 class CBytes(Bytes):
1080 """A casting version of the byte string trait."""
1131 """A casting version of the byte string trait."""
1081
1132
1082 def validate(self, obj, value):
1133 def validate(self, obj, value):
1083 try:
1134 try:
1084 return bytes(value)
1135 return bytes(value)
1085 except:
1136 except:
1086 self.error(obj, value)
1137 self.error(obj, value)
1087
1138
1088
1139
1089 class Unicode(TraitType):
1140 class Unicode(TraitType):
1090 """A trait for unicode strings."""
1141 """A trait for unicode strings."""
1091
1142
1092 default_value = u''
1143 default_value = u''
1093 info_text = 'a unicode string'
1144 info_text = 'a unicode string'
1094
1145
1095 def validate(self, obj, value):
1146 def validate(self, obj, value):
1096 if isinstance(value, py3compat.unicode_type):
1147 if isinstance(value, py3compat.unicode_type):
1097 return value
1148 return value
1098 if isinstance(value, bytes):
1149 if isinstance(value, bytes):
1099 try:
1150 try:
1100 return value.decode('ascii', 'strict')
1151 return value.decode('ascii', 'strict')
1101 except UnicodeDecodeError:
1152 except UnicodeDecodeError:
1102 msg = "Could not decode {!r} for unicode trait '{}' of {} instance."
1153 msg = "Could not decode {!r} for unicode trait '{}' of {} instance."
1103 raise TraitError(msg.format(value, self.name, class_of(obj)))
1154 raise TraitError(msg.format(value, self.name, class_of(obj)))
1104 self.error(obj, value)
1155 self.error(obj, value)
1105
1156
1106
1157
1107 class CUnicode(Unicode):
1158 class CUnicode(Unicode):
1108 """A casting version of the unicode trait."""
1159 """A casting version of the unicode trait."""
1109
1160
1110 def validate(self, obj, value):
1161 def validate(self, obj, value):
1111 try:
1162 try:
1112 return py3compat.unicode_type(value)
1163 return py3compat.unicode_type(value)
1113 except:
1164 except:
1114 self.error(obj, value)
1165 self.error(obj, value)
1115
1166
1116
1167
1117 class ObjectName(TraitType):
1168 class ObjectName(TraitType):
1118 """A string holding a valid object name in this version of Python.
1169 """A string holding a valid object name in this version of Python.
1119
1170
1120 This does not check that the name exists in any scope."""
1171 This does not check that the name exists in any scope."""
1121 info_text = "a valid object identifier in Python"
1172 info_text = "a valid object identifier in Python"
1122
1173
1123 if py3compat.PY3:
1174 if py3compat.PY3:
1124 # Python 3:
1175 # Python 3:
1125 coerce_str = staticmethod(lambda _,s: s)
1176 coerce_str = staticmethod(lambda _,s: s)
1126
1177
1127 else:
1178 else:
1128 # Python 2:
1179 # Python 2:
1129 def coerce_str(self, obj, value):
1180 def coerce_str(self, obj, value):
1130 "In Python 2, coerce ascii-only unicode to str"
1181 "In Python 2, coerce ascii-only unicode to str"
1131 if isinstance(value, unicode):
1182 if isinstance(value, unicode):
1132 try:
1183 try:
1133 return str(value)
1184 return str(value)
1134 except UnicodeEncodeError:
1185 except UnicodeEncodeError:
1135 self.error(obj, value)
1186 self.error(obj, value)
1136 return value
1187 return value
1137
1188
1138 def validate(self, obj, value):
1189 def validate(self, obj, value):
1139 value = self.coerce_str(obj, value)
1190 value = self.coerce_str(obj, value)
1140
1191
1141 if isinstance(value, str) and py3compat.isidentifier(value):
1192 if isinstance(value, str) and py3compat.isidentifier(value):
1142 return value
1193 return value
1143 self.error(obj, value)
1194 self.error(obj, value)
1144
1195
1145 class DottedObjectName(ObjectName):
1196 class DottedObjectName(ObjectName):
1146 """A string holding a valid dotted object name in Python, such as A.b3._c"""
1197 """A string holding a valid dotted object name in Python, such as A.b3._c"""
1147 def validate(self, obj, value):
1198 def validate(self, obj, value):
1148 value = self.coerce_str(obj, value)
1199 value = self.coerce_str(obj, value)
1149
1200
1150 if isinstance(value, str) and py3compat.isidentifier(value, dotted=True):
1201 if isinstance(value, str) and py3compat.isidentifier(value, dotted=True):
1151 return value
1202 return value
1152 self.error(obj, value)
1203 self.error(obj, value)
1153
1204
1154
1205
1155 class Bool(TraitType):
1206 class Bool(TraitType):
1156 """A boolean (True, False) trait."""
1207 """A boolean (True, False) trait."""
1157
1208
1158 default_value = False
1209 default_value = False
1159 info_text = 'a boolean'
1210 info_text = 'a boolean'
1160
1211
1161 def validate(self, obj, value):
1212 def validate(self, obj, value):
1162 if isinstance(value, bool):
1213 if isinstance(value, bool):
1163 return value
1214 return value
1164 self.error(obj, value)
1215 self.error(obj, value)
1165
1216
1166
1217
1167 class CBool(Bool):
1218 class CBool(Bool):
1168 """A casting version of the boolean trait."""
1219 """A casting version of the boolean trait."""
1169
1220
1170 def validate(self, obj, value):
1221 def validate(self, obj, value):
1171 try:
1222 try:
1172 return bool(value)
1223 return bool(value)
1173 except:
1224 except:
1174 self.error(obj, value)
1225 self.error(obj, value)
1175
1226
1176
1227
1177 class Enum(TraitType):
1228 class Enum(TraitType):
1178 """An enum that whose value must be in a given sequence."""
1229 """An enum that whose value must be in a given sequence."""
1179
1230
1180 def __init__(self, values, default_value=None, allow_none=True, **metadata):
1231 def __init__(self, values, default_value=None, allow_none=True, **metadata):
1181 self.values = values
1232 self.values = values
1182 super(Enum, self).__init__(default_value, allow_none=allow_none, **metadata)
1233 super(Enum, self).__init__(default_value, allow_none=allow_none, **metadata)
1183
1234
1184 def validate(self, obj, value):
1235 def validate(self, obj, value):
1185 if value in self.values:
1236 if value in self.values:
1186 return value
1237 return value
1187 self.error(obj, value)
1238 self.error(obj, value)
1188
1239
1189 def info(self):
1240 def info(self):
1190 """ Returns a description of the trait."""
1241 """ Returns a description of the trait."""
1191 result = 'any of ' + repr(self.values)
1242 result = 'any of ' + repr(self.values)
1192 if self.allow_none:
1243 if self.allow_none:
1193 return result + ' or None'
1244 return result + ' or None'
1194 return result
1245 return result
1195
1246
1196 class CaselessStrEnum(Enum):
1247 class CaselessStrEnum(Enum):
1197 """An enum of strings that are caseless in validate."""
1248 """An enum of strings that are caseless in validate."""
1198
1249
1199 def validate(self, obj, value):
1250 def validate(self, obj, value):
1200 if not isinstance(value, py3compat.string_types):
1251 if not isinstance(value, py3compat.string_types):
1201 self.error(obj, value)
1252 self.error(obj, value)
1202
1253
1203 for v in self.values:
1254 for v in self.values:
1204 if v.lower() == value.lower():
1255 if v.lower() == value.lower():
1205 return v
1256 return v
1206 self.error(obj, value)
1257 self.error(obj, value)
1207
1258
1208 class Container(Instance):
1259 class Container(Instance):
1209 """An instance of a container (list, set, etc.)
1260 """An instance of a container (list, set, etc.)
1210
1261
1211 To be subclassed by overriding klass.
1262 To be subclassed by overriding klass.
1212 """
1263 """
1213 klass = None
1264 klass = None
1214 _cast_types = ()
1265 _cast_types = ()
1215 _valid_defaults = SequenceTypes
1266 _valid_defaults = SequenceTypes
1216 _trait = None
1267 _trait = None
1217
1268
1218 def __init__(self, trait=None, default_value=None, allow_none=True,
1269 def __init__(self, trait=None, default_value=None, allow_none=True,
1219 **metadata):
1270 **metadata):
1220 """Create a container trait type from a list, set, or tuple.
1271 """Create a container trait type from a list, set, or tuple.
1221
1272
1222 The default value is created by doing ``List(default_value)``,
1273 The default value is created by doing ``List(default_value)``,
1223 which creates a copy of the ``default_value``.
1274 which creates a copy of the ``default_value``.
1224
1275
1225 ``trait`` can be specified, which restricts the type of elements
1276 ``trait`` can be specified, which restricts the type of elements
1226 in the container to that TraitType.
1277 in the container to that TraitType.
1227
1278
1228 If only one arg is given and it is not a Trait, it is taken as
1279 If only one arg is given and it is not a Trait, it is taken as
1229 ``default_value``:
1280 ``default_value``:
1230
1281
1231 ``c = List([1,2,3])``
1282 ``c = List([1,2,3])``
1232
1283
1233 Parameters
1284 Parameters
1234 ----------
1285 ----------
1235
1286
1236 trait : TraitType [ optional ]
1287 trait : TraitType [ optional ]
1237 the type for restricting the contents of the Container. If unspecified,
1288 the type for restricting the contents of the Container. If unspecified,
1238 types are not checked.
1289 types are not checked.
1239
1290
1240 default_value : SequenceType [ optional ]
1291 default_value : SequenceType [ optional ]
1241 The default value for the Trait. Must be list/tuple/set, and
1292 The default value for the Trait. Must be list/tuple/set, and
1242 will be cast to the container type.
1293 will be cast to the container type.
1243
1294
1244 allow_none : Bool [ default True ]
1295 allow_none : Bool [ default True ]
1245 Whether to allow the value to be None
1296 Whether to allow the value to be None
1246
1297
1247 **metadata : any
1298 **metadata : any
1248 further keys for extensions to the Trait (e.g. config)
1299 further keys for extensions to the Trait (e.g. config)
1249
1300
1250 """
1301 """
1251 # allow List([values]):
1302 # allow List([values]):
1252 if default_value is None and not is_trait(trait):
1303 if default_value is None and not is_trait(trait):
1253 default_value = trait
1304 default_value = trait
1254 trait = None
1305 trait = None
1255
1306
1256 if default_value is None:
1307 if default_value is None:
1257 args = ()
1308 args = ()
1258 elif isinstance(default_value, self._valid_defaults):
1309 elif isinstance(default_value, self._valid_defaults):
1259 args = (default_value,)
1310 args = (default_value,)
1260 else:
1311 else:
1261 raise TypeError('default value of %s was %s' %(self.__class__.__name__, default_value))
1312 raise TypeError('default value of %s was %s' %(self.__class__.__name__, default_value))
1262
1313
1263 if is_trait(trait):
1314 if is_trait(trait):
1264 self._trait = trait() if isinstance(trait, type) else trait
1315 self._trait = trait() if isinstance(trait, type) else trait
1265 self._trait.name = 'element'
1316 self._trait.name = 'element'
1266 elif trait is not None:
1317 elif trait is not None:
1267 raise TypeError("`trait` must be a Trait or None, got %s"%repr_type(trait))
1318 raise TypeError("`trait` must be a Trait or None, got %s"%repr_type(trait))
1268
1319
1269 super(Container,self).__init__(klass=self.klass, args=args,
1320 super(Container,self).__init__(klass=self.klass, args=args,
1270 allow_none=allow_none, **metadata)
1321 allow_none=allow_none, **metadata)
1271
1322
1272 def element_error(self, obj, element, validator):
1323 def element_error(self, obj, element, validator):
1273 e = "Element of the '%s' trait of %s instance must be %s, but a value of %s was specified." \
1324 e = "Element of the '%s' trait of %s instance must be %s, but a value of %s was specified." \
1274 % (self.name, class_of(obj), validator.info(), repr_type(element))
1325 % (self.name, class_of(obj), validator.info(), repr_type(element))
1275 raise TraitError(e)
1326 raise TraitError(e)
1276
1327
1277 def validate(self, obj, value):
1328 def validate(self, obj, value):
1278 if isinstance(value, self._cast_types):
1329 if isinstance(value, self._cast_types):
1279 value = self.klass(value)
1330 value = self.klass(value)
1280 value = super(Container, self).validate(obj, value)
1331 value = super(Container, self).validate(obj, value)
1281 if value is None:
1332 if value is None:
1282 return value
1333 return value
1283
1334
1284 value = self.validate_elements(obj, value)
1335 value = self.validate_elements(obj, value)
1285
1336
1286 return value
1337 return value
1287
1338
1288 def validate_elements(self, obj, value):
1339 def validate_elements(self, obj, value):
1289 validated = []
1340 validated = []
1290 if self._trait is None or isinstance(self._trait, Any):
1341 if self._trait is None or isinstance(self._trait, Any):
1291 return value
1342 return value
1292 for v in value:
1343 for v in value:
1293 try:
1344 try:
1294 v = self._trait._validate(obj, v)
1345 v = self._trait._validate(obj, v)
1295 except TraitError:
1346 except TraitError:
1296 self.element_error(obj, v, self._trait)
1347 self.element_error(obj, v, self._trait)
1297 else:
1348 else:
1298 validated.append(v)
1349 validated.append(v)
1299 return self.klass(validated)
1350 return self.klass(validated)
1300
1351
1301 def instance_init(self, obj):
1352 def instance_init(self, obj):
1302 if isinstance(self._trait, Instance):
1353 if isinstance(self._trait, Instance):
1303 self._trait._resolve_classes()
1354 self._trait._resolve_classes()
1304 super(Container, self).instance_init(obj)
1355 super(Container, self).instance_init(obj)
1305
1356
1306
1357
1307 class List(Container):
1358 class List(Container):
1308 """An instance of a Python list."""
1359 """An instance of a Python list."""
1309 klass = list
1360 klass = list
1310 _cast_types = (tuple,)
1361 _cast_types = (tuple,)
1311
1362
1312 def __init__(self, trait=None, default_value=None, minlen=0, maxlen=sys.maxsize,
1363 def __init__(self, trait=None, default_value=None, minlen=0, maxlen=sys.maxsize,
1313 allow_none=True, **metadata):
1364 allow_none=True, **metadata):
1314 """Create a List trait type from a list, set, or tuple.
1365 """Create a List trait type from a list, set, or tuple.
1315
1366
1316 The default value is created by doing ``List(default_value)``,
1367 The default value is created by doing ``List(default_value)``,
1317 which creates a copy of the ``default_value``.
1368 which creates a copy of the ``default_value``.
1318
1369
1319 ``trait`` can be specified, which restricts the type of elements
1370 ``trait`` can be specified, which restricts the type of elements
1320 in the container to that TraitType.
1371 in the container to that TraitType.
1321
1372
1322 If only one arg is given and it is not a Trait, it is taken as
1373 If only one arg is given and it is not a Trait, it is taken as
1323 ``default_value``:
1374 ``default_value``:
1324
1375
1325 ``c = List([1,2,3])``
1376 ``c = List([1,2,3])``
1326
1377
1327 Parameters
1378 Parameters
1328 ----------
1379 ----------
1329
1380
1330 trait : TraitType [ optional ]
1381 trait : TraitType [ optional ]
1331 the type for restricting the contents of the Container. If unspecified,
1382 the type for restricting the contents of the Container. If unspecified,
1332 types are not checked.
1383 types are not checked.
1333
1384
1334 default_value : SequenceType [ optional ]
1385 default_value : SequenceType [ optional ]
1335 The default value for the Trait. Must be list/tuple/set, and
1386 The default value for the Trait. Must be list/tuple/set, and
1336 will be cast to the container type.
1387 will be cast to the container type.
1337
1388
1338 minlen : Int [ default 0 ]
1389 minlen : Int [ default 0 ]
1339 The minimum length of the input list
1390 The minimum length of the input list
1340
1391
1341 maxlen : Int [ default sys.maxsize ]
1392 maxlen : Int [ default sys.maxsize ]
1342 The maximum length of the input list
1393 The maximum length of the input list
1343
1394
1344 allow_none : Bool [ default True ]
1395 allow_none : Bool [ default True ]
1345 Whether to allow the value to be None
1396 Whether to allow the value to be None
1346
1397
1347 **metadata : any
1398 **metadata : any
1348 further keys for extensions to the Trait (e.g. config)
1399 further keys for extensions to the Trait (e.g. config)
1349
1400
1350 """
1401 """
1351 self._minlen = minlen
1402 self._minlen = minlen
1352 self._maxlen = maxlen
1403 self._maxlen = maxlen
1353 super(List, self).__init__(trait=trait, default_value=default_value,
1404 super(List, self).__init__(trait=trait, default_value=default_value,
1354 allow_none=allow_none, **metadata)
1405 allow_none=allow_none, **metadata)
1355
1406
1356 def length_error(self, obj, value):
1407 def length_error(self, obj, value):
1357 e = "The '%s' trait of %s instance must be of length %i <= L <= %i, but a value of %s was specified." \
1408 e = "The '%s' trait of %s instance must be of length %i <= L <= %i, but a value of %s was specified." \
1358 % (self.name, class_of(obj), self._minlen, self._maxlen, value)
1409 % (self.name, class_of(obj), self._minlen, self._maxlen, value)
1359 raise TraitError(e)
1410 raise TraitError(e)
1360
1411
1361 def validate_elements(self, obj, value):
1412 def validate_elements(self, obj, value):
1362 length = len(value)
1413 length = len(value)
1363 if length < self._minlen or length > self._maxlen:
1414 if length < self._minlen or length > self._maxlen:
1364 self.length_error(obj, value)
1415 self.length_error(obj, value)
1365
1416
1366 return super(List, self).validate_elements(obj, value)
1417 return super(List, self).validate_elements(obj, value)
1367
1418
1368 def validate(self, obj, value):
1419 def validate(self, obj, value):
1369 value = super(List, self).validate(obj, value)
1420 value = super(List, self).validate(obj, value)
1370
1421
1371 value = self.validate_elements(obj, value)
1422 value = self.validate_elements(obj, value)
1372
1423
1373 return value
1424 return value
1374
1425
1375
1426
1376
1427
1377 class Set(List):
1428 class Set(List):
1378 """An instance of a Python set."""
1429 """An instance of a Python set."""
1379 klass = set
1430 klass = set
1380 _cast_types = (tuple, list)
1431 _cast_types = (tuple, list)
1381
1432
1382 class Tuple(Container):
1433 class Tuple(Container):
1383 """An instance of a Python tuple."""
1434 """An instance of a Python tuple."""
1384 klass = tuple
1435 klass = tuple
1385 _cast_types = (list,)
1436 _cast_types = (list,)
1386
1437
1387 def __init__(self, *traits, **metadata):
1438 def __init__(self, *traits, **metadata):
1388 """Tuple(*traits, default_value=None, allow_none=True, **medatata)
1439 """Tuple(*traits, default_value=None, allow_none=True, **medatata)
1389
1440
1390 Create a tuple from a list, set, or tuple.
1441 Create a tuple from a list, set, or tuple.
1391
1442
1392 Create a fixed-type tuple with Traits:
1443 Create a fixed-type tuple with Traits:
1393
1444
1394 ``t = Tuple(Int, Str, CStr)``
1445 ``t = Tuple(Int, Str, CStr)``
1395
1446
1396 would be length 3, with Int,Str,CStr for each element.
1447 would be length 3, with Int,Str,CStr for each element.
1397
1448
1398 If only one arg is given and it is not a Trait, it is taken as
1449 If only one arg is given and it is not a Trait, it is taken as
1399 default_value:
1450 default_value:
1400
1451
1401 ``t = Tuple((1,2,3))``
1452 ``t = Tuple((1,2,3))``
1402
1453
1403 Otherwise, ``default_value`` *must* be specified by keyword.
1454 Otherwise, ``default_value`` *must* be specified by keyword.
1404
1455
1405 Parameters
1456 Parameters
1406 ----------
1457 ----------
1407
1458
1408 *traits : TraitTypes [ optional ]
1459 *traits : TraitTypes [ optional ]
1409 the tsype for restricting the contents of the Tuple. If unspecified,
1460 the tsype for restricting the contents of the Tuple. If unspecified,
1410 types are not checked. If specified, then each positional argument
1461 types are not checked. If specified, then each positional argument
1411 corresponds to an element of the tuple. Tuples defined with traits
1462 corresponds to an element of the tuple. Tuples defined with traits
1412 are of fixed length.
1463 are of fixed length.
1413
1464
1414 default_value : SequenceType [ optional ]
1465 default_value : SequenceType [ optional ]
1415 The default value for the Tuple. Must be list/tuple/set, and
1466 The default value for the Tuple. Must be list/tuple/set, and
1416 will be cast to a tuple. If `traits` are specified, the
1467 will be cast to a tuple. If `traits` are specified, the
1417 `default_value` must conform to the shape and type they specify.
1468 `default_value` must conform to the shape and type they specify.
1418
1469
1419 allow_none : Bool [ default True ]
1470 allow_none : Bool [ default True ]
1420 Whether to allow the value to be None
1471 Whether to allow the value to be None
1421
1472
1422 **metadata : any
1473 **metadata : any
1423 further keys for extensions to the Trait (e.g. config)
1474 further keys for extensions to the Trait (e.g. config)
1424
1475
1425 """
1476 """
1426 default_value = metadata.pop('default_value', None)
1477 default_value = metadata.pop('default_value', None)
1427 allow_none = metadata.pop('allow_none', True)
1478 allow_none = metadata.pop('allow_none', True)
1428
1479
1429 # allow Tuple((values,)):
1480 # allow Tuple((values,)):
1430 if len(traits) == 1 and default_value is None and not is_trait(traits[0]):
1481 if len(traits) == 1 and default_value is None and not is_trait(traits[0]):
1431 default_value = traits[0]
1482 default_value = traits[0]
1432 traits = ()
1483 traits = ()
1433
1484
1434 if default_value is None:
1485 if default_value is None:
1435 args = ()
1486 args = ()
1436 elif isinstance(default_value, self._valid_defaults):
1487 elif isinstance(default_value, self._valid_defaults):
1437 args = (default_value,)
1488 args = (default_value,)
1438 else:
1489 else:
1439 raise TypeError('default value of %s was %s' %(self.__class__.__name__, default_value))
1490 raise TypeError('default value of %s was %s' %(self.__class__.__name__, default_value))
1440
1491
1441 self._traits = []
1492 self._traits = []
1442 for trait in traits:
1493 for trait in traits:
1443 t = trait() if isinstance(trait, type) else trait
1494 t = trait() if isinstance(trait, type) else trait
1444 t.name = 'element'
1495 t.name = 'element'
1445 self._traits.append(t)
1496 self._traits.append(t)
1446
1497
1447 if self._traits and default_value is None:
1498 if self._traits and default_value is None:
1448 # don't allow default to be an empty container if length is specified
1499 # don't allow default to be an empty container if length is specified
1449 args = None
1500 args = None
1450 super(Container,self).__init__(klass=self.klass, args=args,
1501 super(Container,self).__init__(klass=self.klass, args=args,
1451 allow_none=allow_none, **metadata)
1502 allow_none=allow_none, **metadata)
1452
1503
1453 def validate_elements(self, obj, value):
1504 def validate_elements(self, obj, value):
1454 if not self._traits:
1505 if not self._traits:
1455 # nothing to validate
1506 # nothing to validate
1456 return value
1507 return value
1457 if len(value) != len(self._traits):
1508 if len(value) != len(self._traits):
1458 e = "The '%s' trait of %s instance requires %i elements, but a value of %s was specified." \
1509 e = "The '%s' trait of %s instance requires %i elements, but a value of %s was specified." \
1459 % (self.name, class_of(obj), len(self._traits), repr_type(value))
1510 % (self.name, class_of(obj), len(self._traits), repr_type(value))
1460 raise TraitError(e)
1511 raise TraitError(e)
1461
1512
1462 validated = []
1513 validated = []
1463 for t,v in zip(self._traits, value):
1514 for t,v in zip(self._traits, value):
1464 try:
1515 try:
1465 v = t._validate(obj, v)
1516 v = t._validate(obj, v)
1466 except TraitError:
1517 except TraitError:
1467 self.element_error(obj, v, t)
1518 self.element_error(obj, v, t)
1468 else:
1519 else:
1469 validated.append(v)
1520 validated.append(v)
1470 return tuple(validated)
1521 return tuple(validated)
1471
1522
1472
1523
1473 class Dict(Instance):
1524 class Dict(Instance):
1474 """An instance of a Python dict."""
1525 """An instance of a Python dict."""
1475
1526
1476 def __init__(self, default_value=None, allow_none=True, **metadata):
1527 def __init__(self, default_value=None, allow_none=True, **metadata):
1477 """Create a dict trait type from a dict.
1528 """Create a dict trait type from a dict.
1478
1529
1479 The default value is created by doing ``dict(default_value)``,
1530 The default value is created by doing ``dict(default_value)``,
1480 which creates a copy of the ``default_value``.
1531 which creates a copy of the ``default_value``.
1481 """
1532 """
1482 if default_value is None:
1533 if default_value is None:
1483 args = ((),)
1534 args = ((),)
1484 elif isinstance(default_value, dict):
1535 elif isinstance(default_value, dict):
1485 args = (default_value,)
1536 args = (default_value,)
1486 elif isinstance(default_value, SequenceTypes):
1537 elif isinstance(default_value, SequenceTypes):
1487 args = (default_value,)
1538 args = (default_value,)
1488 else:
1539 else:
1489 raise TypeError('default value of Dict was %s' % default_value)
1540 raise TypeError('default value of Dict was %s' % default_value)
1490
1541
1491 super(Dict,self).__init__(klass=dict, args=args,
1542 super(Dict,self).__init__(klass=dict, args=args,
1492 allow_none=allow_none, **metadata)
1543 allow_none=allow_none, **metadata)
1493
1544
1494
1545
1495 class EventfulDict(Instance):
1546 class EventfulDict(Instance):
1496 """An instance of an EventfulDict."""
1547 """An instance of an EventfulDict."""
1497
1548
1498 def __init__(self, default_value=None, allow_none=True, **metadata):
1549 def __init__(self, default_value=None, allow_none=True, **metadata):
1499 """Create a EventfulDict trait type from a dict.
1550 """Create a EventfulDict trait type from a dict.
1500
1551
1501 The default value is created by doing
1552 The default value is created by doing
1502 ``eventful.EvenfulDict(default_value)``, which creates a copy of the
1553 ``eventful.EvenfulDict(default_value)``, which creates a copy of the
1503 ``default_value``.
1554 ``default_value``.
1504 """
1555 """
1505 if default_value is None:
1556 if default_value is None:
1506 args = ((),)
1557 args = ((),)
1507 elif isinstance(default_value, dict):
1558 elif isinstance(default_value, dict):
1508 args = (default_value,)
1559 args = (default_value,)
1509 elif isinstance(default_value, SequenceTypes):
1560 elif isinstance(default_value, SequenceTypes):
1510 args = (default_value,)
1561 args = (default_value,)
1511 else:
1562 else:
1512 raise TypeError('default value of EventfulDict was %s' % default_value)
1563 raise TypeError('default value of EventfulDict was %s' % default_value)
1513
1564
1514 super(EventfulDict, self).__init__(klass=eventful.EventfulDict, args=args,
1565 super(EventfulDict, self).__init__(klass=eventful.EventfulDict, args=args,
1515 allow_none=allow_none, **metadata)
1566 allow_none=allow_none, **metadata)
1516
1567
1517
1568
1518 class EventfulList(Instance):
1569 class EventfulList(Instance):
1519 """An instance of an EventfulList."""
1570 """An instance of an EventfulList."""
1520
1571
1521 def __init__(self, default_value=None, allow_none=True, **metadata):
1572 def __init__(self, default_value=None, allow_none=True, **metadata):
1522 """Create a EventfulList trait type from a dict.
1573 """Create a EventfulList trait type from a dict.
1523
1574
1524 The default value is created by doing
1575 The default value is created by doing
1525 ``eventful.EvenfulList(default_value)``, which creates a copy of the
1576 ``eventful.EvenfulList(default_value)``, which creates a copy of the
1526 ``default_value``.
1577 ``default_value``.
1527 """
1578 """
1528 if default_value is None:
1579 if default_value is None:
1529 args = ((),)
1580 args = ((),)
1530 else:
1581 else:
1531 args = (default_value,)
1582 args = (default_value,)
1532
1583
1533 super(EventfulList, self).__init__(klass=eventful.EventfulList, args=args,
1584 super(EventfulList, self).__init__(klass=eventful.EventfulList, args=args,
1534 allow_none=allow_none, **metadata)
1585 allow_none=allow_none, **metadata)
1535
1586
1536
1587
1537 class TCPAddress(TraitType):
1588 class TCPAddress(TraitType):
1538 """A trait for an (ip, port) tuple.
1589 """A trait for an (ip, port) tuple.
1539
1590
1540 This allows for both IPv4 IP addresses as well as hostnames.
1591 This allows for both IPv4 IP addresses as well as hostnames.
1541 """
1592 """
1542
1593
1543 default_value = ('127.0.0.1', 0)
1594 default_value = ('127.0.0.1', 0)
1544 info_text = 'an (ip, port) tuple'
1595 info_text = 'an (ip, port) tuple'
1545
1596
1546 def validate(self, obj, value):
1597 def validate(self, obj, value):
1547 if isinstance(value, tuple):
1598 if isinstance(value, tuple):
1548 if len(value) == 2:
1599 if len(value) == 2:
1549 if isinstance(value[0], py3compat.string_types) and isinstance(value[1], int):
1600 if isinstance(value[0], py3compat.string_types) and isinstance(value[1], int):
1550 port = value[1]
1601 port = value[1]
1551 if port >= 0 and port <= 65535:
1602 if port >= 0 and port <= 65535:
1552 return value
1603 return value
1553 self.error(obj, value)
1604 self.error(obj, value)
1554
1605
1555 class CRegExp(TraitType):
1606 class CRegExp(TraitType):
1556 """A casting compiled regular expression trait.
1607 """A casting compiled regular expression trait.
1557
1608
1558 Accepts both strings and compiled regular expressions. The resulting
1609 Accepts both strings and compiled regular expressions. The resulting
1559 attribute will be a compiled regular expression."""
1610 attribute will be a compiled regular expression."""
1560
1611
1561 info_text = 'a regular expression'
1612 info_text = 'a regular expression'
1562
1613
1563 def validate(self, obj, value):
1614 def validate(self, obj, value):
1564 try:
1615 try:
1565 return re.compile(value)
1616 return re.compile(value)
1566 except:
1617 except:
1567 self.error(obj, value)
1618 self.error(obj, value)
General Comments 0
You need to be logged in to leave comments. Login now