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