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