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