##// END OF EJS Templates
CBytes and CStr only try casting to bytes (=str), not to unicode.
Thomas Kluyver -
Show More
@@ -1,1358 +1,1355 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 Bytes(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, bytes):
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 CBytes(Bytes):
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 bytes(value)
972 return bytes(value)
973 except:
973 except:
974 try:
974 self.error(obj, value)
975 return unicode(value)
976 except:
977 self.error(obj, value)
978
975
979
976
980 class Unicode(TraitType):
977 class Unicode(TraitType):
981 """A trait for unicode strings."""
978 """A trait for unicode strings."""
982
979
983 default_value = u''
980 default_value = u''
984 info_text = 'a unicode string'
981 info_text = 'a unicode string'
985
982
986 def validate(self, obj, value):
983 def validate(self, obj, value):
987 if isinstance(value, unicode):
984 if isinstance(value, unicode):
988 return value
985 return value
989 if isinstance(value, bytes):
986 if isinstance(value, bytes):
990 return unicode(value)
987 return unicode(value)
991 self.error(obj, value)
988 self.error(obj, value)
992
989
993
990
994 class CUnicode(Unicode):
991 class CUnicode(Unicode):
995 """A casting version of the unicode trait."""
992 """A casting version of the unicode trait."""
996
993
997 def validate(self, obj, value):
994 def validate(self, obj, value):
998 try:
995 try:
999 return unicode(value)
996 return unicode(value)
1000 except:
997 except:
1001 self.error(obj, value)
998 self.error(obj, value)
1002
999
1003 if sys.version_info[0] < 3:
1000 if sys.version_info[0] < 3:
1004 Str, CStr = Bytes, CBytes
1001 Str, CStr = Bytes, CBytes
1005 else:
1002 else:
1006 Str, CStr = Unicode, CUnicode
1003 Str, CStr = Unicode, CUnicode
1007
1004
1008
1005
1009 class Bool(TraitType):
1006 class Bool(TraitType):
1010 """A boolean (True, False) trait."""
1007 """A boolean (True, False) trait."""
1011
1008
1012 default_value = False
1009 default_value = False
1013 info_text = 'a boolean'
1010 info_text = 'a boolean'
1014
1011
1015 def validate(self, obj, value):
1012 def validate(self, obj, value):
1016 if isinstance(value, bool):
1013 if isinstance(value, bool):
1017 return value
1014 return value
1018 self.error(obj, value)
1015 self.error(obj, value)
1019
1016
1020
1017
1021 class CBool(Bool):
1018 class CBool(Bool):
1022 """A casting version of the boolean trait."""
1019 """A casting version of the boolean trait."""
1023
1020
1024 def validate(self, obj, value):
1021 def validate(self, obj, value):
1025 try:
1022 try:
1026 return bool(value)
1023 return bool(value)
1027 except:
1024 except:
1028 self.error(obj, value)
1025 self.error(obj, value)
1029
1026
1030
1027
1031 class Enum(TraitType):
1028 class Enum(TraitType):
1032 """An enum that whose value must be in a given sequence."""
1029 """An enum that whose value must be in a given sequence."""
1033
1030
1034 def __init__(self, values, default_value=None, allow_none=True, **metadata):
1031 def __init__(self, values, default_value=None, allow_none=True, **metadata):
1035 self.values = values
1032 self.values = values
1036 self._allow_none = allow_none
1033 self._allow_none = allow_none
1037 super(Enum, self).__init__(default_value, **metadata)
1034 super(Enum, self).__init__(default_value, **metadata)
1038
1035
1039 def validate(self, obj, value):
1036 def validate(self, obj, value):
1040 if value is None:
1037 if value is None:
1041 if self._allow_none:
1038 if self._allow_none:
1042 return value
1039 return value
1043
1040
1044 if value in self.values:
1041 if value in self.values:
1045 return value
1042 return value
1046 self.error(obj, value)
1043 self.error(obj, value)
1047
1044
1048 def info(self):
1045 def info(self):
1049 """ Returns a description of the trait."""
1046 """ Returns a description of the trait."""
1050 result = 'any of ' + repr(self.values)
1047 result = 'any of ' + repr(self.values)
1051 if self._allow_none:
1048 if self._allow_none:
1052 return result + ' or None'
1049 return result + ' or None'
1053 return result
1050 return result
1054
1051
1055 class CaselessStrEnum(Enum):
1052 class CaselessStrEnum(Enum):
1056 """An enum of strings that are caseless in validate."""
1053 """An enum of strings that are caseless in validate."""
1057
1054
1058 def validate(self, obj, value):
1055 def validate(self, obj, value):
1059 if value is None:
1056 if value is None:
1060 if self._allow_none:
1057 if self._allow_none:
1061 return value
1058 return value
1062
1059
1063 if not isinstance(value, str):
1060 if not isinstance(value, str):
1064 self.error(obj, value)
1061 self.error(obj, value)
1065
1062
1066 for v in self.values:
1063 for v in self.values:
1067 if v.lower() == value.lower():
1064 if v.lower() == value.lower():
1068 return v
1065 return v
1069 self.error(obj, value)
1066 self.error(obj, value)
1070
1067
1071 class Container(Instance):
1068 class Container(Instance):
1072 """An instance of a container (list, set, etc.)
1069 """An instance of a container (list, set, etc.)
1073
1070
1074 To be subclassed by overriding klass.
1071 To be subclassed by overriding klass.
1075 """
1072 """
1076 klass = None
1073 klass = None
1077 _valid_defaults = SequenceTypes
1074 _valid_defaults = SequenceTypes
1078 _trait = None
1075 _trait = None
1079
1076
1080 def __init__(self, trait=None, default_value=None, allow_none=True,
1077 def __init__(self, trait=None, default_value=None, allow_none=True,
1081 **metadata):
1078 **metadata):
1082 """Create a container trait type from a list, set, or tuple.
1079 """Create a container trait type from a list, set, or tuple.
1083
1080
1084 The default value is created by doing ``List(default_value)``,
1081 The default value is created by doing ``List(default_value)``,
1085 which creates a copy of the ``default_value``.
1082 which creates a copy of the ``default_value``.
1086
1083
1087 ``trait`` can be specified, which restricts the type of elements
1084 ``trait`` can be specified, which restricts the type of elements
1088 in the container to that TraitType.
1085 in the container to that TraitType.
1089
1086
1090 If only one arg is given and it is not a Trait, it is taken as
1087 If only one arg is given and it is not a Trait, it is taken as
1091 ``default_value``:
1088 ``default_value``:
1092
1089
1093 ``c = List([1,2,3])``
1090 ``c = List([1,2,3])``
1094
1091
1095 Parameters
1092 Parameters
1096 ----------
1093 ----------
1097
1094
1098 trait : TraitType [ optional ]
1095 trait : TraitType [ optional ]
1099 the type for restricting the contents of the Container. If unspecified,
1096 the type for restricting the contents of the Container. If unspecified,
1100 types are not checked.
1097 types are not checked.
1101
1098
1102 default_value : SequenceType [ optional ]
1099 default_value : SequenceType [ optional ]
1103 The default value for the Trait. Must be list/tuple/set, and
1100 The default value for the Trait. Must be list/tuple/set, and
1104 will be cast to the container type.
1101 will be cast to the container type.
1105
1102
1106 allow_none : Bool [ default True ]
1103 allow_none : Bool [ default True ]
1107 Whether to allow the value to be None
1104 Whether to allow the value to be None
1108
1105
1109 **metadata : any
1106 **metadata : any
1110 further keys for extensions to the Trait (e.g. config)
1107 further keys for extensions to the Trait (e.g. config)
1111
1108
1112 """
1109 """
1113 istrait = lambda t: isinstance(t, type) and issubclass(t, TraitType)
1110 istrait = lambda t: isinstance(t, type) and issubclass(t, TraitType)
1114
1111
1115 # allow List([values]):
1112 # allow List([values]):
1116 if default_value is None and not istrait(trait):
1113 if default_value is None and not istrait(trait):
1117 default_value = trait
1114 default_value = trait
1118 trait = None
1115 trait = None
1119
1116
1120 if default_value is None:
1117 if default_value is None:
1121 args = ()
1118 args = ()
1122 elif isinstance(default_value, self._valid_defaults):
1119 elif isinstance(default_value, self._valid_defaults):
1123 args = (default_value,)
1120 args = (default_value,)
1124 else:
1121 else:
1125 raise TypeError('default value of %s was %s' %(self.__class__.__name__, default_value))
1122 raise TypeError('default value of %s was %s' %(self.__class__.__name__, default_value))
1126
1123
1127 if istrait(trait):
1124 if istrait(trait):
1128 self._trait = trait()
1125 self._trait = trait()
1129 self._trait.name = 'element'
1126 self._trait.name = 'element'
1130 elif trait is not None:
1127 elif trait is not None:
1131 raise TypeError("`trait` must be a Trait or None, got %s"%repr_type(trait))
1128 raise TypeError("`trait` must be a Trait or None, got %s"%repr_type(trait))
1132
1129
1133 super(Container,self).__init__(klass=self.klass, args=args,
1130 super(Container,self).__init__(klass=self.klass, args=args,
1134 allow_none=allow_none, **metadata)
1131 allow_none=allow_none, **metadata)
1135
1132
1136 def element_error(self, obj, element, validator):
1133 def element_error(self, obj, element, validator):
1137 e = "Element of the '%s' trait of %s instance must be %s, but a value of %s was specified." \
1134 e = "Element of the '%s' trait of %s instance must be %s, but a value of %s was specified." \
1138 % (self.name, class_of(obj), validator.info(), repr_type(element))
1135 % (self.name, class_of(obj), validator.info(), repr_type(element))
1139 raise TraitError(e)
1136 raise TraitError(e)
1140
1137
1141 def validate(self, obj, value):
1138 def validate(self, obj, value):
1142 value = super(Container, self).validate(obj, value)
1139 value = super(Container, self).validate(obj, value)
1143 if value is None:
1140 if value is None:
1144 return value
1141 return value
1145
1142
1146 value = self.validate_elements(obj, value)
1143 value = self.validate_elements(obj, value)
1147
1144
1148 return value
1145 return value
1149
1146
1150 def validate_elements(self, obj, value):
1147 def validate_elements(self, obj, value):
1151 validated = []
1148 validated = []
1152 if self._trait is None or isinstance(self._trait, Any):
1149 if self._trait is None or isinstance(self._trait, Any):
1153 return value
1150 return value
1154 for v in value:
1151 for v in value:
1155 try:
1152 try:
1156 v = self._trait.validate(obj, v)
1153 v = self._trait.validate(obj, v)
1157 except TraitError:
1154 except TraitError:
1158 self.element_error(obj, v, self._trait)
1155 self.element_error(obj, v, self._trait)
1159 else:
1156 else:
1160 validated.append(v)
1157 validated.append(v)
1161 return self.klass(validated)
1158 return self.klass(validated)
1162
1159
1163
1160
1164 class List(Container):
1161 class List(Container):
1165 """An instance of a Python list."""
1162 """An instance of a Python list."""
1166 klass = list
1163 klass = list
1167
1164
1168 def __init__(self, trait=None, default_value=None, minlen=0, maxlen=sys.maxint,
1165 def __init__(self, trait=None, default_value=None, minlen=0, maxlen=sys.maxint,
1169 allow_none=True, **metadata):
1166 allow_none=True, **metadata):
1170 """Create a List trait type from a list, set, or tuple.
1167 """Create a List trait type from a list, set, or tuple.
1171
1168
1172 The default value is created by doing ``List(default_value)``,
1169 The default value is created by doing ``List(default_value)``,
1173 which creates a copy of the ``default_value``.
1170 which creates a copy of the ``default_value``.
1174
1171
1175 ``trait`` can be specified, which restricts the type of elements
1172 ``trait`` can be specified, which restricts the type of elements
1176 in the container to that TraitType.
1173 in the container to that TraitType.
1177
1174
1178 If only one arg is given and it is not a Trait, it is taken as
1175 If only one arg is given and it is not a Trait, it is taken as
1179 ``default_value``:
1176 ``default_value``:
1180
1177
1181 ``c = List([1,2,3])``
1178 ``c = List([1,2,3])``
1182
1179
1183 Parameters
1180 Parameters
1184 ----------
1181 ----------
1185
1182
1186 trait : TraitType [ optional ]
1183 trait : TraitType [ optional ]
1187 the type for restricting the contents of the Container. If unspecified,
1184 the type for restricting the contents of the Container. If unspecified,
1188 types are not checked.
1185 types are not checked.
1189
1186
1190 default_value : SequenceType [ optional ]
1187 default_value : SequenceType [ optional ]
1191 The default value for the Trait. Must be list/tuple/set, and
1188 The default value for the Trait. Must be list/tuple/set, and
1192 will be cast to the container type.
1189 will be cast to the container type.
1193
1190
1194 minlen : Int [ default 0 ]
1191 minlen : Int [ default 0 ]
1195 The minimum length of the input list
1192 The minimum length of the input list
1196
1193
1197 maxlen : Int [ default sys.maxint ]
1194 maxlen : Int [ default sys.maxint ]
1198 The maximum length of the input list
1195 The maximum length of the input list
1199
1196
1200 allow_none : Bool [ default True ]
1197 allow_none : Bool [ default True ]
1201 Whether to allow the value to be None
1198 Whether to allow the value to be None
1202
1199
1203 **metadata : any
1200 **metadata : any
1204 further keys for extensions to the Trait (e.g. config)
1201 further keys for extensions to the Trait (e.g. config)
1205
1202
1206 """
1203 """
1207 self._minlen = minlen
1204 self._minlen = minlen
1208 self._maxlen = maxlen
1205 self._maxlen = maxlen
1209 super(List, self).__init__(trait=trait, default_value=default_value,
1206 super(List, self).__init__(trait=trait, default_value=default_value,
1210 allow_none=allow_none, **metadata)
1207 allow_none=allow_none, **metadata)
1211
1208
1212 def length_error(self, obj, value):
1209 def length_error(self, obj, value):
1213 e = "The '%s' trait of %s instance must be of length %i <= L <= %i, but a value of %s was specified." \
1210 e = "The '%s' trait of %s instance must be of length %i <= L <= %i, but a value of %s was specified." \
1214 % (self.name, class_of(obj), self._minlen, self._maxlen, value)
1211 % (self.name, class_of(obj), self._minlen, self._maxlen, value)
1215 raise TraitError(e)
1212 raise TraitError(e)
1216
1213
1217 def validate_elements(self, obj, value):
1214 def validate_elements(self, obj, value):
1218 length = len(value)
1215 length = len(value)
1219 if length < self._minlen or length > self._maxlen:
1216 if length < self._minlen or length > self._maxlen:
1220 self.length_error(obj, value)
1217 self.length_error(obj, value)
1221
1218
1222 return super(List, self).validate_elements(obj, value)
1219 return super(List, self).validate_elements(obj, value)
1223
1220
1224
1221
1225 class Set(Container):
1222 class Set(Container):
1226 """An instance of a Python set."""
1223 """An instance of a Python set."""
1227 klass = set
1224 klass = set
1228
1225
1229 class Tuple(Container):
1226 class Tuple(Container):
1230 """An instance of a Python tuple."""
1227 """An instance of a Python tuple."""
1231 klass = tuple
1228 klass = tuple
1232
1229
1233 def __init__(self, *traits, **metadata):
1230 def __init__(self, *traits, **metadata):
1234 """Tuple(*traits, default_value=None, allow_none=True, **medatata)
1231 """Tuple(*traits, default_value=None, allow_none=True, **medatata)
1235
1232
1236 Create a tuple from a list, set, or tuple.
1233 Create a tuple from a list, set, or tuple.
1237
1234
1238 Create a fixed-type tuple with Traits:
1235 Create a fixed-type tuple with Traits:
1239
1236
1240 ``t = Tuple(Int, Str, CStr)``
1237 ``t = Tuple(Int, Str, CStr)``
1241
1238
1242 would be length 3, with Int,Str,CStr for each element.
1239 would be length 3, with Int,Str,CStr for each element.
1243
1240
1244 If only one arg is given and it is not a Trait, it is taken as
1241 If only one arg is given and it is not a Trait, it is taken as
1245 default_value:
1242 default_value:
1246
1243
1247 ``t = Tuple((1,2,3))``
1244 ``t = Tuple((1,2,3))``
1248
1245
1249 Otherwise, ``default_value`` *must* be specified by keyword.
1246 Otherwise, ``default_value`` *must* be specified by keyword.
1250
1247
1251 Parameters
1248 Parameters
1252 ----------
1249 ----------
1253
1250
1254 *traits : TraitTypes [ optional ]
1251 *traits : TraitTypes [ optional ]
1255 the tsype for restricting the contents of the Tuple. If unspecified,
1252 the tsype for restricting the contents of the Tuple. If unspecified,
1256 types are not checked. If specified, then each positional argument
1253 types are not checked. If specified, then each positional argument
1257 corresponds to an element of the tuple. Tuples defined with traits
1254 corresponds to an element of the tuple. Tuples defined with traits
1258 are of fixed length.
1255 are of fixed length.
1259
1256
1260 default_value : SequenceType [ optional ]
1257 default_value : SequenceType [ optional ]
1261 The default value for the Tuple. Must be list/tuple/set, and
1258 The default value for the Tuple. Must be list/tuple/set, and
1262 will be cast to a tuple. If `traits` are specified, the
1259 will be cast to a tuple. If `traits` are specified, the
1263 `default_value` must conform to the shape and type they specify.
1260 `default_value` must conform to the shape and type they specify.
1264
1261
1265 allow_none : Bool [ default True ]
1262 allow_none : Bool [ default True ]
1266 Whether to allow the value to be None
1263 Whether to allow the value to be None
1267
1264
1268 **metadata : any
1265 **metadata : any
1269 further keys for extensions to the Trait (e.g. config)
1266 further keys for extensions to the Trait (e.g. config)
1270
1267
1271 """
1268 """
1272 default_value = metadata.pop('default_value', None)
1269 default_value = metadata.pop('default_value', None)
1273 allow_none = metadata.pop('allow_none', True)
1270 allow_none = metadata.pop('allow_none', True)
1274
1271
1275 istrait = lambda t: isinstance(t, type) and issubclass(t, TraitType)
1272 istrait = lambda t: isinstance(t, type) and issubclass(t, TraitType)
1276
1273
1277 # allow Tuple((values,)):
1274 # allow Tuple((values,)):
1278 if len(traits) == 1 and default_value is None and not istrait(traits[0]):
1275 if len(traits) == 1 and default_value is None and not istrait(traits[0]):
1279 default_value = traits[0]
1276 default_value = traits[0]
1280 traits = ()
1277 traits = ()
1281
1278
1282 if default_value is None:
1279 if default_value is None:
1283 args = ()
1280 args = ()
1284 elif isinstance(default_value, self._valid_defaults):
1281 elif isinstance(default_value, self._valid_defaults):
1285 args = (default_value,)
1282 args = (default_value,)
1286 else:
1283 else:
1287 raise TypeError('default value of %s was %s' %(self.__class__.__name__, default_value))
1284 raise TypeError('default value of %s was %s' %(self.__class__.__name__, default_value))
1288
1285
1289 self._traits = []
1286 self._traits = []
1290 for trait in traits:
1287 for trait in traits:
1291 t = trait()
1288 t = trait()
1292 t.name = 'element'
1289 t.name = 'element'
1293 self._traits.append(t)
1290 self._traits.append(t)
1294
1291
1295 if self._traits and default_value is None:
1292 if self._traits and default_value is None:
1296 # don't allow default to be an empty container if length is specified
1293 # don't allow default to be an empty container if length is specified
1297 args = None
1294 args = None
1298 super(Container,self).__init__(klass=self.klass, args=args,
1295 super(Container,self).__init__(klass=self.klass, args=args,
1299 allow_none=allow_none, **metadata)
1296 allow_none=allow_none, **metadata)
1300
1297
1301 def validate_elements(self, obj, value):
1298 def validate_elements(self, obj, value):
1302 if not self._traits:
1299 if not self._traits:
1303 # nothing to validate
1300 # nothing to validate
1304 return value
1301 return value
1305 if len(value) != len(self._traits):
1302 if len(value) != len(self._traits):
1306 e = "The '%s' trait of %s instance requires %i elements, but a value of %s was specified." \
1303 e = "The '%s' trait of %s instance requires %i elements, but a value of %s was specified." \
1307 % (self.name, class_of(obj), len(self._traits), repr_type(value))
1304 % (self.name, class_of(obj), len(self._traits), repr_type(value))
1308 raise TraitError(e)
1305 raise TraitError(e)
1309
1306
1310 validated = []
1307 validated = []
1311 for t,v in zip(self._traits, value):
1308 for t,v in zip(self._traits, value):
1312 try:
1309 try:
1313 v = t.validate(obj, v)
1310 v = t.validate(obj, v)
1314 except TraitError:
1311 except TraitError:
1315 self.element_error(obj, v, t)
1312 self.element_error(obj, v, t)
1316 else:
1313 else:
1317 validated.append(v)
1314 validated.append(v)
1318 return tuple(validated)
1315 return tuple(validated)
1319
1316
1320
1317
1321 class Dict(Instance):
1318 class Dict(Instance):
1322 """An instance of a Python dict."""
1319 """An instance of a Python dict."""
1323
1320
1324 def __init__(self, default_value=None, allow_none=True, **metadata):
1321 def __init__(self, default_value=None, allow_none=True, **metadata):
1325 """Create a dict trait type from a dict.
1322 """Create a dict trait type from a dict.
1326
1323
1327 The default value is created by doing ``dict(default_value)``,
1324 The default value is created by doing ``dict(default_value)``,
1328 which creates a copy of the ``default_value``.
1325 which creates a copy of the ``default_value``.
1329 """
1326 """
1330 if default_value is None:
1327 if default_value is None:
1331 args = ((),)
1328 args = ((),)
1332 elif isinstance(default_value, dict):
1329 elif isinstance(default_value, dict):
1333 args = (default_value,)
1330 args = (default_value,)
1334 elif isinstance(default_value, SequenceTypes):
1331 elif isinstance(default_value, SequenceTypes):
1335 args = (default_value,)
1332 args = (default_value,)
1336 else:
1333 else:
1337 raise TypeError('default value of Dict was %s' % default_value)
1334 raise TypeError('default value of Dict was %s' % default_value)
1338
1335
1339 super(Dict,self).__init__(klass=dict, args=args,
1336 super(Dict,self).__init__(klass=dict, args=args,
1340 allow_none=allow_none, **metadata)
1337 allow_none=allow_none, **metadata)
1341
1338
1342 class TCPAddress(TraitType):
1339 class TCPAddress(TraitType):
1343 """A trait for an (ip, port) tuple.
1340 """A trait for an (ip, port) tuple.
1344
1341
1345 This allows for both IPv4 IP addresses as well as hostnames.
1342 This allows for both IPv4 IP addresses as well as hostnames.
1346 """
1343 """
1347
1344
1348 default_value = ('127.0.0.1', 0)
1345 default_value = ('127.0.0.1', 0)
1349 info_text = 'an (ip, port) tuple'
1346 info_text = 'an (ip, port) tuple'
1350
1347
1351 def validate(self, obj, value):
1348 def validate(self, obj, value):
1352 if isinstance(value, tuple):
1349 if isinstance(value, tuple):
1353 if len(value) == 2:
1350 if len(value) == 2:
1354 if isinstance(value[0], basestring) and isinstance(value[1], int):
1351 if isinstance(value[0], basestring) and isinstance(value[1], int):
1355 port = value[1]
1352 port = value[1]
1356 if port >= 0 and port <= 65535:
1353 if port >= 0 and port <= 65535:
1357 return value
1354 return value
1358 self.error(obj, value)
1355 self.error(obj, value)
General Comments 0
You need to be logged in to leave comments. Login now