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