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