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