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