##// END OF EJS Templates
Added casting versions of all the basic traitlet types.
Brian Granger -
Show More
@@ -1,752 +1,828 b''
1 1 #!/usr/bin/env python
2 2 # encoding: utf-8
3 3 """
4 4 A lightweight Traits like module.
5 5
6 6 This is designed to provide a lightweight, simple, pure Python version of
7 7 many of the capabilities of enthought.traits. This includes:
8 8
9 9 * Validation
10 10 * Type specification with defaults
11 11 * Static and dynamic notification
12 12 * Basic predefined types
13 13 * An API that is similar to enthought.traits
14 14
15 15 We don't support:
16 16
17 17 * Delegation
18 18 * Automatic GUI generation
19 19 * A full set of trait types
20 20 * API compatibility with enthought.traits
21 21
22 22 We choose to create this module because we need these capabilities, but
23 23 we need them to be pure Python so they work in all Python implementations,
24 24 including Jython and IronPython.
25 25
26 26 Authors:
27 27
28 28 * Brian Granger
29 29 * Enthought, Inc. Some of the code in this file comes from enthought.traits
30 30 and is licensed under the BSD license. Also, many of the ideas also come
31 31 from enthought.traits even though our implementation is very different.
32 32 """
33 33
34 34 #-----------------------------------------------------------------------------
35 35 # Copyright (C) 2008-2009 The IPython Development Team
36 36 #
37 37 # Distributed under the terms of the BSD License. The full license is in
38 38 # the file COPYING, distributed as part of this software.
39 39 #-----------------------------------------------------------------------------
40 40
41 41 #-----------------------------------------------------------------------------
42 42 # Imports
43 43 #-----------------------------------------------------------------------------
44 44
45 45
46 46 import inspect
47 47 import sys
48 48 import types
49 49 from types import InstanceType, ClassType
50 50
51 51 ClassTypes = (ClassType, type)
52 52
53 53 #-----------------------------------------------------------------------------
54 54 # Basic classes
55 55 #-----------------------------------------------------------------------------
56 56
57 57
58 58 class NoDefaultSpecified ( object ): pass
59 59 NoDefaultSpecified = NoDefaultSpecified()
60 60
61 61
62 62 class Undefined ( object ): pass
63 63 Undefined = Undefined()
64 64
65 65
66 66 class TraitletError(Exception):
67 67 pass
68 68
69 69
70 70 #-----------------------------------------------------------------------------
71 71 # Utilities
72 72 #-----------------------------------------------------------------------------
73 73
74 74
75 75 def class_of ( object ):
76 76 """ Returns a string containing the class name of an object with the
77 77 correct indefinite article ('a' or 'an') preceding it (e.g., 'an Image',
78 78 'a PlotValue').
79 79 """
80 80 if isinstance( object, basestring ):
81 81 return add_article( object )
82 82
83 83 return add_article( object.__class__.__name__ )
84 84
85 85
86 86 def add_article ( name ):
87 87 """ Returns a string containing the correct indefinite article ('a' or 'an')
88 88 prefixed to the specified string.
89 89 """
90 90 if name[:1].lower() in 'aeiou':
91 91 return 'an ' + name
92 92
93 93 return 'a ' + name
94 94
95 95
96 96 def repr_type(obj):
97 97 """ Return a string representation of a value and its type for readable
98 98 error messages.
99 99 """
100 100 the_type = type(obj)
101 101 if the_type is InstanceType:
102 102 # Old-style class.
103 103 the_type = obj.__class__
104 104 msg = '%r %r' % (obj, the_type)
105 105 return msg
106 106
107 107
108 108 def parse_notifier_name(name):
109 109 """Convert the name argument to a list of names.
110 110
111 111 Examples
112 112 --------
113 113
114 114 >>> parse_notifier_name('a')
115 115 ['a']
116 116 >>> parse_notifier_name(['a','b'])
117 117 ['a', 'b']
118 118 >>> parse_notifier_name(None)
119 119 ['anytraitlet']
120 120 """
121 121 if isinstance(name, str):
122 122 return [name]
123 123 elif name is None:
124 124 return ['anytraitlet']
125 125 elif isinstance(name, (list, tuple)):
126 126 for n in name:
127 127 assert isinstance(n, str), "names must be strings"
128 128 return name
129 129
130 130
131 131 def get_module_name ( level = 2 ):
132 132 """ Returns the name of the module that the caller's caller is located in.
133 133 """
134 134 return sys._getframe( level ).f_globals.get( '__name__', '__main__' )
135 135
136 136
137 137 #-----------------------------------------------------------------------------
138 138 # Base TraitletType for all traitlets
139 139 #-----------------------------------------------------------------------------
140 140
141 141
142 142 class TraitletType(object):
143 143
144 144 metadata = {}
145 145 default_value = Undefined
146 146 info_text = 'any value'
147 147
148 148 def __init__(self, default_value=NoDefaultSpecified, **metadata):
149 149 """Create a TraitletType.
150 150 """
151 151 if default_value is not NoDefaultSpecified:
152 152 self.default_value = default_value
153 153 self.metadata.update(metadata)
154 154 self.init()
155 155
156 156 def init(self):
157 157 pass
158 158
159 159 def get_default_value(self):
160 160 """Create a new instance of the default value."""
161 161 dv = self.default_value
162 162 return dv
163 163
164 164 def __get__(self, obj, cls=None):
165 165 """Get the value of the traitlet by self.name for the instance.
166 166
167 167 The creation of default values is deferred until this is called the
168 168 first time. This is done so instances of the parent HasTraitlets
169 169 will have their own default value instances.
170 170 """
171 171 if obj is None:
172 172 return self
173 173 else:
174 174 if not obj._traitlet_values.has_key(self.name):
175 175 dv = self.get_default_value()
176 176 self.__set__(obj, dv, first=True)
177 177 return dv
178 178 else:
179 179 return obj._traitlet_values[self.name]
180 180
181 181 def __set__(self, obj, value, first=False):
182 182 new_value = self._validate(obj, value)
183 183 if not first:
184 184 old_value = self.__get__(obj)
185 185 if old_value != new_value:
186 186 obj._traitlet_values[self.name] = new_value
187 187 obj._notify(self.name, old_value, new_value)
188 188 else:
189 189 obj._traitlet_values[self.name] = new_value
190 190
191 191 def _validate(self, obj, value):
192 192 if hasattr(self, 'validate'):
193 193 return self.validate(obj, value)
194 194 elif hasattr(self, 'is_valid_for'):
195 195 valid = self.is_valid_for(value)
196 196 if valid:
197 197 return value
198 198 else:
199 199 raise TraitletError('invalid value for type: %r' % value)
200 200 elif hasattr(self, 'value_for'):
201 201 return self.value_for(value)
202 202 else:
203 203 return value
204 204
205 205 def info(self):
206 206 return self.info_text
207 207
208 208 def error(self, obj, value):
209 209 if obj is not None:
210 210 e = "The '%s' traitlet of %s instance must be %s, but a value of %s was specified." \
211 211 % (self.name, class_of(obj),
212 212 self.info(), repr_type(value))
213 213 else:
214 214 e = "The '%s' traitlet must be %s, but a value of %r was specified." \
215 215 % (self.name, self.info(), repr_type(value))
216 216 raise TraitletError(e)
217 217
218 218
219 219 #-----------------------------------------------------------------------------
220 220 # The HasTraitlets implementation
221 221 #-----------------------------------------------------------------------------
222 222
223 223
224 224 class MetaHasTraitlets(type):
225 225 """A metaclass for HasTraitlets.
226 226
227 227 This metaclass makes sure that any TraitletType class attributes are
228 228 instantiated and sets their name attribute.
229 229 """
230 230
231 231 def __new__(mcls, name, bases, classdict):
232 232 for k,v in classdict.iteritems():
233 233 if isinstance(v, TraitletType):
234 234 v.name = k
235 235 elif inspect.isclass(v):
236 236 if issubclass(v, TraitletType):
237 237 vinst = v()
238 238 vinst.name = k
239 239 classdict[k] = vinst
240 240 return super(MetaHasTraitlets, mcls).__new__(mcls, name, bases, classdict)
241 241
242 242
243 243 class HasTraitlets(object):
244 244
245 245 __metaclass__ = MetaHasTraitlets
246 246
247 247 def __init__(self):
248 248 self._traitlet_values = {}
249 249 self._traitlet_notifiers = {}
250 250
251 251 def _notify(self, name, old_value, new_value):
252 252
253 253 # First dynamic ones
254 254 callables = self._traitlet_notifiers.get(name,[])
255 255 more_callables = self._traitlet_notifiers.get('anytraitlet',[])
256 256 callables.extend(more_callables)
257 257
258 258 # Now static ones
259 259 try:
260 260 cb = getattr(self, '_%s_changed' % name)
261 261 except:
262 262 pass
263 263 else:
264 264 callables.append(cb)
265 265
266 266 # Call them all now
267 267 for c in callables:
268 268 # Traits catches and logs errors here. I allow them to raise
269 269 if callable(c):
270 270 argspec = inspect.getargspec(c)
271 271 nargs = len(argspec[0])
272 272 # Bound methods have an additional 'self' argument
273 273 # I don't know how to treat unbound methods, but they
274 274 # can't really be used for callbacks.
275 275 if isinstance(c, types.MethodType):
276 276 offset = -1
277 277 else:
278 278 offset = 0
279 279 if nargs + offset == 0:
280 280 c()
281 281 elif nargs + offset == 1:
282 282 c(name)
283 283 elif nargs + offset == 2:
284 284 c(name, new_value)
285 285 elif nargs + offset == 3:
286 286 c(name, old_value, new_value)
287 287 else:
288 288 raise TraitletError('a traitlet changed callback '
289 289 'must have 0-3 arguments.')
290 290 else:
291 291 raise TraitletError('a traitlet changed callback '
292 292 'must be callable.')
293 293
294 294
295 295 def _add_notifiers(self, handler, name):
296 296 if not self._traitlet_notifiers.has_key(name):
297 297 nlist = []
298 298 self._traitlet_notifiers[name] = nlist
299 299 else:
300 300 nlist = self._traitlet_notifiers[name]
301 301 if handler not in nlist:
302 302 nlist.append(handler)
303 303
304 304 def _remove_notifiers(self, handler, name):
305 305 if self._traitlet_notifiers.has_key(name):
306 306 nlist = self._traitlet_notifiers[name]
307 307 try:
308 308 index = nlist.index(handler)
309 309 except ValueError:
310 310 pass
311 311 else:
312 312 del nlist[index]
313 313
314 314 def on_traitlet_change(self, handler, name=None, remove=False):
315 315 """Setup a handler to be called when a traitlet changes.
316 316
317 317 This is used to setup dynamic notifications of traitlet changes.
318 318
319 319 Static handlers can be created by creating methods on a HasTraitlets
320 320 subclass with the naming convention '_[traitletname]_changed'. Thus,
321 321 to create static handler for the traitlet 'a', create the method
322 322 _a_changed(self, name, old, new) (fewer arguments can be used, see
323 323 below).
324 324
325 325 Parameters
326 326 ----------
327 327 handler : callable
328 328 A callable that is called when a traitlet changes. Its
329 329 signature can be handler(), handler(name), handler(name, new)
330 330 or handler(name, old, new).
331 331 name : list, str, None
332 332 If None, the handler will apply to all traitlets. If a list
333 333 of str, handler will apply to all names in the list. If a
334 334 str, the handler will apply just to that name.
335 335 remove : bool
336 336 If False (the default), then install the handler. If True
337 337 then unintall it.
338 338 """
339 339 if remove:
340 340 names = parse_notifier_name(name)
341 341 for n in names:
342 342 self._remove_notifiers(handler, n)
343 343 else:
344 344 names = parse_notifier_name(name)
345 345 for n in names:
346 346 self._add_notifiers(handler, n)
347 347
348 348 def _add_class_traitlet(self, name, traitlet):
349 349 """Add a class-level traitlet.
350 350
351 351 This create a new traitlet attached to all instances of this class.
352 352 But, the value can be different on each instance. But, this behavior
353 353 is likely to trip up many folks as they would expect the traitlet
354 354 type to be different on each instance.
355 355
356 356 Parameters
357 357 ----------
358 358 name : str
359 359 The name of the traitlet.
360 360 traitlet : TraitletType or an instance of one
361 361 The traitlet to assign to the name.
362 362 """
363 363 if inspect.isclass(traitlet):
364 364 inst = traitlet()
365 365 else:
366 366 inst = traitlet
367 367 assert isinstance(inst, TraitletType)
368 368 inst.name = name
369 369 setattr(self.__class__, name, inst)
370 370
371 371
372 372 #-----------------------------------------------------------------------------
373 373 # Actual TraitletTypes implementations/subclasses
374 374 #-----------------------------------------------------------------------------
375 375
376 376 #-----------------------------------------------------------------------------
377 377 # TraitletTypes subclasses for handling classes and instances of classes
378 378 #-----------------------------------------------------------------------------
379 379
380 380
381 381 class BaseClassResolver(TraitletType):
382 382 """Mixin class for traitlets that need to resolve classes by strings.
383 383
384 384 This class provides is a mixin that provides its subclasses with the
385 385 ability to resolve classes by specifying a string name (for example,
386 386 'foo.bar.MyClass'). An actual class can also be resolved.
387 387
388 388 Any subclass must define instances with 'klass' and 'module' attributes
389 389 that contain the string name of the class (or actual class object) and
390 390 the module name that contained the original trait definition (used for
391 391 resolving local class names (e.g. 'LocalClass')).
392 392 """
393 393
394 394 def resolve_class(self, obj, value):
395 395 klass = self.validate_class(self.find_class(self.klass))
396 396 if klass is None:
397 397 self.validate_failed(obj, value)
398 398
399 399 self.klass = klass
400 400
401 401 def validate_class(self, klass):
402 402 return klass
403 403
404 404 def find_class(self, klass):
405 405 module = self.module
406 406 col = klass.rfind('.')
407 407 if col >= 0:
408 408 module = klass[ : col ]
409 409 klass = klass[ col + 1: ]
410 410
411 411 theClass = getattr(sys.modules.get(module), klass, None)
412 412 if (theClass is None) and (col >= 0):
413 413 try:
414 414 mod = __import__(module)
415 415 for component in module.split( '.' )[1:]:
416 416 mod = getattr(mod, component)
417 417
418 418 theClass = getattr(mod, klass, None)
419 419 except:
420 420 pass
421 421
422 422 return theClass
423 423
424 424 def validate_failed (self, obj, value):
425 425 kind = type(value)
426 426 if kind is InstanceType:
427 427 msg = 'class %s' % value.__class__.__name__
428 428 else:
429 429 msg = '%s (i.e. %s)' % ( str( kind )[1:-1], repr( value ) )
430 430
431 431 self.error(obj, msg)
432 432
433 433
434 434 class Type(BaseClassResolver):
435 435 """A traitlet whose value must be a subclass of a specified class."""
436 436
437 437 def __init__ (self, default_value=None, klass=None, allow_none=True, **metadata ):
438 438 """Construct a Type traitlet
439 439
440 440 A Type traitlet specifies that its values must be subclasses of
441 441 a particular class.
442 442
443 443 Parameters
444 444 ----------
445 445 default_value : class or None
446 446 The default value must be a subclass of klass.
447 447 klass : class, str, None
448 448 Values of this traitlet must be a subclass of klass. The klass
449 449 may be specified in a string like: 'foo.bar.MyClass'.
450 450 allow_none : boolean
451 451 Indicates whether None is allowed as an assignable value. Even if
452 452 ``False``, the default value may be ``None``.
453 453 """
454 454 if default_value is None:
455 455 if klass is None:
456 456 klass = object
457 457 elif klass is None:
458 458 klass = default_value
459 459
460 460 if isinstance(klass, basestring):
461 461 self.validate = self.resolve
462 462 elif not isinstance(klass, ClassTypes):
463 463 raise TraitletError("A Type traitlet must specify a class.")
464 464
465 465 self.klass = klass
466 466 self._allow_none = allow_none
467 467 self.module = get_module_name()
468 468
469 469 super(Type, self).__init__(default_value, **metadata)
470 470
471 471 def validate(self, obj, value):
472 472 """Validates that the value is a valid object instance."""
473 473 try:
474 474 if issubclass(value, self.klass):
475 475 return value
476 476 except:
477 477 if (value is None) and (self._allow_none):
478 478 return value
479 479
480 480 self.error(obj, value)
481 481
482 482 def resolve(self, obj, name, value):
483 483 """ Resolves a class originally specified as a string into an actual
484 484 class, then resets the trait so that future calls will be handled by
485 485 the normal validate method.
486 486 """
487 487 if isinstance(self.klass, basestring):
488 488 self.resolve_class(obj, value)
489 489 del self.validate
490 490
491 491 return self.validate(obj, value)
492 492
493 493 def info(self):
494 494 """ Returns a description of the trait."""
495 495 klass = self.klass
496 496 if not isinstance(klass, basestring):
497 497 klass = klass.__name__
498 498
499 499 result = 'a subclass of ' + klass
500 500
501 501 if self._allow_none:
502 502 return result + ' or None'
503 503
504 504 return result
505 505
506 506 def get_default_value(self):
507 507 """ Returns a tuple of the form: ( default_value_type, default_value )
508 508 which describes the default value for this trait.
509 509 """
510 510 if not isinstance(self.default_value, basestring):
511 511 return super(Type, self).get_default_value()
512 512
513 513 dv = self.resolve_default_value()
514 514 dvt = type(dv)
515 515 return (dvt, dv)
516 516
517 517 def resolve_default_value(self):
518 518 """ Resolves a class name into a class so that it can be used to
519 519 return the class as the default value of the trait.
520 520 """
521 521 if isinstance(self.klass, basestring):
522 522 try:
523 523 self.resolve_class(None, None)
524 524 del self.validate
525 525 except:
526 526 raise TraitletError('Could not resolve %s into a valid class' %
527 527 self.klass )
528 528
529 529 return self.klass
530 530
531 531
532 532 class DefaultValueGenerator(object):
533 533 """A class for generating new default value instances."""
534 534
535 535 def __init__(self, klass, *args, **kw):
536 536 self.klass = klass
537 537 self.args = args
538 538 self.kw = kw
539 539
540 540
541 541 class Instance(BaseClassResolver):
542 542 """A trait whose value must be an instance of a specified class.
543 543
544 544 The value can also be an instance of a subclass of the specified class.
545 545 """
546 546
547 547 def __init__(self, klass=None, args=None, kw=None, allow_none=True,
548 548 module = None, **metadata ):
549 549 """Construct an Instance traitlet.
550 550
551 551 Parameters
552 552 ----------
553 553 klass : class or instance
554 554 The object that forms the basis for the traitlet. If an instance
555 555 values must have isinstance(value, type(instance)).
556 556 args : tuple
557 557 Positional arguments for generating the default value.
558 558 kw : dict
559 559 Keyword arguments for generating the default value.
560 560 allow_none : bool
561 561 Indicates whether None is allowed as a value.
562 562
563 563 Default Value
564 564 -------------
565 565 If klass is an instance, default value is None. If klass is a class
566 566 then the default value is obtained by calling ``klass(*args, **kw)``.
567 567 If klass is a str, it is first resolved to an actual class and then
568 568 instantiated with ``klass(*args, **kw)``.
569 569 """
570 570
571 571 self._allow_none = allow_none
572 572 self.module = module or get_module_name()
573 573
574 574 if klass is None:
575 575 raise TraitletError('A %s traitlet must have a class specified.' %
576 576 self.__class__.__name__ )
577 577 elif not isinstance(klass, (basestring,) + ClassTypes ):
578 578 # klass is an instance so default value will be None
579 579 self.klass = klass.__class__
580 580 default_value = None
581 581 else:
582 582 # klass is a str or class so we handle args, kw
583 583 if args is None:
584 584 args = ()
585 585 if kw is None:
586 586 if isinstance(args, dict):
587 587 kw = args
588 588 args = ()
589 589 else:
590 590 kw = {}
591 591 if not isinstance(kw, dict):
592 592 raise TraitletError("The 'kw' argument must be a dict.")
593 593 if not isinstance(args, tuple):
594 594 raise TraitletError("The 'args' argument must be a tuple.")
595 595 self.klass = klass
596 596 # This tells my get_default_value that the default value
597 597 # instance needs to be generated when it is called. This
598 598 # is usually when TraitletType.__get__ is called for the 1st time.
599 599
600 600 default_value = DefaultValueGenerator(klass, *args, **kw)
601 601
602 602 super(Instance, self).__init__(default_value, **metadata)
603 603
604 604 def validate(self, obj, value):
605 605 if value is None:
606 606 if self._allow_none:
607 607 return value
608 608 self.validate_failed(obj, value)
609 609
610 610 # This is where self.klass is turned into a real class if it was
611 611 # a str initially. This happens the first time TraitletType.__set__
612 612 # is called. This does happen if a default value is generated by
613 613 # TraitletType.__get__.
614 614 if isinstance(self.klass, basestring):
615 615 self.resolve_class(obj, value)
616 616
617 617 if isinstance(value, self.klass):
618 618 return value
619 619 else:
620 620 self.validate_failed(obj, value)
621 621
622 622 def info ( self ):
623 623 klass = self.klass
624 624 if not isinstance( klass, basestring ):
625 625 klass = klass.__name__
626 626 result = class_of(klass)
627 627 if self._allow_none:
628 628 return result + ' or None'
629 629
630 630 return result
631 631
632 632 def get_default_value ( self ):
633 633 """Instantiate a default value instance.
634 634
635 635 When TraitletType.__get__ is called the first time, this is called
636 636 (if no value has been assigned) to get a default value instance.
637 637 """
638 638 dv = self.default_value
639 639 if isinstance(dv, DefaultValueGenerator):
640 640 klass = dv.klass
641 641 args = dv.args
642 642 kw = dv.kw
643 643 if isinstance(klass, basestring):
644 644 klass = self.validate_class(self.find_class(klass))
645 645 if klass is None:
646 646 raise TraitletError('Unable to locate class: ' + dv.klass)
647 647 return klass(*args, **kw)
648 648 else:
649 649 return dv
650 650
651 651
652 652 #-----------------------------------------------------------------------------
653 653 # Basic TraitletTypes implementations/subclasses
654 654 #-----------------------------------------------------------------------------
655 655
656 656
657 657 class Any(TraitletType):
658 658 default_value = None
659 659 info_text = 'any value'
660 660
661 661
662 662 class Int(TraitletType):
663 """A integer traitlet."""
663 664
664 665 evaluate = int
665 666 default_value = 0
666 667 info_text = 'an integer'
667 668
668 669 def validate(self, obj, value):
669 670 if isinstance(value, int):
670 671 return value
671 672 self.error(obj, value)
672 673
674 class CInt(Int):
675 """A casting version of the int traitlet."""
676
677 def validate(self, obj, value):
678 try:
679 return int(value)
680 except:
681 self.error(obj, value)
682
673 683
674 684 class Long(TraitletType):
685 """A long integer traitlet."""
675 686
676 687 evaluate = long
677 688 default_value = 0L
678 689 info_text = 'a long'
679 690
680 691 def validate(self, obj, value):
681 692 if isinstance(value, long):
682 693 return value
683 694 if isinstance(value, int):
684 695 return long(value)
685 696 self.error(obj, value)
686 697
687 698
699 class CLong(Long):
700 """A casting version of the long integer traitlet."""
701
702 def validate(self, obj, value):
703 try:
704 return long(value)
705 except:
706 self.error(obj, value)
707
708
688 709 class Float(TraitletType):
710 """A float traitlet."""
689 711
690 712 evaluate = float
691 713 default_value = 0.0
692 714 info_text = 'a float'
693 715
694 716 def validate(self, obj, value):
695 717 if isinstance(value, float):
696 718 return value
697 719 if isinstance(value, int):
698 720 return float(value)
699 721 self.error(obj, value)
700 722
701 723
724 class CFloat(Float):
725 """A casting version of the float traitlet."""
726
727 def validate(self, obj, value):
728 try:
729 return float(value)
730 except:
731 self.error(obj, value)
732
702 733 class Complex(TraitletType):
734 """A traitlet for complex numbers."""
703 735
704 736 evaluate = complex
705 737 default_value = 0.0 + 0.0j
706 738 info_text = 'a complex number'
707 739
708 740 def validate(self, obj, value):
709 741 if isinstance(value, complex):
710 742 return value
711 743 if isinstance(value, (float, int)):
712 744 return complex(value)
713 745 self.error(obj, value)
714 746
715 747
748 class CComplex(Complex):
749 """A casting version of the complex number traitlet."""
750
751 def validate (self, obj, value):
752 try:
753 return complex(value)
754 except:
755 self.error(obj, value)
756
757
716 758 class Str(TraitletType):
759 """A traitlet for strings."""
717 760
718 761 evaluate = lambda x: x
719 762 default_value = ''
720 763 info_text = 'a string'
721 764
722 765 def validate(self, obj, value):
723 766 if isinstance(value, str):
724 767 return value
725 768 self.error(obj, value)
726 769
727 770
771 class CStr(Str):
772 """A casting version of the string traitlet."""
773
774 def validate(self, obj, value):
775 try:
776 return str(value)
777 except:
778 try:
779 return unicode(value)
780 except:
781 self.error(obj, value)
782
783
728 784 class Unicode(TraitletType):
785 """A traitlet for unicode strings."""
729 786
730 787 evaluate = unicode
731 788 default_value = u''
732 789 info_text = 'a unicode string'
733 790
734 791 def validate(self, obj, value):
735 792 if isinstance(value, unicode):
736 793 return value
737 794 if isinstance(value, str):
738 795 return unicode(value)
739 796 self.error(obj, value)
740 797
741 798
742 class Bool(TraitletType):
799 class CUnicode(Unicode):
800 """A casting version of the unicode traitlet."""
801
802 def validate(self, obj, value):
803 try:
804 return unicode(value)
805 except:
806 self.error(obj, value)
807
743 808
809 class Bool(TraitletType):
810 """A boolean (True, False) traitlet."""
744 811 evaluate = bool
745 812 default_value = False
746 813 info_text = 'a boolean'
747 814
748 815 def validate(self, obj, value):
749 816 if isinstance(value, bool):
750 817 return value
751 818 self.error(obj, value)
752 819
820
821 class CBool(Bool):
822 """A casting version of the boolean traitlet."""
823
824 def validate(self, obj, value):
825 try:
826 return bool(value)
827 except:
828 self.error(obj, value) No newline at end of file
General Comments 0
You need to be logged in to leave comments. Login now