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