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