##// END OF EJS Templates
diff I sent to Fernando
Dav Clark -
Show More
@@ -1,983 +1,985 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 # This is needed because in Python 2.6 object.__new__ only accepts
345 # This is needed because in Python 2.6 object.__new__ only accepts
346 # the cls argument.
346 # the cls argument.
347 new_meth = super(HasTraitlets, cls).__new__
347 new_meth = super(HasTraitlets, cls).__new__
348 if new_meth is object.__new__:
348 if new_meth is object.__new__:
349 inst = new_meth(cls)
349 inst = new_meth(cls)
350 else:
350 else:
351 inst = new_meth(cls, *args, **kw)
351 inst = new_meth(cls, *args, **kw)
352 inst._traitlet_values = {}
352 inst._traitlet_values = {}
353 inst._traitlet_notifiers = {}
353 inst._traitlet_notifiers = {}
354 # Here we tell all the TraitletType instances to set their default
354 # Here we tell all the TraitletType instances to set their default
355 # values on the instance.
355 # values on the instance.
356 for key in dir(cls):
356 for key in dir(cls):
357 value = getattr(cls, key)
357 value = getattr(cls, key)
358 if isinstance(value, TraitletType):
358 if isinstance(value, TraitletType):
359 value.instance_init(inst)
359 value.instance_init(inst)
360 return inst
360 return inst
361
361
362 # def __init__(self):
362 # def __init__(self):
363 # self._traitlet_values = {}
363 # self._traitlet_values = {}
364 # self._traitlet_notifiers = {}
364 # self._traitlet_notifiers = {}
365
365
366 def _notify_traitlet(self, name, old_value, new_value):
366 def _notify_traitlet(self, name, old_value, new_value):
367
367
368 # First dynamic ones
368 # First dynamic ones
369 callables = self._traitlet_notifiers.get(name,[])
369 callables = self._traitlet_notifiers.get(name,[])
370 more_callables = self._traitlet_notifiers.get('anytraitlet',[])
370 more_callables = self._traitlet_notifiers.get('anytraitlet',[])
371 callables.extend(more_callables)
371 callables.extend(more_callables)
372
372
373 # Now static ones
373 # Now static ones
374 try:
374 try:
375 cb = getattr(self, '_%s_changed' % name)
375 cb = getattr(self, '_%s_changed' % name)
376 except:
376 except:
377 pass
377 pass
378 else:
378 else:
379 callables.append(cb)
379 callables.append(cb)
380
380
381 # Call them all now
381 # Call them all now
382 for c in callables:
382 for c in callables:
383 # Traits catches and logs errors here. I allow them to raise
383 # Traits catches and logs errors here. I allow them to raise
384 if callable(c):
384 if callable(c):
385 argspec = inspect.getargspec(c)
385 argspec = inspect.getargspec(c)
386 nargs = len(argspec[0])
386 nargs = len(argspec[0])
387 # Bound methods have an additional 'self' argument
387 # Bound methods have an additional 'self' argument
388 # I don't know how to treat unbound methods, but they
388 # I don't know how to treat unbound methods, but they
389 # can't really be used for callbacks.
389 # can't really be used for callbacks.
390 if isinstance(c, types.MethodType):
390 if isinstance(c, types.MethodType):
391 offset = -1
391 offset = -1
392 else:
392 else:
393 offset = 0
393 offset = 0
394 if nargs + offset == 0:
394 if nargs + offset == 0:
395 c()
395 c()
396 elif nargs + offset == 1:
396 elif nargs + offset == 1:
397 c(name)
397 c(name)
398 elif nargs + offset == 2:
398 elif nargs + offset == 2:
399 c(name, new_value)
399 c(name, new_value)
400 elif nargs + offset == 3:
400 elif nargs + offset == 3:
401 c(name, old_value, new_value)
401 c(name, old_value, new_value)
402 else:
402 else:
403 raise TraitletError('a traitlet changed callback '
403 raise TraitletError('a traitlet changed callback '
404 'must have 0-3 arguments.')
404 'must have 0-3 arguments.')
405 else:
405 else:
406 raise TraitletError('a traitlet changed callback '
406 raise TraitletError('a traitlet changed callback '
407 'must be callable.')
407 'must be callable.')
408
408
409
409
410 def _add_notifiers(self, handler, name):
410 def _add_notifiers(self, handler, name):
411 if not self._traitlet_notifiers.has_key(name):
411 if not self._traitlet_notifiers.has_key(name):
412 nlist = []
412 nlist = []
413 self._traitlet_notifiers[name] = nlist
413 self._traitlet_notifiers[name] = nlist
414 else:
414 else:
415 nlist = self._traitlet_notifiers[name]
415 nlist = self._traitlet_notifiers[name]
416 if handler not in nlist:
416 if handler not in nlist:
417 nlist.append(handler)
417 nlist.append(handler)
418
418
419 def _remove_notifiers(self, handler, name):
419 def _remove_notifiers(self, handler, name):
420 if self._traitlet_notifiers.has_key(name):
420 if self._traitlet_notifiers.has_key(name):
421 nlist = self._traitlet_notifiers[name]
421 nlist = self._traitlet_notifiers[name]
422 try:
422 try:
423 index = nlist.index(handler)
423 index = nlist.index(handler)
424 except ValueError:
424 except ValueError:
425 pass
425 pass
426 else:
426 else:
427 del nlist[index]
427 del nlist[index]
428
428
429 def on_traitlet_change(self, handler, name=None, remove=False):
429 def on_traitlet_change(self, handler, name=None, remove=False):
430 """Setup a handler to be called when a traitlet changes.
430 """Setup a handler to be called when a traitlet changes.
431
431
432 This is used to setup dynamic notifications of traitlet changes.
432 This is used to setup dynamic notifications of traitlet changes.
433
433
434 Static handlers can be created by creating methods on a HasTraitlets
434 Static handlers can be created by creating methods on a HasTraitlets
435 subclass with the naming convention '_[traitletname]_changed'. Thus,
435 subclass with the naming convention '_[traitletname]_changed'. Thus,
436 to create static handler for the traitlet 'a', create the method
436 to create static handler for the traitlet 'a', create the method
437 _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
438 below).
438 below).
439
439
440 Parameters
440 Parameters
441 ----------
441 ----------
442 handler : callable
442 handler : callable
443 A callable that is called when a traitlet changes. Its
443 A callable that is called when a traitlet changes. Its
444 signature can be handler(), handler(name), handler(name, new)
444 signature can be handler(), handler(name), handler(name, new)
445 or handler(name, old, new).
445 or handler(name, old, new).
446 name : list, str, None
446 name : list, str, None
447 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
448 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
449 str, the handler will apply just to that name.
449 str, the handler will apply just to that name.
450 remove : bool
450 remove : bool
451 If False (the default), then install the handler. If True
451 If False (the default), then install the handler. If True
452 then unintall it.
452 then unintall it.
453 """
453 """
454 if remove:
454 if remove:
455 names = parse_notifier_name(name)
455 names = parse_notifier_name(name)
456 for n in names:
456 for n in names:
457 self._remove_notifiers(handler, n)
457 self._remove_notifiers(handler, n)
458 else:
458 else:
459 names = parse_notifier_name(name)
459 names = parse_notifier_name(name)
460 for n in names:
460 for n in names:
461 self._add_notifiers(handler, n)
461 self._add_notifiers(handler, n)
462
462
463 def traitlet_names(self, **metadata):
463 def traitlet_names(self, **metadata):
464 """Get a list of all the names of this classes traitlets."""
464 """Get a list of all the names of this classes traitlets."""
465 return self.traitlets(**metadata).keys()
465 return self.traitlets(**metadata).keys()
466
466
467 def traitlets(self, **metadata):
467 def traitlets(self, **metadata):
468 """Get a list of all the traitlets of this class.
468 """Get a list of all the traitlets of this class.
469
469
470 The TraitletTypes returned don't know anything about the values
470 The TraitletTypes returned don't know anything about the values
471 that the various HasTraitlet's instances are holding.
471 that the various HasTraitlet's instances are holding.
472
472
473 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
474 for any simple way of specifying merely that a metadata name
474 for any simple way of specifying merely that a metadata name
475 exists, but has any value. This is because get_metadata returns
475 exists, but has any value. This is because get_metadata returns
476 None if a metadata key doesn't exist.
476 None if a metadata key doesn't exist.
477 """
477 """
478 traitlets = dict([memb for memb in inspect.getmembers(self.__class__) if \
478 traitlets = dict([memb for memb in inspect.getmembers(self.__class__) if \
479 isinstance(memb[1], TraitletType)])
479 isinstance(memb[1], TraitletType)])
480
480
481 if len(metadata) == 0:
481 if len(metadata) == 0:
482 return traitlets
482 return traitlets
483
483
484 for meta_name, meta_eval in metadata.items():
484 for meta_name, meta_eval in metadata.items():
485 if type(meta_eval) is not FunctionType:
485 if type(meta_eval) is not FunctionType:
486 metadata[meta_name] = _SimpleTest(meta_eval)
486 metadata[meta_name] = _SimpleTest(meta_eval)
487
487
488 result = {}
488 result = {}
489 for name, traitlet in traitlets.items():
489 for name, traitlet in traitlets.items():
490 for meta_name, meta_eval in metadata.items():
490 for meta_name, meta_eval in metadata.items():
491 if not meta_eval(traitlet.get_metadata(meta_name)):
491 if not meta_eval(traitlet.get_metadata(meta_name)):
492 break
492 break
493 else:
493 else:
494 result[name] = traitlet
494 result[name] = traitlet
495
495
496 return result
496 return result
497
497
498 def traitlet_metadata(self, traitletname, key):
498 def traitlet_metadata(self, traitletname, key):
499 """Get metadata values for traitlet by key."""
499 """Get metadata values for traitlet by key."""
500 try:
500 try:
501 traitlet = getattr(self.__class__, traitletname)
501 traitlet = getattr(self.__class__, traitletname)
502 except AttributeError:
502 except AttributeError:
503 raise TraitletError("Class %s does not have a traitlet named %s" %
503 raise TraitletError("Class %s does not have a traitlet named %s" %
504 (self.__class__.__name__, traitletname))
504 (self.__class__.__name__, traitletname))
505 else:
505 else:
506 return traitlet.get_metadata(key)
506 return traitlet.get_metadata(key)
507
507
508 #-----------------------------------------------------------------------------
508 #-----------------------------------------------------------------------------
509 # Actual TraitletTypes implementations/subclasses
509 # Actual TraitletTypes implementations/subclasses
510 #-----------------------------------------------------------------------------
510 #-----------------------------------------------------------------------------
511
511
512 #-----------------------------------------------------------------------------
512 #-----------------------------------------------------------------------------
513 # TraitletTypes subclasses for handling classes and instances of classes
513 # TraitletTypes subclasses for handling classes and instances of classes
514 #-----------------------------------------------------------------------------
514 #-----------------------------------------------------------------------------
515
515
516
516
517 class ClassBasedTraitletType(TraitletType):
517 class ClassBasedTraitletType(TraitletType):
518 """A traitlet with error reporting for Type, Instance and This."""
518 """A traitlet with error reporting for Type, Instance and This."""
519
519
520 def error(self, obj, value):
520 def error(self, obj, value):
521 kind = type(value)
521 kind = type(value)
522 if kind is InstanceType:
522 if kind is InstanceType:
523 msg = 'class %s' % value.__class__.__name__
523 msg = 'class %s' % value.__class__.__name__
524 else:
524 else:
525 msg = '%s (i.e. %s)' % ( str( kind )[1:-1], repr( value ) )
525 msg = '%s (i.e. %s)' % ( str( kind )[1:-1], repr( value ) )
526
526
527 super(ClassBasedTraitletType, self).error(obj, msg)
527 super(ClassBasedTraitletType, self).error(obj, msg)
528
528
529
529
530 class Type(ClassBasedTraitletType):
530 class Type(ClassBasedTraitletType):
531 """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."""
532
532
533 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 ):
534 """Construct a Type traitlet
534 """Construct a Type traitlet
535
535
536 A Type traitlet specifies that its values must be subclasses of
536 A Type traitlet specifies that its values must be subclasses of
537 a particular class.
537 a particular class.
538
538
539 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
540 well.
540 well.
541
541
542 Parameters
542 Parameters
543 ----------
543 ----------
544 default_value : class, str or None
544 default_value : class, str or None
545 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,
546 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'.
547 The string is resolved into real class, when the parent
547 The string is resolved into real class, when the parent
548 :class:`HasTraitlets` class is instantiated.
548 :class:`HasTraitlets` class is instantiated.
549 klass : class, str, None
549 klass : class, str, None
550 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
551 may be specified in a string like: 'foo.bar.MyClass'.
551 may be specified in a string like: 'foo.bar.MyClass'.
552 The string is resolved into real class, when the parent
552 The string is resolved into real class, when the parent
553 :class:`HasTraitlets` class is instantiated.
553 :class:`HasTraitlets` class is instantiated.
554 allow_none : boolean
554 allow_none : boolean
555 Indicates whether None is allowed as an assignable value. Even if
555 Indicates whether None is allowed as an assignable value. Even if
556 ``False``, the default value may be ``None``.
556 ``False``, the default value may be ``None``.
557 """
557 """
558 if default_value is None:
558 if default_value is None:
559 if klass is None:
559 if klass is None:
560 klass = object
560 klass = object
561 elif klass is None:
561 elif klass is None:
562 klass = default_value
562 klass = default_value
563
563
564 if not (inspect.isclass(klass) or isinstance(klass, basestring)):
564 if not (inspect.isclass(klass) or isinstance(klass, basestring)):
565 raise TraitletError("A Type traitlet must specify a class.")
565 raise TraitletError("A Type traitlet must specify a class.")
566
566
567 self.klass = klass
567 self.klass = klass
568 self._allow_none = allow_none
568 self._allow_none = allow_none
569
569
570 super(Type, self).__init__(default_value, **metadata)
570 super(Type, self).__init__(default_value, **metadata)
571
571
572 def validate(self, obj, value):
572 def validate(self, obj, value):
573 """Validates that the value is a valid object instance."""
573 """Validates that the value is a valid object instance."""
574 try:
574 try:
575 if issubclass(value, self.klass):
575 if issubclass(value, self.klass):
576 return value
576 return value
577 except:
577 except:
578 if (value is None) and (self._allow_none):
578 if (value is None) and (self._allow_none):
579 return value
579 return value
580
580
581 self.error(obj, value)
581 self.error(obj, value)
582
582
583 def info(self):
583 def info(self):
584 """ Returns a description of the trait."""
584 """ Returns a description of the trait."""
585 if isinstance(self.klass, basestring):
585 if isinstance(self.klass, basestring):
586 klass = self.klass
586 klass = self.klass
587 else:
587 else:
588 klass = self.klass.__name__
588 klass = self.klass.__name__
589 result = 'a subclass of ' + klass
589 result = 'a subclass of ' + klass
590 if self._allow_none:
590 if self._allow_none:
591 return result + ' or None'
591 return result + ' or None'
592 return result
592 return result
593
593
594 def instance_init(self, obj):
594 def instance_init(self, obj):
595 self._resolve_classes()
595 self._resolve_classes()
596 super(Type, self).instance_init(obj)
596 super(Type, self).instance_init(obj)
597
597
598 def _resolve_classes(self):
598 def _resolve_classes(self):
599 if isinstance(self.klass, basestring):
599 if isinstance(self.klass, basestring):
600 self.klass = import_item(self.klass)
600 self.klass = import_item(self.klass)
601 if isinstance(self.default_value, basestring):
601 if isinstance(self.default_value, basestring):
602 self.default_value = import_item(self.default_value)
602 self.default_value = import_item(self.default_value)
603
603
604 def get_default_value(self):
604 def get_default_value(self):
605 return self.default_value
605 return self.default_value
606
606
607
607
608 class DefaultValueGenerator(object):
608 class DefaultValueGenerator(object):
609 """A class for generating new default value instances."""
609 """A class for generating new default value instances."""
610
610
611 def __init__(self, *args, **kw):
611 def __init__(self, *args, **kw):
612 self.args = args
612 self.args = args
613 self.kw = kw
613 self.kw = kw
614
614
615 def generate(self, klass):
615 def generate(self, klass):
616 return klass(*self.args, **self.kw)
616 return klass(*self.args, **self.kw)
617
617
618
618
619 class Instance(ClassBasedTraitletType):
619 class Instance(ClassBasedTraitletType):
620 """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.
621
621
622 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.
623 """
623 """
624
624
625 def __init__(self, klass=None, args=None, kw=None,
625 def __init__(self, klass=None, args=None, kw=None,
626 allow_none=True, **metadata ):
626 allow_none=True, **metadata ):
627 """Construct an Instance traitlet.
627 """Construct an Instance traitlet.
628
628
629 This traitlet allows values that are instances of a particular
629 This traitlet allows values that are instances of a particular
630 class or its sublclasses. Our implementation is quite different
630 class or its sublclasses. Our implementation is quite different
631 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
632 for klass and we handle the ``args`` and ``kw`` arguments differently.
632 for klass and we handle the ``args`` and ``kw`` arguments differently.
633
633
634 Parameters
634 Parameters
635 ----------
635 ----------
636 klass : class, str
636 klass : class, str
637 The class that forms the basis for the traitlet. Class names
637 The class that forms the basis for the traitlet. Class names
638 can also be specified as strings, like 'foo.bar.Bar'.
638 can also be specified as strings, like 'foo.bar.Bar'.
639 args : tuple
639 args : tuple
640 Positional arguments for generating the default value.
640 Positional arguments for generating the default value.
641 kw : dict
641 kw : dict
642 Keyword arguments for generating the default value.
642 Keyword arguments for generating the default value.
643 allow_none : bool
643 allow_none : bool
644 Indicates whether None is allowed as a value.
644 Indicates whether None is allowed as a value.
645
645
646 Default Value
646 Default Value
647 -------------
647 -------------
648 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.
649 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
650 created as ``klass(*args, **kw)``. If either ``args`` or ``kw`` is
650 created as ``klass(*args, **kw)``. If either ``args`` or ``kw`` is
651 not (but not both), None is replace by ``()`` or ``{}``.
651 not (but not both), None is replace by ``()`` or ``{}``.
652 """
652 """
653
653
654 self._allow_none = allow_none
654 self._allow_none = allow_none
655
655
656 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))):
657 raise TraitletError('The klass argument must be a class'
657 raise TraitletError('The klass argument must be a class'
658 ' you gave: %r' % klass)
658 ' you gave: %r' % klass)
659 self.klass = klass
659 self.klass = klass
660
660
661 # self.klass is a class, so handle default_value
661 # self.klass is a class, so handle default_value
662 if args is None and kw is None:
662 if args is None and kw is None:
663 default_value = None
663 default_value = None
664 else:
664 else:
665 if args is None:
665 if args is None:
666 # kw is not None
666 # kw is not None
667 args = ()
667 args = ()
668 elif kw is None:
668 elif kw is None:
669 # args is not None
669 # args is not None
670 kw = {}
670 kw = {}
671
671
672 if not isinstance(kw, dict):
672 if not isinstance(kw, dict):
673 raise TraitletError("The 'kw' argument must be a dict or None.")
673 raise TraitletError("The 'kw' argument must be a dict or None.")
674 if not isinstance(args, tuple):
674 if not isinstance(args, tuple):
675 raise TraitletError("The 'args' argument must be a tuple or None.")
675 raise TraitletError("The 'args' argument must be a tuple or None.")
676
676
677 default_value = DefaultValueGenerator(*args, **kw)
677 default_value = DefaultValueGenerator(*args, **kw)
678
678
679 super(Instance, self).__init__(default_value, **metadata)
679 super(Instance, self).__init__(default_value, **metadata)
680
680
681 def validate(self, obj, value):
681 def validate(self, obj, value):
682 if value is None:
682 if value is None:
683 if self._allow_none:
683 if self._allow_none:
684 return value
684 return value
685 self.error(obj, value)
685 self.error(obj, value)
686
686
687 if isinstance(value, self.klass):
687 if isinstance(value, self.klass):
688 return value
688 return value
689 else:
689 else:
690 self.error(obj, value)
690 self.error(obj, value)
691
691
692 def info(self):
692 def info(self):
693 if isinstance(self.klass, basestring):
693 if isinstance(self.klass, basestring):
694 klass = self.klass
694 klass = self.klass
695 else:
695 else:
696 klass = self.klass.__name__
696 klass = self.klass.__name__
697 result = class_of(klass)
697 result = class_of(klass)
698 if self._allow_none:
698 if self._allow_none:
699 return result + ' or None'
699 return result + ' or None'
700
700
701 return result
701 return result
702
702
703 def instance_init(self, obj):
703 def instance_init(self, obj):
704 self._resolve_classes()
704 self._resolve_classes()
705 super(Instance, self).instance_init(obj)
705 super(Instance, self).instance_init(obj)
706
706
707 def _resolve_classes(self):
707 def _resolve_classes(self):
708 if isinstance(self.klass, basestring):
708 if isinstance(self.klass, basestring):
709 self.klass = import_item(self.klass)
709 self.klass = import_item(self.klass)
710
710
711 def get_default_value(self):
711 def get_default_value(self):
712 """Instantiate a default value instance.
712 """Instantiate a default value instance.
713
713
714 This is called when the containing HasTraitlets classes'
714 This is called when the containing HasTraitlets classes'
715 :meth:`__new__` method is called to ensure that a unique instance
715 :meth:`__new__` method is called to ensure that a unique instance
716 is created for each HasTraitlets instance.
716 is created for each HasTraitlets instance.
717 """
717 """
718 dv = self.default_value
718 dv = self.default_value
719 if isinstance(dv, DefaultValueGenerator):
719 if isinstance(dv, DefaultValueGenerator):
720 return dv.generate(self.klass)
720 return dv.generate(self.klass)
721 else:
721 else:
722 return dv
722 return dv
723
723
724
724
725 class This(ClassBasedTraitletType):
725 class This(ClassBasedTraitletType):
726 """A traitlet for instances of the class containing this trait.
726 """A traitlet for instances of the class containing this trait.
727
727
728 Because how how and when class bodies are executed, the ``This``
728 Because how how and when class bodies are executed, the ``This``
729 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
730 always validate default values, ``allow_none`` is *always* true.
730 always validate default values, ``allow_none`` is *always* true.
731 """
731 """
732
732
733 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'
734
734
735 def __init__(self, **metadata):
735 def __init__(self, **metadata):
736 super(This, self).__init__(None, **metadata)
736 super(This, self).__init__(None, **metadata)
737
737
738 def validate(self, obj, value):
738 def validate(self, obj, value):
739 # What if value is a superclass of obj.__class__? This is
739 # What if value is a superclass of obj.__class__? This is
740 # complicated if it was the superclass that defined the This
740 # complicated if it was the superclass that defined the This
741 # traitlet.
741 # traitlet.
742 if isinstance(value, self.this_class) or (value is None):
742 if isinstance(value, self.this_class) or (value is None):
743 return value
743 return value
744 else:
744 else:
745 self.error(obj, value)
745 self.error(obj, value)
746
746
747
747
748 #-----------------------------------------------------------------------------
748 #-----------------------------------------------------------------------------
749 # Basic TraitletTypes implementations/subclasses
749 # Basic TraitletTypes implementations/subclasses
750 #-----------------------------------------------------------------------------
750 #-----------------------------------------------------------------------------
751
751
752
752
753 class Any(TraitletType):
753 class Any(TraitletType):
754 default_value = None
754 default_value = None
755 info_text = 'any value'
755 info_text = 'any value'
756
756
757
757
758 class Int(TraitletType):
758 class Int(TraitletType):
759 """A integer traitlet."""
759 """A integer traitlet."""
760
760
761 evaluate = int
761 evaluate = int
762 default_value = 0
762 default_value = 0
763 info_text = 'an integer'
763 info_text = 'an integer'
764
764
765 def validate(self, obj, value):
765 def validate(self, obj, value):
766 if isinstance(value, int):
766 if isinstance(value, int):
767 return value
767 return value
768 self.error(obj, value)
768 self.error(obj, value)
769
769
770 class CInt(Int):
770 class CInt(Int):
771 """A casting version of the int traitlet."""
771 """A casting version of the int traitlet."""
772
772
773 def validate(self, obj, value):
773 def validate(self, obj, value):
774 try:
774 try:
775 return int(value)
775 return int(value)
776 except:
776 except:
777 self.error(obj, value)
777 self.error(obj, value)
778
778
779
779
780 class Long(TraitletType):
780 class Long(TraitletType):
781 """A long integer traitlet."""
781 """A long integer traitlet."""
782
782
783 evaluate = long
783 evaluate = long
784 default_value = 0L
784 default_value = 0L
785 info_text = 'a long'
785 info_text = 'a long'
786
786
787 def validate(self, obj, value):
787 def validate(self, obj, value):
788 if isinstance(value, long):
788 if isinstance(value, long):
789 return value
789 return value
790 if isinstance(value, int):
790 if isinstance(value, int):
791 return long(value)
791 return long(value)
792 self.error(obj, value)
792 self.error(obj, value)
793
793
794
794
795 class CLong(Long):
795 class CLong(Long):
796 """A casting version of the long integer traitlet."""
796 """A casting version of the long integer traitlet."""
797
797
798 def validate(self, obj, value):
798 def validate(self, obj, value):
799 try:
799 try:
800 return long(value)
800 return long(value)
801 except:
801 except:
802 self.error(obj, value)
802 self.error(obj, value)
803
803
804
804
805 class Float(TraitletType):
805 class Float(TraitletType):
806 """A float traitlet."""
806 """A float traitlet."""
807
807
808 evaluate = float
808 evaluate = float
809 default_value = 0.0
809 default_value = 0.0
810 info_text = 'a float'
810 info_text = 'a float'
811
811
812 def validate(self, obj, value):
812 def validate(self, obj, value):
813 if isinstance(value, float):
813 if isinstance(value, float):
814 return value
814 return value
815 if isinstance(value, int):
815 if isinstance(value, int):
816 return float(value)
816 return float(value)
817 self.error(obj, value)
817 self.error(obj, value)
818
818
819
819
820 class CFloat(Float):
820 class CFloat(Float):
821 """A casting version of the float traitlet."""
821 """A casting version of the float traitlet."""
822
822
823 def validate(self, obj, value):
823 def validate(self, obj, value):
824 try:
824 try:
825 return float(value)
825 return float(value)
826 except:
826 except:
827 self.error(obj, value)
827 self.error(obj, value)
828
828
829 class Complex(TraitletType):
829 class Complex(TraitletType):
830 """A traitlet for complex numbers."""
830 """A traitlet for complex numbers."""
831
831
832 evaluate = complex
832 evaluate = complex
833 default_value = 0.0 + 0.0j
833 default_value = 0.0 + 0.0j
834 info_text = 'a complex number'
834 info_text = 'a complex number'
835
835
836 def validate(self, obj, value):
836 def validate(self, obj, value):
837 if isinstance(value, complex):
837 if isinstance(value, complex):
838 return value
838 return value
839 if isinstance(value, (float, int)):
839 if isinstance(value, (float, int)):
840 return complex(value)
840 return complex(value)
841 self.error(obj, value)
841 self.error(obj, value)
842
842
843
843
844 class CComplex(Complex):
844 class CComplex(Complex):
845 """A casting version of the complex number traitlet."""
845 """A casting version of the complex number traitlet."""
846
846
847 def validate (self, obj, value):
847 def validate (self, obj, value):
848 try:
848 try:
849 return complex(value)
849 return complex(value)
850 except:
850 except:
851 self.error(obj, value)
851 self.error(obj, value)
852
852
853
853
854 class Str(TraitletType):
854 class Str(TraitletType):
855 """A traitlet for strings."""
855 """A traitlet for strings."""
856
856
857 evaluate = lambda x: x
857 evaluate = lambda x: x
858 default_value = ''
858 default_value = ''
859 info_text = 'a string'
859 info_text = 'a string'
860
860
861 def validate(self, obj, value):
861 def validate(self, obj, value):
862 if isinstance(value, str):
862 if isinstance(value, str):
863 return value
863 return value
864 self.error(obj, value)
864 self.error(obj, value)
865
865
866
866
867 class CStr(Str):
867 class CStr(Str):
868 """A casting version of the string traitlet."""
868 """A casting version of the string traitlet."""
869
869
870 def validate(self, obj, value):
870 def validate(self, obj, value):
871 try:
871 try:
872 return str(value)
872 return str(value)
873 except:
873 except:
874 try:
874 try:
875 return unicode(value)
875 return unicode(value)
876 except:
876 except:
877 self.error(obj, value)
877 self.error(obj, value)
878
878
879
879
880 class Unicode(TraitletType):
880 class Unicode(TraitletType):
881 """A traitlet for unicode strings."""
881 """A traitlet for unicode strings."""
882
882
883 evaluate = unicode
883 evaluate = unicode
884 default_value = u''
884 default_value = u''
885 info_text = 'a unicode string'
885 info_text = 'a unicode string'
886
886
887 def validate(self, obj, value):
887 def validate(self, obj, value):
888 if isinstance(value, unicode):
888 if isinstance(value, unicode):
889 return value
889 return value
890 if isinstance(value, str):
890 if isinstance(value, str):
891 return unicode(value)
891 return unicode(value)
892 self.error(obj, value)
892 self.error(obj, value)
893
893
894
894
895 class CUnicode(Unicode):
895 class CUnicode(Unicode):
896 """A casting version of the unicode traitlet."""
896 """A casting version of the unicode traitlet."""
897
897
898 def validate(self, obj, value):
898 def validate(self, obj, value):
899 try:
899 try:
900 return unicode(value)
900 return unicode(value)
901 except:
901 except:
902 self.error(obj, value)
902 self.error(obj, value)
903
903
904
904
905 class Bool(TraitletType):
905 class Bool(TraitletType):
906 """A boolean (True, False) traitlet."""
906 """A boolean (True, False) traitlet."""
907 evaluate = bool
907 evaluate = bool
908 default_value = False
908 default_value = False
909 info_text = 'a boolean'
909 info_text = 'a boolean'
910
910
911 def validate(self, obj, value):
911 def validate(self, obj, value):
912 if isinstance(value, bool):
912 if isinstance(value, bool):
913 return value
913 return value
914 self.error(obj, value)
914 self.error(obj, value)
915
915
916
916
917 class CBool(Bool):
917 class CBool(Bool):
918 """A casting version of the boolean traitlet."""
918 """A casting version of the boolean traitlet."""
919
919
920 def validate(self, obj, value):
920 def validate(self, obj, value):
921 try:
921 try:
922 return bool(value)
922 return bool(value)
923 except:
923 except:
924 self.error(obj, value)
924 self.error(obj, value)
925
925
926
926
927 class Enum(TraitletType):
927 class Enum(TraitletType):
928 """An enum that whose value must be in a given sequence."""
928 """An enum that whose value must be in a given sequence."""
929
929
930 def __init__(self, values, default_value=None, allow_none=True, **metadata):
930 def __init__(self, values, default_value=None, allow_none=True, **metadata):
931 self.values = values
931 self.values = values
932 self._allow_none = allow_none
932 self._allow_none = allow_none
933 super(Enum, self).__init__(default_value, **metadata)
933 super(Enum, self).__init__(default_value, **metadata)
934
934
935 def validate(self, obj, value):
935 def validate(self, obj, value):
936 if value is None:
936 if value is None:
937 if self._allow_none:
937 if self._allow_none:
938 return value
938 return value
939
939
940 if value in self.values:
940 if value in self.values:
941 return value
941 return value
942 self.error(obj, value)
942 self.error(obj, value)
943
943
944 def info(self):
944 def info(self):
945 """ Returns a description of the trait."""
945 """ Returns a description of the trait."""
946 result = 'any of ' + repr(self.values)
946 result = 'any of ' + repr(self.values)
947 if self._allow_none:
947 if self._allow_none:
948 return result + ' or None'
948 return result + ' or None'
949 return result
949 return result
950
950
951 class CaselessStrEnum(Enum):
951 class CaselessStrEnum(Enum):
952 """An enum of strings that are caseless in validate."""
952 """An enum of strings that are caseless in validate."""
953
953
954 def validate(self, obj, value):
954 def validate(self, obj, value):
955 if value is None:
955 if value is None:
956 if self._allow_none:
956 if self._allow_none:
957 return value
957 return value
958
958
959 if not isinstance(value, str):
959 if not isinstance(value, str):
960 self.error(obj, value)
960 self.error(obj, value)
961
961
962 for v in self.values:
962 for v in self.values:
963 if v.lower() == value.lower():
963 if v.lower() == value.lower():
964 return v
964 return v
965 self.error(obj, value)
965 self.error(obj, value)
966
966
967
967
968 class List(Instance):
968 class List(Instance):
969 """An instance of a Python list."""
969 """An instance of a Python list."""
970
970
971 def __init__(self, default_value=None, allow_none=True, **metadata):
971 def __init__(self, default_value=None, allow_none=True, **metadata):
972 """Create a list traitlet type from a list or tuple.
972 """Create a list traitlet type from a list or tuple.
973
973
974 The default value is created by doing ``list(default_value)``,
974 The default value is created by doing ``list(default_value)``,
975 which creates a copy of the ``default_value``.
975 which creates a copy of the ``default_value``.
976 """
976 """
977 if default_value is None:
977 if default_value is None:
978 args = ((),)
978 args = ((),)
979 elif isinstance(default_value, SequenceTypes):
979 elif isinstance(default_value, SequenceTypes):
980 args = (default_value,)
980 args = (default_value,)
981 else:
982 raise TypeError('default value of List was %s' % default_value)
981
983
982 super(List,self).__init__(klass=list, args=args,
984 super(List,self).__init__(klass=list, args=args,
983 allow_none=allow_none, **metadata)
985 allow_none=allow_none, **metadata)
General Comments 0
You need to be logged in to leave comments. Login now