##// END OF EJS Templates
Fixed Python 2.6 warning with traitlets object.__new__....
Brian Granger -
Show More
@@ -1,977 +1,983 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3 """
3 """
4 A lightweight Traits like module.
4 A lightweight Traits like module.
5
5
6 This is designed to provide a lightweight, simple, pure Python version of
6 This is designed to provide a lightweight, simple, pure Python version of
7 many of the capabilities of enthought.traits. This includes:
7 many of the capabilities of enthought.traits. This includes:
8
8
9 * Validation
9 * Validation
10 * Type specification with defaults
10 * Type specification with defaults
11 * Static and dynamic notification
11 * Static and dynamic notification
12 * Basic predefined types
12 * Basic predefined types
13 * An API that is similar to enthought.traits
13 * An API that is similar to enthought.traits
14
14
15 We don't support:
15 We don't support:
16
16
17 * Delegation
17 * Delegation
18 * Automatic GUI generation
18 * Automatic GUI generation
19 * A full set of trait types. Most importantly, we don't provide container
19 * A full set of trait types. Most importantly, we don't provide container
20 traitlets (list, dict, tuple) that can trigger notifications if their
20 traitlets (list, dict, tuple) that can trigger notifications if their
21 contents change.
21 contents change.
22 * API compatibility with enthought.traits
22 * API compatibility with enthought.traits
23
23
24 There are also some important difference in our design:
24 There are also some important difference in our design:
25
25
26 * enthought.traits does not validate default values. We do.
26 * enthought.traits does not validate default values. We do.
27
27
28 We choose to create this module because we need these capabilities, but
28 We choose to create this module because we need these capabilities, but
29 we need them to be pure Python so they work in all Python implementations,
29 we need them to be pure Python so they work in all Python implementations,
30 including Jython and IronPython.
30 including Jython and IronPython.
31
31
32 Authors:
32 Authors:
33
33
34 * Brian Granger
34 * Brian Granger
35 * Enthought, Inc. Some of the code in this file comes from enthought.traits
35 * Enthought, Inc. Some of the code in this file comes from enthought.traits
36 and is licensed under the BSD license. Also, many of the ideas also come
36 and is licensed under the BSD license. Also, many of the ideas also come
37 from enthought.traits even though our implementation is very different.
37 from enthought.traits even though our implementation is very different.
38 """
38 """
39
39
40 #-----------------------------------------------------------------------------
40 #-----------------------------------------------------------------------------
41 # Copyright (C) 2008-2009 The IPython Development Team
41 # Copyright (C) 2008-2009 The IPython Development Team
42 #
42 #
43 # Distributed under the terms of the BSD License. The full license is in
43 # Distributed under the terms of the BSD License. The full license is in
44 # the file COPYING, distributed as part of this software.
44 # the file COPYING, distributed as part of this software.
45 #-----------------------------------------------------------------------------
45 #-----------------------------------------------------------------------------
46
46
47 #-----------------------------------------------------------------------------
47 #-----------------------------------------------------------------------------
48 # Imports
48 # Imports
49 #-----------------------------------------------------------------------------
49 #-----------------------------------------------------------------------------
50
50
51
51
52 import inspect
52 import inspect
53 import sys
53 import sys
54 import types
54 import types
55 from types import (
55 from types import (
56 InstanceType, ClassType, FunctionType,
56 InstanceType, ClassType, FunctionType,
57 ListType, TupleType
57 ListType, TupleType
58 )
58 )
59
59
60 from IPython.utils.importstring import import_item
60 from IPython.utils.importstring import import_item
61
61
62 ClassTypes = (ClassType, type)
62 ClassTypes = (ClassType, type)
63
63
64 SequenceTypes = (ListType, TupleType)
64 SequenceTypes = (ListType, TupleType)
65
65
66 #-----------------------------------------------------------------------------
66 #-----------------------------------------------------------------------------
67 # Basic classes
67 # Basic classes
68 #-----------------------------------------------------------------------------
68 #-----------------------------------------------------------------------------
69
69
70
70
71 class NoDefaultSpecified ( object ): pass
71 class NoDefaultSpecified ( object ): pass
72 NoDefaultSpecified = NoDefaultSpecified()
72 NoDefaultSpecified = NoDefaultSpecified()
73
73
74
74
75 class Undefined ( object ): pass
75 class Undefined ( object ): pass
76 Undefined = Undefined()
76 Undefined = Undefined()
77
77
78
78
79 class TraitletError(Exception):
79 class TraitletError(Exception):
80 pass
80 pass
81
81
82
82
83 #-----------------------------------------------------------------------------
83 #-----------------------------------------------------------------------------
84 # Utilities
84 # Utilities
85 #-----------------------------------------------------------------------------
85 #-----------------------------------------------------------------------------
86
86
87
87
88 def class_of ( object ):
88 def class_of ( object ):
89 """ Returns a string containing the class name of an object with the
89 """ Returns a string containing the class name of an object with the
90 correct indefinite article ('a' or 'an') preceding it (e.g., 'an Image',
90 correct indefinite article ('a' or 'an') preceding it (e.g., 'an Image',
91 'a PlotValue').
91 'a PlotValue').
92 """
92 """
93 if isinstance( object, basestring ):
93 if isinstance( object, basestring ):
94 return add_article( object )
94 return add_article( object )
95
95
96 return add_article( object.__class__.__name__ )
96 return add_article( object.__class__.__name__ )
97
97
98
98
99 def add_article ( name ):
99 def add_article ( name ):
100 """ Returns a string containing the correct indefinite article ('a' or 'an')
100 """ Returns a string containing the correct indefinite article ('a' or 'an')
101 prefixed to the specified string.
101 prefixed to the specified string.
102 """
102 """
103 if name[:1].lower() in 'aeiou':
103 if name[:1].lower() in 'aeiou':
104 return 'an ' + name
104 return 'an ' + name
105
105
106 return 'a ' + name
106 return 'a ' + name
107
107
108
108
109 def repr_type(obj):
109 def repr_type(obj):
110 """ Return a string representation of a value and its type for readable
110 """ Return a string representation of a value and its type for readable
111 error messages.
111 error messages.
112 """
112 """
113 the_type = type(obj)
113 the_type = type(obj)
114 if the_type is InstanceType:
114 if the_type is InstanceType:
115 # Old-style class.
115 # Old-style class.
116 the_type = obj.__class__
116 the_type = obj.__class__
117 msg = '%r %r' % (obj, the_type)
117 msg = '%r %r' % (obj, the_type)
118 return msg
118 return msg
119
119
120
120
121 def parse_notifier_name(name):
121 def parse_notifier_name(name):
122 """Convert the name argument to a list of names.
122 """Convert the name argument to a list of names.
123
123
124 Examples
124 Examples
125 --------
125 --------
126
126
127 >>> parse_notifier_name('a')
127 >>> parse_notifier_name('a')
128 ['a']
128 ['a']
129 >>> parse_notifier_name(['a','b'])
129 >>> parse_notifier_name(['a','b'])
130 ['a', 'b']
130 ['a', 'b']
131 >>> parse_notifier_name(None)
131 >>> parse_notifier_name(None)
132 ['anytraitlet']
132 ['anytraitlet']
133 """
133 """
134 if isinstance(name, str):
134 if isinstance(name, str):
135 return [name]
135 return [name]
136 elif name is None:
136 elif name is None:
137 return ['anytraitlet']
137 return ['anytraitlet']
138 elif isinstance(name, (list, tuple)):
138 elif isinstance(name, (list, tuple)):
139 for n in name:
139 for n in name:
140 assert isinstance(n, str), "names must be strings"
140 assert isinstance(n, str), "names must be strings"
141 return name
141 return name
142
142
143
143
144 class _SimpleTest:
144 class _SimpleTest:
145 def __init__ ( self, value ): self.value = value
145 def __init__ ( self, value ): self.value = value
146 def __call__ ( self, test ):
146 def __call__ ( self, test ):
147 return test == self.value
147 return test == self.value
148 def __repr__(self):
148 def __repr__(self):
149 return "<SimpleTest(%r)" % self.value
149 return "<SimpleTest(%r)" % self.value
150 def __str__(self):
150 def __str__(self):
151 return self.__repr__()
151 return self.__repr__()
152
152
153
153
154 #-----------------------------------------------------------------------------
154 #-----------------------------------------------------------------------------
155 # Base TraitletType for all traitlets
155 # Base TraitletType for all traitlets
156 #-----------------------------------------------------------------------------
156 #-----------------------------------------------------------------------------
157
157
158
158
159 class TraitletType(object):
159 class TraitletType(object):
160 """A base class for all traitlet descriptors.
160 """A base class for all traitlet descriptors.
161
161
162 Notes
162 Notes
163 -----
163 -----
164 Our implementation of traitlets is based on Python's descriptor
164 Our implementation of traitlets is based on Python's descriptor
165 prototol. This class is the base class for all such descriptors. The
165 prototol. This class is the base class for all such descriptors. The
166 only magic we use is a custom metaclass for the main :class:`HasTraitlets`
166 only magic we use is a custom metaclass for the main :class:`HasTraitlets`
167 class that does the following:
167 class that does the following:
168
168
169 1. Sets the :attr:`name` attribute of every :class:`TraitletType`
169 1. Sets the :attr:`name` attribute of every :class:`TraitletType`
170 instance in the class dict to the name of the attribute.
170 instance in the class dict to the name of the attribute.
171 2. Sets the :attr:`this_class` attribute of every :class:`TraitletType`
171 2. Sets the :attr:`this_class` attribute of every :class:`TraitletType`
172 instance in the class dict to the *class* that declared the traitlet.
172 instance in the class dict to the *class* that declared the traitlet.
173 This is used by the :class:`This` traitlet to allow subclasses to
173 This is used by the :class:`This` traitlet to allow subclasses to
174 accept superclasses for :class:`This` values.
174 accept superclasses for :class:`This` values.
175 """
175 """
176
176
177
177
178 metadata = {}
178 metadata = {}
179 default_value = Undefined
179 default_value = Undefined
180 info_text = 'any value'
180 info_text = 'any value'
181
181
182 def __init__(self, default_value=NoDefaultSpecified, **metadata):
182 def __init__(self, default_value=NoDefaultSpecified, **metadata):
183 """Create a TraitletType.
183 """Create a TraitletType.
184 """
184 """
185 if default_value is not NoDefaultSpecified:
185 if default_value is not NoDefaultSpecified:
186 self.default_value = default_value
186 self.default_value = default_value
187
187
188 if len(metadata) > 0:
188 if len(metadata) > 0:
189 if len(self.metadata) > 0:
189 if len(self.metadata) > 0:
190 self._metadata = self.metadata.copy()
190 self._metadata = self.metadata.copy()
191 self._metadata.update(metadata)
191 self._metadata.update(metadata)
192 else:
192 else:
193 self._metadata = metadata
193 self._metadata = metadata
194 else:
194 else:
195 self._metadata = self.metadata
195 self._metadata = self.metadata
196
196
197 self.init()
197 self.init()
198
198
199 def init(self):
199 def init(self):
200 pass
200 pass
201
201
202 def get_default_value(self):
202 def get_default_value(self):
203 """Create a new instance of the default value."""
203 """Create a new instance of the default value."""
204 dv = self.default_value
204 dv = self.default_value
205 return dv
205 return dv
206
206
207 def instance_init(self, obj):
207 def instance_init(self, obj):
208 """This is called by :meth:`HasTraitlets.__new__` to finish init'ing.
208 """This is called by :meth:`HasTraitlets.__new__` to finish init'ing.
209
209
210 Some stages of initialization must be delayed until the parent
210 Some stages of initialization must be delayed until the parent
211 :class:`HasTraitlets` instance has been created. This method is
211 :class:`HasTraitlets` instance has been created. This method is
212 called in :meth:`HasTraitlets.__new__` after the instance has been
212 called in :meth:`HasTraitlets.__new__` after the instance has been
213 created.
213 created.
214
214
215 This method trigger the creation and validation of default values
215 This method trigger the creation and validation of default values
216 and also things like the resolution of str given class names in
216 and also things like the resolution of str given class names in
217 :class:`Type` and :class`Instance`.
217 :class:`Type` and :class`Instance`.
218
218
219 Parameters
219 Parameters
220 ----------
220 ----------
221 obj : :class:`HasTraitlets` instance
221 obj : :class:`HasTraitlets` instance
222 The parent :class:`HasTraitlets` instance that has just been
222 The parent :class:`HasTraitlets` instance that has just been
223 created.
223 created.
224 """
224 """
225 self.set_default_value(obj)
225 self.set_default_value(obj)
226
226
227 def set_default_value(self, obj):
227 def set_default_value(self, obj):
228 """Set the default value on a per instance basis.
228 """Set the default value on a per instance basis.
229
229
230 This method is called by :meth:`instance_init` to create and
230 This method is called by :meth:`instance_init` to create and
231 validate the default value. The creation and validation of
231 validate the default value. The creation and validation of
232 default values must be delayed until the parent :class:`HasTraitlets`
232 default values must be delayed until the parent :class:`HasTraitlets`
233 class has been instantiated.
233 class has been instantiated.
234 """
234 """
235 dv = self.get_default_value()
235 dv = self.get_default_value()
236 newdv = self._validate(obj, dv)
236 newdv = self._validate(obj, dv)
237 obj._traitlet_values[self.name] = newdv
237 obj._traitlet_values[self.name] = newdv
238
238
239 def __get__(self, obj, cls=None):
239 def __get__(self, obj, cls=None):
240 """Get the value of the traitlet by self.name for the instance.
240 """Get the value of the traitlet by self.name for the instance.
241
241
242 Default values are instantiated when :meth:`HasTraitlets.__new__`
242 Default values are instantiated when :meth:`HasTraitlets.__new__`
243 is called. Thus by the time this method gets called either the
243 is called. Thus by the time this method gets called either the
244 default value or a user defined value (they called :meth:`__set__`)
244 default value or a user defined value (they called :meth:`__set__`)
245 is in the :class:`HasTraitlets` instance.
245 is in the :class:`HasTraitlets` instance.
246 """
246 """
247 if obj is None:
247 if obj is None:
248 return self
248 return self
249 else:
249 else:
250 try:
250 try:
251 value = obj._traitlet_values[self.name]
251 value = obj._traitlet_values[self.name]
252 except:
252 except:
253 # HasTraitlets should call set_default_value to populate
253 # HasTraitlets should call set_default_value to populate
254 # this. So this should never be reached.
254 # this. So this should never be reached.
255 raise TraitletError('Unexpected error in TraitletType: '
255 raise TraitletError('Unexpected error in TraitletType: '
256 'default value not set properly')
256 'default value not set properly')
257 else:
257 else:
258 return value
258 return value
259
259
260 def __set__(self, obj, value):
260 def __set__(self, obj, value):
261 new_value = self._validate(obj, value)
261 new_value = self._validate(obj, value)
262 old_value = self.__get__(obj)
262 old_value = self.__get__(obj)
263 if old_value != new_value:
263 if old_value != new_value:
264 obj._traitlet_values[self.name] = new_value
264 obj._traitlet_values[self.name] = new_value
265 obj._notify_traitlet(self.name, old_value, new_value)
265 obj._notify_traitlet(self.name, old_value, new_value)
266
266
267 def _validate(self, obj, value):
267 def _validate(self, obj, value):
268 if hasattr(self, 'validate'):
268 if hasattr(self, 'validate'):
269 return self.validate(obj, value)
269 return self.validate(obj, value)
270 elif hasattr(self, 'is_valid_for'):
270 elif hasattr(self, 'is_valid_for'):
271 valid = self.is_valid_for(value)
271 valid = self.is_valid_for(value)
272 if valid:
272 if valid:
273 return value
273 return value
274 else:
274 else:
275 raise TraitletError('invalid value for type: %r' % value)
275 raise TraitletError('invalid value for type: %r' % value)
276 elif hasattr(self, 'value_for'):
276 elif hasattr(self, 'value_for'):
277 return self.value_for(value)
277 return self.value_for(value)
278 else:
278 else:
279 return value
279 return value
280
280
281 def info(self):
281 def info(self):
282 return self.info_text
282 return self.info_text
283
283
284 def error(self, obj, value):
284 def error(self, obj, value):
285 if obj is not None:
285 if obj is not None:
286 e = "The '%s' traitlet of %s instance must be %s, but a value of %s was specified." \
286 e = "The '%s' traitlet of %s instance must be %s, but a value of %s was specified." \
287 % (self.name, class_of(obj),
287 % (self.name, class_of(obj),
288 self.info(), repr_type(value))
288 self.info(), repr_type(value))
289 else:
289 else:
290 e = "The '%s' traitlet must be %s, but a value of %r was specified." \
290 e = "The '%s' traitlet must be %s, but a value of %r was specified." \
291 % (self.name, self.info(), repr_type(value))
291 % (self.name, self.info(), repr_type(value))
292 raise TraitletError(e)
292 raise TraitletError(e)
293
293
294 def get_metadata(self, key):
294 def get_metadata(self, key):
295 return getattr(self, '_metadata', {}).get(key, None)
295 return getattr(self, '_metadata', {}).get(key, None)
296
296
297 def set_metadata(self, key, value):
297 def set_metadata(self, key, value):
298 getattr(self, '_metadata', {})[key] = value
298 getattr(self, '_metadata', {})[key] = value
299
299
300
300
301 #-----------------------------------------------------------------------------
301 #-----------------------------------------------------------------------------
302 # The HasTraitlets implementation
302 # The HasTraitlets implementation
303 #-----------------------------------------------------------------------------
303 #-----------------------------------------------------------------------------
304
304
305
305
306 class MetaHasTraitlets(type):
306 class MetaHasTraitlets(type):
307 """A metaclass for HasTraitlets.
307 """A metaclass for HasTraitlets.
308
308
309 This metaclass makes sure that any TraitletType class attributes are
309 This metaclass makes sure that any TraitletType class attributes are
310 instantiated and sets their name attribute.
310 instantiated and sets their name attribute.
311 """
311 """
312
312
313 def __new__(mcls, name, bases, classdict):
313 def __new__(mcls, name, bases, classdict):
314 """Create the HasTraitlets class.
314 """Create the HasTraitlets class.
315
315
316 This instantiates all TraitletTypes in the class dict and sets their
316 This instantiates all TraitletTypes in the class dict and sets their
317 :attr:`name` attribute.
317 :attr:`name` attribute.
318 """
318 """
319 for k,v in classdict.iteritems():
319 for k,v in classdict.iteritems():
320 if isinstance(v, TraitletType):
320 if isinstance(v, TraitletType):
321 v.name = k
321 v.name = k
322 elif inspect.isclass(v):
322 elif inspect.isclass(v):
323 if issubclass(v, TraitletType):
323 if issubclass(v, TraitletType):
324 vinst = v()
324 vinst = v()
325 vinst.name = k
325 vinst.name = k
326 classdict[k] = vinst
326 classdict[k] = vinst
327 return super(MetaHasTraitlets, mcls).__new__(mcls, name, bases, classdict)
327 return super(MetaHasTraitlets, mcls).__new__(mcls, name, bases, classdict)
328
328
329 def __init__(cls, name, bases, classdict):
329 def __init__(cls, name, bases, classdict):
330 """Finish initializing the HasTraitlets class.
330 """Finish initializing the HasTraitlets class.
331
331
332 This sets the :attr:`this_class` attribute of each TraitletType in the
332 This sets the :attr:`this_class` attribute of each TraitletType in the
333 class dict to the newly created class ``cls``.
333 class dict to the newly created class ``cls``.
334 """
334 """
335 for k, v in classdict.iteritems():
335 for k, v in classdict.iteritems():
336 if isinstance(v, TraitletType):
336 if isinstance(v, TraitletType):
337 v.this_class = cls
337 v.this_class = cls
338 super(MetaHasTraitlets, cls).__init__(name, bases, classdict)
338 super(MetaHasTraitlets, cls).__init__(name, bases, classdict)
339
339
340 class HasTraitlets(object):
340 class HasTraitlets(object):
341
341
342 __metaclass__ = MetaHasTraitlets
342 __metaclass__ = MetaHasTraitlets
343
343
344 def __new__(cls, *args, **kw):
344 def __new__(cls, *args, **kw):
345 inst = super(HasTraitlets, cls).__new__(cls, *args, **kw)
345 # This is needed because in Python 2.6 object.__new__ only accepts
346 # the cls argument.
347 new_meth = super(HasTraitlets, cls).__new__
348 if new_meth is object.__new__:
349 inst = new_meth(cls)
350 else:
351 inst = new_meth(cls, *args, **kw)
346 inst._traitlet_values = {}
352 inst._traitlet_values = {}
347 inst._traitlet_notifiers = {}
353 inst._traitlet_notifiers = {}
348 # Here we tell all the TraitletType instances to set their default
354 # Here we tell all the TraitletType instances to set their default
349 # values on the instance.
355 # values on the instance.
350 for key in dir(cls):
356 for key in dir(cls):
351 value = getattr(cls, key)
357 value = getattr(cls, key)
352 if isinstance(value, TraitletType):
358 if isinstance(value, TraitletType):
353 value.instance_init(inst)
359 value.instance_init(inst)
354 return inst
360 return inst
355
361
356 # def __init__(self):
362 # def __init__(self):
357 # self._traitlet_values = {}
363 # self._traitlet_values = {}
358 # self._traitlet_notifiers = {}
364 # self._traitlet_notifiers = {}
359
365
360 def _notify_traitlet(self, name, old_value, new_value):
366 def _notify_traitlet(self, name, old_value, new_value):
361
367
362 # First dynamic ones
368 # First dynamic ones
363 callables = self._traitlet_notifiers.get(name,[])
369 callables = self._traitlet_notifiers.get(name,[])
364 more_callables = self._traitlet_notifiers.get('anytraitlet',[])
370 more_callables = self._traitlet_notifiers.get('anytraitlet',[])
365 callables.extend(more_callables)
371 callables.extend(more_callables)
366
372
367 # Now static ones
373 # Now static ones
368 try:
374 try:
369 cb = getattr(self, '_%s_changed' % name)
375 cb = getattr(self, '_%s_changed' % name)
370 except:
376 except:
371 pass
377 pass
372 else:
378 else:
373 callables.append(cb)
379 callables.append(cb)
374
380
375 # Call them all now
381 # Call them all now
376 for c in callables:
382 for c in callables:
377 # Traits catches and logs errors here. I allow them to raise
383 # Traits catches and logs errors here. I allow them to raise
378 if callable(c):
384 if callable(c):
379 argspec = inspect.getargspec(c)
385 argspec = inspect.getargspec(c)
380 nargs = len(argspec[0])
386 nargs = len(argspec[0])
381 # Bound methods have an additional 'self' argument
387 # Bound methods have an additional 'self' argument
382 # I don't know how to treat unbound methods, but they
388 # I don't know how to treat unbound methods, but they
383 # can't really be used for callbacks.
389 # can't really be used for callbacks.
384 if isinstance(c, types.MethodType):
390 if isinstance(c, types.MethodType):
385 offset = -1
391 offset = -1
386 else:
392 else:
387 offset = 0
393 offset = 0
388 if nargs + offset == 0:
394 if nargs + offset == 0:
389 c()
395 c()
390 elif nargs + offset == 1:
396 elif nargs + offset == 1:
391 c(name)
397 c(name)
392 elif nargs + offset == 2:
398 elif nargs + offset == 2:
393 c(name, new_value)
399 c(name, new_value)
394 elif nargs + offset == 3:
400 elif nargs + offset == 3:
395 c(name, old_value, new_value)
401 c(name, old_value, new_value)
396 else:
402 else:
397 raise TraitletError('a traitlet changed callback '
403 raise TraitletError('a traitlet changed callback '
398 'must have 0-3 arguments.')
404 'must have 0-3 arguments.')
399 else:
405 else:
400 raise TraitletError('a traitlet changed callback '
406 raise TraitletError('a traitlet changed callback '
401 'must be callable.')
407 'must be callable.')
402
408
403
409
404 def _add_notifiers(self, handler, name):
410 def _add_notifiers(self, handler, name):
405 if not self._traitlet_notifiers.has_key(name):
411 if not self._traitlet_notifiers.has_key(name):
406 nlist = []
412 nlist = []
407 self._traitlet_notifiers[name] = nlist
413 self._traitlet_notifiers[name] = nlist
408 else:
414 else:
409 nlist = self._traitlet_notifiers[name]
415 nlist = self._traitlet_notifiers[name]
410 if handler not in nlist:
416 if handler not in nlist:
411 nlist.append(handler)
417 nlist.append(handler)
412
418
413 def _remove_notifiers(self, handler, name):
419 def _remove_notifiers(self, handler, name):
414 if self._traitlet_notifiers.has_key(name):
420 if self._traitlet_notifiers.has_key(name):
415 nlist = self._traitlet_notifiers[name]
421 nlist = self._traitlet_notifiers[name]
416 try:
422 try:
417 index = nlist.index(handler)
423 index = nlist.index(handler)
418 except ValueError:
424 except ValueError:
419 pass
425 pass
420 else:
426 else:
421 del nlist[index]
427 del nlist[index]
422
428
423 def on_traitlet_change(self, handler, name=None, remove=False):
429 def on_traitlet_change(self, handler, name=None, remove=False):
424 """Setup a handler to be called when a traitlet changes.
430 """Setup a handler to be called when a traitlet changes.
425
431
426 This is used to setup dynamic notifications of traitlet changes.
432 This is used to setup dynamic notifications of traitlet changes.
427
433
428 Static handlers can be created by creating methods on a HasTraitlets
434 Static handlers can be created by creating methods on a HasTraitlets
429 subclass with the naming convention '_[traitletname]_changed'. Thus,
435 subclass with the naming convention '_[traitletname]_changed'. Thus,
430 to create static handler for the traitlet 'a', create the method
436 to create static handler for the traitlet 'a', create the method
431 _a_changed(self, name, old, new) (fewer arguments can be used, see
437 _a_changed(self, name, old, new) (fewer arguments can be used, see
432 below).
438 below).
433
439
434 Parameters
440 Parameters
435 ----------
441 ----------
436 handler : callable
442 handler : callable
437 A callable that is called when a traitlet changes. Its
443 A callable that is called when a traitlet changes. Its
438 signature can be handler(), handler(name), handler(name, new)
444 signature can be handler(), handler(name), handler(name, new)
439 or handler(name, old, new).
445 or handler(name, old, new).
440 name : list, str, None
446 name : list, str, None
441 If None, the handler will apply to all traitlets. If a list
447 If None, the handler will apply to all traitlets. If a list
442 of str, handler will apply to all names in the list. If a
448 of str, handler will apply to all names in the list. If a
443 str, the handler will apply just to that name.
449 str, the handler will apply just to that name.
444 remove : bool
450 remove : bool
445 If False (the default), then install the handler. If True
451 If False (the default), then install the handler. If True
446 then unintall it.
452 then unintall it.
447 """
453 """
448 if remove:
454 if remove:
449 names = parse_notifier_name(name)
455 names = parse_notifier_name(name)
450 for n in names:
456 for n in names:
451 self._remove_notifiers(handler, n)
457 self._remove_notifiers(handler, n)
452 else:
458 else:
453 names = parse_notifier_name(name)
459 names = parse_notifier_name(name)
454 for n in names:
460 for n in names:
455 self._add_notifiers(handler, n)
461 self._add_notifiers(handler, n)
456
462
457 def traitlet_names(self, **metadata):
463 def traitlet_names(self, **metadata):
458 """Get a list of all the names of this classes traitlets."""
464 """Get a list of all the names of this classes traitlets."""
459 return self.traitlets(**metadata).keys()
465 return self.traitlets(**metadata).keys()
460
466
461 def traitlets(self, **metadata):
467 def traitlets(self, **metadata):
462 """Get a list of all the traitlets of this class.
468 """Get a list of all the traitlets of this class.
463
469
464 The TraitletTypes returned don't know anything about the values
470 The TraitletTypes returned don't know anything about the values
465 that the various HasTraitlet's instances are holding.
471 that the various HasTraitlet's instances are holding.
466
472
467 This follows the same algorithm as traits does and does not allow
473 This follows the same algorithm as traits does and does not allow
468 for any simple way of specifying merely that a metadata name
474 for any simple way of specifying merely that a metadata name
469 exists, but has any value. This is because get_metadata returns
475 exists, but has any value. This is because get_metadata returns
470 None if a metadata key doesn't exist.
476 None if a metadata key doesn't exist.
471 """
477 """
472 traitlets = dict([memb for memb in inspect.getmembers(self.__class__) if \
478 traitlets = dict([memb for memb in inspect.getmembers(self.__class__) if \
473 isinstance(memb[1], TraitletType)])
479 isinstance(memb[1], TraitletType)])
474
480
475 if len(metadata) == 0:
481 if len(metadata) == 0:
476 return traitlets
482 return traitlets
477
483
478 for meta_name, meta_eval in metadata.items():
484 for meta_name, meta_eval in metadata.items():
479 if type(meta_eval) is not FunctionType:
485 if type(meta_eval) is not FunctionType:
480 metadata[meta_name] = _SimpleTest(meta_eval)
486 metadata[meta_name] = _SimpleTest(meta_eval)
481
487
482 result = {}
488 result = {}
483 for name, traitlet in traitlets.items():
489 for name, traitlet in traitlets.items():
484 for meta_name, meta_eval in metadata.items():
490 for meta_name, meta_eval in metadata.items():
485 if not meta_eval(traitlet.get_metadata(meta_name)):
491 if not meta_eval(traitlet.get_metadata(meta_name)):
486 break
492 break
487 else:
493 else:
488 result[name] = traitlet
494 result[name] = traitlet
489
495
490 return result
496 return result
491
497
492 def traitlet_metadata(self, traitletname, key):
498 def traitlet_metadata(self, traitletname, key):
493 """Get metadata values for traitlet by key."""
499 """Get metadata values for traitlet by key."""
494 try:
500 try:
495 traitlet = getattr(self.__class__, traitletname)
501 traitlet = getattr(self.__class__, traitletname)
496 except AttributeError:
502 except AttributeError:
497 raise TraitletError("Class %s does not have a traitlet named %s" %
503 raise TraitletError("Class %s does not have a traitlet named %s" %
498 (self.__class__.__name__, traitletname))
504 (self.__class__.__name__, traitletname))
499 else:
505 else:
500 return traitlet.get_metadata(key)
506 return traitlet.get_metadata(key)
501
507
502 #-----------------------------------------------------------------------------
508 #-----------------------------------------------------------------------------
503 # Actual TraitletTypes implementations/subclasses
509 # Actual TraitletTypes implementations/subclasses
504 #-----------------------------------------------------------------------------
510 #-----------------------------------------------------------------------------
505
511
506 #-----------------------------------------------------------------------------
512 #-----------------------------------------------------------------------------
507 # TraitletTypes subclasses for handling classes and instances of classes
513 # TraitletTypes subclasses for handling classes and instances of classes
508 #-----------------------------------------------------------------------------
514 #-----------------------------------------------------------------------------
509
515
510
516
511 class ClassBasedTraitletType(TraitletType):
517 class ClassBasedTraitletType(TraitletType):
512 """A traitlet with error reporting for Type, Instance and This."""
518 """A traitlet with error reporting for Type, Instance and This."""
513
519
514 def error(self, obj, value):
520 def error(self, obj, value):
515 kind = type(value)
521 kind = type(value)
516 if kind is InstanceType:
522 if kind is InstanceType:
517 msg = 'class %s' % value.__class__.__name__
523 msg = 'class %s' % value.__class__.__name__
518 else:
524 else:
519 msg = '%s (i.e. %s)' % ( str( kind )[1:-1], repr( value ) )
525 msg = '%s (i.e. %s)' % ( str( kind )[1:-1], repr( value ) )
520
526
521 super(ClassBasedTraitletType, self).error(obj, msg)
527 super(ClassBasedTraitletType, self).error(obj, msg)
522
528
523
529
524 class Type(ClassBasedTraitletType):
530 class Type(ClassBasedTraitletType):
525 """A traitlet whose value must be a subclass of a specified class."""
531 """A traitlet whose value must be a subclass of a specified class."""
526
532
527 def __init__ (self, default_value=None, klass=None, allow_none=True, **metadata ):
533 def __init__ (self, default_value=None, klass=None, allow_none=True, **metadata ):
528 """Construct a Type traitlet
534 """Construct a Type traitlet
529
535
530 A Type traitlet specifies that its values must be subclasses of
536 A Type traitlet specifies that its values must be subclasses of
531 a particular class.
537 a particular class.
532
538
533 If only ``default_value`` is given, it is used for the ``klass`` as
539 If only ``default_value`` is given, it is used for the ``klass`` as
534 well.
540 well.
535
541
536 Parameters
542 Parameters
537 ----------
543 ----------
538 default_value : class, str or None
544 default_value : class, str or None
539 The default value must be a subclass of klass. If an str,
545 The default value must be a subclass of klass. If an str,
540 the str must be a fully specified class name, like 'foo.bar.Bah'.
546 the str must be a fully specified class name, like 'foo.bar.Bah'.
541 The string is resolved into real class, when the parent
547 The string is resolved into real class, when the parent
542 :class:`HasTraitlets` class is instantiated.
548 :class:`HasTraitlets` class is instantiated.
543 klass : class, str, None
549 klass : class, str, None
544 Values of this traitlet must be a subclass of klass. The klass
550 Values of this traitlet must be a subclass of klass. The klass
545 may be specified in a string like: 'foo.bar.MyClass'.
551 may be specified in a string like: 'foo.bar.MyClass'.
546 The string is resolved into real class, when the parent
552 The string is resolved into real class, when the parent
547 :class:`HasTraitlets` class is instantiated.
553 :class:`HasTraitlets` class is instantiated.
548 allow_none : boolean
554 allow_none : boolean
549 Indicates whether None is allowed as an assignable value. Even if
555 Indicates whether None is allowed as an assignable value. Even if
550 ``False``, the default value may be ``None``.
556 ``False``, the default value may be ``None``.
551 """
557 """
552 if default_value is None:
558 if default_value is None:
553 if klass is None:
559 if klass is None:
554 klass = object
560 klass = object
555 elif klass is None:
561 elif klass is None:
556 klass = default_value
562 klass = default_value
557
563
558 if not (inspect.isclass(klass) or isinstance(klass, basestring)):
564 if not (inspect.isclass(klass) or isinstance(klass, basestring)):
559 raise TraitletError("A Type traitlet must specify a class.")
565 raise TraitletError("A Type traitlet must specify a class.")
560
566
561 self.klass = klass
567 self.klass = klass
562 self._allow_none = allow_none
568 self._allow_none = allow_none
563
569
564 super(Type, self).__init__(default_value, **metadata)
570 super(Type, self).__init__(default_value, **metadata)
565
571
566 def validate(self, obj, value):
572 def validate(self, obj, value):
567 """Validates that the value is a valid object instance."""
573 """Validates that the value is a valid object instance."""
568 try:
574 try:
569 if issubclass(value, self.klass):
575 if issubclass(value, self.klass):
570 return value
576 return value
571 except:
577 except:
572 if (value is None) and (self._allow_none):
578 if (value is None) and (self._allow_none):
573 return value
579 return value
574
580
575 self.error(obj, value)
581 self.error(obj, value)
576
582
577 def info(self):
583 def info(self):
578 """ Returns a description of the trait."""
584 """ Returns a description of the trait."""
579 if isinstance(self.klass, basestring):
585 if isinstance(self.klass, basestring):
580 klass = self.klass
586 klass = self.klass
581 else:
587 else:
582 klass = self.klass.__name__
588 klass = self.klass.__name__
583 result = 'a subclass of ' + klass
589 result = 'a subclass of ' + klass
584 if self._allow_none:
590 if self._allow_none:
585 return result + ' or None'
591 return result + ' or None'
586 return result
592 return result
587
593
588 def instance_init(self, obj):
594 def instance_init(self, obj):
589 self._resolve_classes()
595 self._resolve_classes()
590 super(Type, self).instance_init(obj)
596 super(Type, self).instance_init(obj)
591
597
592 def _resolve_classes(self):
598 def _resolve_classes(self):
593 if isinstance(self.klass, basestring):
599 if isinstance(self.klass, basestring):
594 self.klass = import_item(self.klass)
600 self.klass = import_item(self.klass)
595 if isinstance(self.default_value, basestring):
601 if isinstance(self.default_value, basestring):
596 self.default_value = import_item(self.default_value)
602 self.default_value = import_item(self.default_value)
597
603
598 def get_default_value(self):
604 def get_default_value(self):
599 return self.default_value
605 return self.default_value
600
606
601
607
602 class DefaultValueGenerator(object):
608 class DefaultValueGenerator(object):
603 """A class for generating new default value instances."""
609 """A class for generating new default value instances."""
604
610
605 def __init__(self, *args, **kw):
611 def __init__(self, *args, **kw):
606 self.args = args
612 self.args = args
607 self.kw = kw
613 self.kw = kw
608
614
609 def generate(self, klass):
615 def generate(self, klass):
610 return klass(*self.args, **self.kw)
616 return klass(*self.args, **self.kw)
611
617
612
618
613 class Instance(ClassBasedTraitletType):
619 class Instance(ClassBasedTraitletType):
614 """A trait whose value must be an instance of a specified class.
620 """A trait whose value must be an instance of a specified class.
615
621
616 The value can also be an instance of a subclass of the specified class.
622 The value can also be an instance of a subclass of the specified class.
617 """
623 """
618
624
619 def __init__(self, klass=None, args=None, kw=None,
625 def __init__(self, klass=None, args=None, kw=None,
620 allow_none=True, **metadata ):
626 allow_none=True, **metadata ):
621 """Construct an Instance traitlet.
627 """Construct an Instance traitlet.
622
628
623 This traitlet allows values that are instances of a particular
629 This traitlet allows values that are instances of a particular
624 class or its sublclasses. Our implementation is quite different
630 class or its sublclasses. Our implementation is quite different
625 from that of enthough.traits as we don't allow instances to be used
631 from that of enthough.traits as we don't allow instances to be used
626 for klass and we handle the ``args`` and ``kw`` arguments differently.
632 for klass and we handle the ``args`` and ``kw`` arguments differently.
627
633
628 Parameters
634 Parameters
629 ----------
635 ----------
630 klass : class, str
636 klass : class, str
631 The class that forms the basis for the traitlet. Class names
637 The class that forms the basis for the traitlet. Class names
632 can also be specified as strings, like 'foo.bar.Bar'.
638 can also be specified as strings, like 'foo.bar.Bar'.
633 args : tuple
639 args : tuple
634 Positional arguments for generating the default value.
640 Positional arguments for generating the default value.
635 kw : dict
641 kw : dict
636 Keyword arguments for generating the default value.
642 Keyword arguments for generating the default value.
637 allow_none : bool
643 allow_none : bool
638 Indicates whether None is allowed as a value.
644 Indicates whether None is allowed as a value.
639
645
640 Default Value
646 Default Value
641 -------------
647 -------------
642 If both ``args`` and ``kw`` are None, then the default value is None.
648 If both ``args`` and ``kw`` are None, then the default value is None.
643 If ``args`` is a tuple and ``kw`` is a dict, then the default is
649 If ``args`` is a tuple and ``kw`` is a dict, then the default is
644 created as ``klass(*args, **kw)``. If either ``args`` or ``kw`` is
650 created as ``klass(*args, **kw)``. If either ``args`` or ``kw`` is
645 not (but not both), None is replace by ``()`` or ``{}``.
651 not (but not both), None is replace by ``()`` or ``{}``.
646 """
652 """
647
653
648 self._allow_none = allow_none
654 self._allow_none = allow_none
649
655
650 if (klass is None) or (not (inspect.isclass(klass) or isinstance(klass, basestring))):
656 if (klass is None) or (not (inspect.isclass(klass) or isinstance(klass, basestring))):
651 raise TraitletError('The klass argument must be a class'
657 raise TraitletError('The klass argument must be a class'
652 ' you gave: %r' % klass)
658 ' you gave: %r' % klass)
653 self.klass = klass
659 self.klass = klass
654
660
655 # self.klass is a class, so handle default_value
661 # self.klass is a class, so handle default_value
656 if args is None and kw is None:
662 if args is None and kw is None:
657 default_value = None
663 default_value = None
658 else:
664 else:
659 if args is None:
665 if args is None:
660 # kw is not None
666 # kw is not None
661 args = ()
667 args = ()
662 elif kw is None:
668 elif kw is None:
663 # args is not None
669 # args is not None
664 kw = {}
670 kw = {}
665
671
666 if not isinstance(kw, dict):
672 if not isinstance(kw, dict):
667 raise TraitletError("The 'kw' argument must be a dict or None.")
673 raise TraitletError("The 'kw' argument must be a dict or None.")
668 if not isinstance(args, tuple):
674 if not isinstance(args, tuple):
669 raise TraitletError("The 'args' argument must be a tuple or None.")
675 raise TraitletError("The 'args' argument must be a tuple or None.")
670
676
671 default_value = DefaultValueGenerator(*args, **kw)
677 default_value = DefaultValueGenerator(*args, **kw)
672
678
673 super(Instance, self).__init__(default_value, **metadata)
679 super(Instance, self).__init__(default_value, **metadata)
674
680
675 def validate(self, obj, value):
681 def validate(self, obj, value):
676 if value is None:
682 if value is None:
677 if self._allow_none:
683 if self._allow_none:
678 return value
684 return value
679 self.error(obj, value)
685 self.error(obj, value)
680
686
681 if isinstance(value, self.klass):
687 if isinstance(value, self.klass):
682 return value
688 return value
683 else:
689 else:
684 self.error(obj, value)
690 self.error(obj, value)
685
691
686 def info(self):
692 def info(self):
687 if isinstance(self.klass, basestring):
693 if isinstance(self.klass, basestring):
688 klass = self.klass
694 klass = self.klass
689 else:
695 else:
690 klass = self.klass.__name__
696 klass = self.klass.__name__
691 result = class_of(klass)
697 result = class_of(klass)
692 if self._allow_none:
698 if self._allow_none:
693 return result + ' or None'
699 return result + ' or None'
694
700
695 return result
701 return result
696
702
697 def instance_init(self, obj):
703 def instance_init(self, obj):
698 self._resolve_classes()
704 self._resolve_classes()
699 super(Instance, self).instance_init(obj)
705 super(Instance, self).instance_init(obj)
700
706
701 def _resolve_classes(self):
707 def _resolve_classes(self):
702 if isinstance(self.klass, basestring):
708 if isinstance(self.klass, basestring):
703 self.klass = import_item(self.klass)
709 self.klass = import_item(self.klass)
704
710
705 def get_default_value(self):
711 def get_default_value(self):
706 """Instantiate a default value instance.
712 """Instantiate a default value instance.
707
713
708 This is called when the containing HasTraitlets classes'
714 This is called when the containing HasTraitlets classes'
709 :meth:`__new__` method is called to ensure that a unique instance
715 :meth:`__new__` method is called to ensure that a unique instance
710 is created for each HasTraitlets instance.
716 is created for each HasTraitlets instance.
711 """
717 """
712 dv = self.default_value
718 dv = self.default_value
713 if isinstance(dv, DefaultValueGenerator):
719 if isinstance(dv, DefaultValueGenerator):
714 return dv.generate(self.klass)
720 return dv.generate(self.klass)
715 else:
721 else:
716 return dv
722 return dv
717
723
718
724
719 class This(ClassBasedTraitletType):
725 class This(ClassBasedTraitletType):
720 """A traitlet for instances of the class containing this trait.
726 """A traitlet for instances of the class containing this trait.
721
727
722 Because how how and when class bodies are executed, the ``This``
728 Because how how and when class bodies are executed, the ``This``
723 traitlet can only have a default value of None. This, and because we
729 traitlet can only have a default value of None. This, and because we
724 always validate default values, ``allow_none`` is *always* true.
730 always validate default values, ``allow_none`` is *always* true.
725 """
731 """
726
732
727 info_text = 'an instance of the same type as the receiver or None'
733 info_text = 'an instance of the same type as the receiver or None'
728
734
729 def __init__(self, **metadata):
735 def __init__(self, **metadata):
730 super(This, self).__init__(None, **metadata)
736 super(This, self).__init__(None, **metadata)
731
737
732 def validate(self, obj, value):
738 def validate(self, obj, value):
733 # What if value is a superclass of obj.__class__? This is
739 # What if value is a superclass of obj.__class__? This is
734 # complicated if it was the superclass that defined the This
740 # complicated if it was the superclass that defined the This
735 # traitlet.
741 # traitlet.
736 if isinstance(value, self.this_class) or (value is None):
742 if isinstance(value, self.this_class) or (value is None):
737 return value
743 return value
738 else:
744 else:
739 self.error(obj, value)
745 self.error(obj, value)
740
746
741
747
742 #-----------------------------------------------------------------------------
748 #-----------------------------------------------------------------------------
743 # Basic TraitletTypes implementations/subclasses
749 # Basic TraitletTypes implementations/subclasses
744 #-----------------------------------------------------------------------------
750 #-----------------------------------------------------------------------------
745
751
746
752
747 class Any(TraitletType):
753 class Any(TraitletType):
748 default_value = None
754 default_value = None
749 info_text = 'any value'
755 info_text = 'any value'
750
756
751
757
752 class Int(TraitletType):
758 class Int(TraitletType):
753 """A integer traitlet."""
759 """A integer traitlet."""
754
760
755 evaluate = int
761 evaluate = int
756 default_value = 0
762 default_value = 0
757 info_text = 'an integer'
763 info_text = 'an integer'
758
764
759 def validate(self, obj, value):
765 def validate(self, obj, value):
760 if isinstance(value, int):
766 if isinstance(value, int):
761 return value
767 return value
762 self.error(obj, value)
768 self.error(obj, value)
763
769
764 class CInt(Int):
770 class CInt(Int):
765 """A casting version of the int traitlet."""
771 """A casting version of the int traitlet."""
766
772
767 def validate(self, obj, value):
773 def validate(self, obj, value):
768 try:
774 try:
769 return int(value)
775 return int(value)
770 except:
776 except:
771 self.error(obj, value)
777 self.error(obj, value)
772
778
773
779
774 class Long(TraitletType):
780 class Long(TraitletType):
775 """A long integer traitlet."""
781 """A long integer traitlet."""
776
782
777 evaluate = long
783 evaluate = long
778 default_value = 0L
784 default_value = 0L
779 info_text = 'a long'
785 info_text = 'a long'
780
786
781 def validate(self, obj, value):
787 def validate(self, obj, value):
782 if isinstance(value, long):
788 if isinstance(value, long):
783 return value
789 return value
784 if isinstance(value, int):
790 if isinstance(value, int):
785 return long(value)
791 return long(value)
786 self.error(obj, value)
792 self.error(obj, value)
787
793
788
794
789 class CLong(Long):
795 class CLong(Long):
790 """A casting version of the long integer traitlet."""
796 """A casting version of the long integer traitlet."""
791
797
792 def validate(self, obj, value):
798 def validate(self, obj, value):
793 try:
799 try:
794 return long(value)
800 return long(value)
795 except:
801 except:
796 self.error(obj, value)
802 self.error(obj, value)
797
803
798
804
799 class Float(TraitletType):
805 class Float(TraitletType):
800 """A float traitlet."""
806 """A float traitlet."""
801
807
802 evaluate = float
808 evaluate = float
803 default_value = 0.0
809 default_value = 0.0
804 info_text = 'a float'
810 info_text = 'a float'
805
811
806 def validate(self, obj, value):
812 def validate(self, obj, value):
807 if isinstance(value, float):
813 if isinstance(value, float):
808 return value
814 return value
809 if isinstance(value, int):
815 if isinstance(value, int):
810 return float(value)
816 return float(value)
811 self.error(obj, value)
817 self.error(obj, value)
812
818
813
819
814 class CFloat(Float):
820 class CFloat(Float):
815 """A casting version of the float traitlet."""
821 """A casting version of the float traitlet."""
816
822
817 def validate(self, obj, value):
823 def validate(self, obj, value):
818 try:
824 try:
819 return float(value)
825 return float(value)
820 except:
826 except:
821 self.error(obj, value)
827 self.error(obj, value)
822
828
823 class Complex(TraitletType):
829 class Complex(TraitletType):
824 """A traitlet for complex numbers."""
830 """A traitlet for complex numbers."""
825
831
826 evaluate = complex
832 evaluate = complex
827 default_value = 0.0 + 0.0j
833 default_value = 0.0 + 0.0j
828 info_text = 'a complex number'
834 info_text = 'a complex number'
829
835
830 def validate(self, obj, value):
836 def validate(self, obj, value):
831 if isinstance(value, complex):
837 if isinstance(value, complex):
832 return value
838 return value
833 if isinstance(value, (float, int)):
839 if isinstance(value, (float, int)):
834 return complex(value)
840 return complex(value)
835 self.error(obj, value)
841 self.error(obj, value)
836
842
837
843
838 class CComplex(Complex):
844 class CComplex(Complex):
839 """A casting version of the complex number traitlet."""
845 """A casting version of the complex number traitlet."""
840
846
841 def validate (self, obj, value):
847 def validate (self, obj, value):
842 try:
848 try:
843 return complex(value)
849 return complex(value)
844 except:
850 except:
845 self.error(obj, value)
851 self.error(obj, value)
846
852
847
853
848 class Str(TraitletType):
854 class Str(TraitletType):
849 """A traitlet for strings."""
855 """A traitlet for strings."""
850
856
851 evaluate = lambda x: x
857 evaluate = lambda x: x
852 default_value = ''
858 default_value = ''
853 info_text = 'a string'
859 info_text = 'a string'
854
860
855 def validate(self, obj, value):
861 def validate(self, obj, value):
856 if isinstance(value, str):
862 if isinstance(value, str):
857 return value
863 return value
858 self.error(obj, value)
864 self.error(obj, value)
859
865
860
866
861 class CStr(Str):
867 class CStr(Str):
862 """A casting version of the string traitlet."""
868 """A casting version of the string traitlet."""
863
869
864 def validate(self, obj, value):
870 def validate(self, obj, value):
865 try:
871 try:
866 return str(value)
872 return str(value)
867 except:
873 except:
868 try:
874 try:
869 return unicode(value)
875 return unicode(value)
870 except:
876 except:
871 self.error(obj, value)
877 self.error(obj, value)
872
878
873
879
874 class Unicode(TraitletType):
880 class Unicode(TraitletType):
875 """A traitlet for unicode strings."""
881 """A traitlet for unicode strings."""
876
882
877 evaluate = unicode
883 evaluate = unicode
878 default_value = u''
884 default_value = u''
879 info_text = 'a unicode string'
885 info_text = 'a unicode string'
880
886
881 def validate(self, obj, value):
887 def validate(self, obj, value):
882 if isinstance(value, unicode):
888 if isinstance(value, unicode):
883 return value
889 return value
884 if isinstance(value, str):
890 if isinstance(value, str):
885 return unicode(value)
891 return unicode(value)
886 self.error(obj, value)
892 self.error(obj, value)
887
893
888
894
889 class CUnicode(Unicode):
895 class CUnicode(Unicode):
890 """A casting version of the unicode traitlet."""
896 """A casting version of the unicode traitlet."""
891
897
892 def validate(self, obj, value):
898 def validate(self, obj, value):
893 try:
899 try:
894 return unicode(value)
900 return unicode(value)
895 except:
901 except:
896 self.error(obj, value)
902 self.error(obj, value)
897
903
898
904
899 class Bool(TraitletType):
905 class Bool(TraitletType):
900 """A boolean (True, False) traitlet."""
906 """A boolean (True, False) traitlet."""
901 evaluate = bool
907 evaluate = bool
902 default_value = False
908 default_value = False
903 info_text = 'a boolean'
909 info_text = 'a boolean'
904
910
905 def validate(self, obj, value):
911 def validate(self, obj, value):
906 if isinstance(value, bool):
912 if isinstance(value, bool):
907 return value
913 return value
908 self.error(obj, value)
914 self.error(obj, value)
909
915
910
916
911 class CBool(Bool):
917 class CBool(Bool):
912 """A casting version of the boolean traitlet."""
918 """A casting version of the boolean traitlet."""
913
919
914 def validate(self, obj, value):
920 def validate(self, obj, value):
915 try:
921 try:
916 return bool(value)
922 return bool(value)
917 except:
923 except:
918 self.error(obj, value)
924 self.error(obj, value)
919
925
920
926
921 class Enum(TraitletType):
927 class Enum(TraitletType):
922 """An enum that whose value must be in a given sequence."""
928 """An enum that whose value must be in a given sequence."""
923
929
924 def __init__(self, values, default_value=None, allow_none=True, **metadata):
930 def __init__(self, values, default_value=None, allow_none=True, **metadata):
925 self.values = values
931 self.values = values
926 self._allow_none = allow_none
932 self._allow_none = allow_none
927 super(Enum, self).__init__(default_value, **metadata)
933 super(Enum, self).__init__(default_value, **metadata)
928
934
929 def validate(self, obj, value):
935 def validate(self, obj, value):
930 if value is None:
936 if value is None:
931 if self._allow_none:
937 if self._allow_none:
932 return value
938 return value
933
939
934 if value in self.values:
940 if value in self.values:
935 return value
941 return value
936 self.error(obj, value)
942 self.error(obj, value)
937
943
938 def info(self):
944 def info(self):
939 """ Returns a description of the trait."""
945 """ Returns a description of the trait."""
940 result = 'any of ' + repr(self.values)
946 result = 'any of ' + repr(self.values)
941 if self._allow_none:
947 if self._allow_none:
942 return result + ' or None'
948 return result + ' or None'
943 return result
949 return result
944
950
945 class CaselessStrEnum(Enum):
951 class CaselessStrEnum(Enum):
946 """An enum of strings that are caseless in validate."""
952 """An enum of strings that are caseless in validate."""
947
953
948 def validate(self, obj, value):
954 def validate(self, obj, value):
949 if value is None:
955 if value is None:
950 if self._allow_none:
956 if self._allow_none:
951 return value
957 return value
952
958
953 if not isinstance(value, str):
959 if not isinstance(value, str):
954 self.error(obj, value)
960 self.error(obj, value)
955
961
956 for v in self.values:
962 for v in self.values:
957 if v.lower() == value.lower():
963 if v.lower() == value.lower():
958 return v
964 return v
959 self.error(obj, value)
965 self.error(obj, value)
960
966
961
967
962 class List(Instance):
968 class List(Instance):
963 """An instance of a Python list."""
969 """An instance of a Python list."""
964
970
965 def __init__(self, default_value=None, allow_none=True, **metadata):
971 def __init__(self, default_value=None, allow_none=True, **metadata):
966 """Create a list traitlet type from a list or tuple.
972 """Create a list traitlet type from a list or tuple.
967
973
968 The default value is created by doing ``list(default_value)``,
974 The default value is created by doing ``list(default_value)``,
969 which creates a copy of the ``default_value``.
975 which creates a copy of the ``default_value``.
970 """
976 """
971 if default_value is None:
977 if default_value is None:
972 args = ((),)
978 args = ((),)
973 elif isinstance(default_value, SequenceTypes):
979 elif isinstance(default_value, SequenceTypes):
974 args = (default_value,)
980 args = (default_value,)
975
981
976 super(List,self).__init__(klass=list, args=args,
982 super(List,self).__init__(klass=list, args=args,
977 allow_none=allow_none, **metadata)
983 allow_none=allow_none, **metadata)
General Comments 0
You need to be logged in to leave comments. Login now