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