##// END OF EJS Templates
Merge pull request #8188 from minrk/bigsplit-traitlets...
Thomas Kluyver -
r21004:5ffdabae merge
parent child Browse files
Show More
@@ -0,0 +1,18 b''
1 """
2 Shim to maintain backwards compatibility with old IPython.config imports.
3 """
4 # Copyright (c) IPython Development Team.
5 # Distributed under the terms of the Modified BSD License.
6
7 import sys
8 from warnings import warn
9
10 warn("The `IPython.config` package has been deprecated. "
11 "You should import from traitlets.config instead.")
12
13 from IPython.utils.shimmodule import ShimModule
14
15 # Unconditionally insert the shim into sys.modules so that further import calls
16 # trigger the custom attribute access above
17
18 sys.modules['IPython.config'] = ShimModule(src='IPython.config', mirror='traitlets.config')
@@ -0,0 +1,5 b''
1 # FIXME: import IPython first, to avoid circular imports
2 # this shouldn't be needed after finishing the big split
3 import IPython
4
5 from .traitlets import *
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
This diff has been collapsed as it changes many lines, (1874 lines changed) Show them Hide them
@@ -0,0 +1,1874 b''
1 # encoding: utf-8
2 """
3 A lightweight Traits like module.
4
5 This is designed to provide a lightweight, simple, pure Python version of
6 many of the capabilities of enthought.traits. This includes:
7
8 * Validation
9 * Type specification with defaults
10 * Static and dynamic notification
11 * Basic predefined types
12 * An API that is similar to enthought.traits
13
14 We don't support:
15
16 * Delegation
17 * Automatic GUI generation
18 * A full set of trait types. Most importantly, we don't provide container
19 traits (list, dict, tuple) that can trigger notifications if their
20 contents change.
21 * API compatibility with enthought.traits
22
23 There are also some important difference in our design:
24
25 * enthought.traits does not validate default values. We do.
26
27 We choose to create this module because we need these capabilities, but
28 we need them to be pure Python so they work in all Python implementations,
29 including Jython and IronPython.
30
31 Inheritance diagram:
32
33 .. inheritance-diagram:: IPython.utils.traitlets
34 :parts: 3
35 """
36
37 # Copyright (c) IPython Development Team.
38 # Distributed under the terms of the Modified BSD License.
39 #
40 # Adapted from enthought.traits, Copyright (c) Enthought, Inc.,
41 # also under the terms of the Modified BSD License.
42
43 import contextlib
44 import inspect
45 import re
46 import sys
47 import types
48 from types import FunctionType
49 try:
50 from types import ClassType, InstanceType
51 ClassTypes = (ClassType, type)
52 except:
53 ClassTypes = (type,)
54 from warnings import warn
55
56 from IPython.utils import py3compat
57 from IPython.utils import eventful
58 from IPython.utils.getargspec import getargspec
59 from IPython.utils.importstring import import_item
60 from IPython.utils.py3compat import iteritems, string_types
61 from IPython.testing.skipdoctest import skip_doctest
62
63 SequenceTypes = (list, tuple, set, frozenset)
64
65 #-----------------------------------------------------------------------------
66 # Basic classes
67 #-----------------------------------------------------------------------------
68
69
70 class NoDefaultSpecified ( object ): pass
71 NoDefaultSpecified = NoDefaultSpecified()
72
73
74 class Undefined ( object ): pass
75 Undefined = Undefined()
76
77 class TraitError(Exception):
78 pass
79
80 #-----------------------------------------------------------------------------
81 # Utilities
82 #-----------------------------------------------------------------------------
83
84
85 def class_of ( object ):
86 """ Returns a string containing the class name of an object with the
87 correct indefinite article ('a' or 'an') preceding it (e.g., 'an Image',
88 'a PlotValue').
89 """
90 if isinstance( object, py3compat.string_types ):
91 return add_article( object )
92
93 return add_article( object.__class__.__name__ )
94
95
96 def add_article ( name ):
97 """ Returns a string containing the correct indefinite article ('a' or 'an')
98 prefixed to the specified string.
99 """
100 if name[:1].lower() in 'aeiou':
101 return 'an ' + name
102
103 return 'a ' + name
104
105
106 def repr_type(obj):
107 """ Return a string representation of a value and its type for readable
108 error messages.
109 """
110 the_type = type(obj)
111 if (not py3compat.PY3) and the_type is InstanceType:
112 # Old-style class.
113 the_type = obj.__class__
114 msg = '%r %r' % (obj, the_type)
115 return msg
116
117
118 def is_trait(t):
119 """ Returns whether the given value is an instance or subclass of TraitType.
120 """
121 return (isinstance(t, TraitType) or
122 (isinstance(t, type) and issubclass(t, TraitType)))
123
124
125 def parse_notifier_name(name):
126 """Convert the name argument to a list of names.
127
128 Examples
129 --------
130
131 >>> parse_notifier_name('a')
132 ['a']
133 >>> parse_notifier_name(['a','b'])
134 ['a', 'b']
135 >>> parse_notifier_name(None)
136 ['anytrait']
137 """
138 if isinstance(name, string_types):
139 return [name]
140 elif name is None:
141 return ['anytrait']
142 elif isinstance(name, (list, tuple)):
143 for n in name:
144 assert isinstance(n, string_types), "names must be strings"
145 return name
146
147
148 class _SimpleTest:
149 def __init__ ( self, value ): self.value = value
150 def __call__ ( self, test ):
151 return test == self.value
152 def __repr__(self):
153 return "<SimpleTest(%r)" % self.value
154 def __str__(self):
155 return self.__repr__()
156
157
158 def getmembers(object, predicate=None):
159 """A safe version of inspect.getmembers that handles missing attributes.
160
161 This is useful when there are descriptor based attributes that for
162 some reason raise AttributeError even though they exist. This happens
163 in zope.inteface with the __provides__ attribute.
164 """
165 results = []
166 for key in dir(object):
167 try:
168 value = getattr(object, key)
169 except AttributeError:
170 pass
171 else:
172 if not predicate or predicate(value):
173 results.append((key, value))
174 results.sort()
175 return results
176
177 def _validate_link(*tuples):
178 """Validate arguments for traitlet link functions"""
179 for t in tuples:
180 if not len(t) == 2:
181 raise TypeError("Each linked traitlet must be specified as (HasTraits, 'trait_name'), not %r" % t)
182 obj, trait_name = t
183 if not isinstance(obj, HasTraits):
184 raise TypeError("Each object must be HasTraits, not %r" % type(obj))
185 if not trait_name in obj.traits():
186 raise TypeError("%r has no trait %r" % (obj, trait_name))
187
188 @skip_doctest
189 class link(object):
190 """Link traits from different objects together so they remain in sync.
191
192 Parameters
193 ----------
194 *args : pairs of objects/attributes
195
196 Examples
197 --------
198
199 >>> c = link((obj1, 'value'), (obj2, 'value'), (obj3, 'value'))
200 >>> obj1.value = 5 # updates other objects as well
201 """
202 updating = False
203 def __init__(self, *args):
204 if len(args) < 2:
205 raise TypeError('At least two traitlets must be provided.')
206 _validate_link(*args)
207
208 self.objects = {}
209
210 initial = getattr(args[0][0], args[0][1])
211 for obj, attr in args:
212 setattr(obj, attr, initial)
213
214 callback = self._make_closure(obj, attr)
215 obj.on_trait_change(callback, attr)
216 self.objects[(obj, attr)] = callback
217
218 @contextlib.contextmanager
219 def _busy_updating(self):
220 self.updating = True
221 try:
222 yield
223 finally:
224 self.updating = False
225
226 def _make_closure(self, sending_obj, sending_attr):
227 def update(name, old, new):
228 self._update(sending_obj, sending_attr, new)
229 return update
230
231 def _update(self, sending_obj, sending_attr, new):
232 if self.updating:
233 return
234 with self._busy_updating():
235 for obj, attr in self.objects.keys():
236 setattr(obj, attr, new)
237
238 def unlink(self):
239 for key, callback in self.objects.items():
240 (obj, attr) = key
241 obj.on_trait_change(callback, attr, remove=True)
242
243 @skip_doctest
244 class directional_link(object):
245 """Link the trait of a source object with traits of target objects.
246
247 Parameters
248 ----------
249 source : pair of object, name
250 targets : pairs of objects/attributes
251
252 Examples
253 --------
254
255 >>> c = directional_link((src, 'value'), (tgt1, 'value'), (tgt2, 'value'))
256 >>> src.value = 5 # updates target objects
257 >>> tgt1.value = 6 # does not update other objects
258 """
259 updating = False
260
261 def __init__(self, source, *targets):
262 if len(targets) < 1:
263 raise TypeError('At least two traitlets must be provided.')
264 _validate_link(source, *targets)
265 self.source = source
266 self.targets = targets
267
268 # Update current value
269 src_attr_value = getattr(source[0], source[1])
270 for obj, attr in targets:
271 setattr(obj, attr, src_attr_value)
272
273 # Wire
274 self.source[0].on_trait_change(self._update, self.source[1])
275
276 @contextlib.contextmanager
277 def _busy_updating(self):
278 self.updating = True
279 try:
280 yield
281 finally:
282 self.updating = False
283
284 def _update(self, name, old, new):
285 if self.updating:
286 return
287 with self._busy_updating():
288 for obj, attr in self.targets:
289 setattr(obj, attr, new)
290
291 def unlink(self):
292 self.source[0].on_trait_change(self._update, self.source[1], remove=True)
293 self.source = None
294 self.targets = []
295
296 dlink = directional_link
297
298
299 #-----------------------------------------------------------------------------
300 # Base TraitType for all traits
301 #-----------------------------------------------------------------------------
302
303
304 class TraitType(object):
305 """A base class for all trait descriptors.
306
307 Notes
308 -----
309 Our implementation of traits is based on Python's descriptor
310 prototol. This class is the base class for all such descriptors. The
311 only magic we use is a custom metaclass for the main :class:`HasTraits`
312 class that does the following:
313
314 1. Sets the :attr:`name` attribute of every :class:`TraitType`
315 instance in the class dict to the name of the attribute.
316 2. Sets the :attr:`this_class` attribute of every :class:`TraitType`
317 instance in the class dict to the *class* that declared the trait.
318 This is used by the :class:`This` trait to allow subclasses to
319 accept superclasses for :class:`This` values.
320 """
321
322 metadata = {}
323 default_value = Undefined
324 allow_none = False
325 info_text = 'any value'
326
327 def __init__(self, default_value=NoDefaultSpecified, allow_none=None, **metadata):
328 """Create a TraitType.
329 """
330 if default_value is not NoDefaultSpecified:
331 self.default_value = default_value
332 if allow_none is not None:
333 self.allow_none = allow_none
334
335 if 'default' in metadata:
336 # Warn the user that they probably meant default_value.
337 warn(
338 "Parameter 'default' passed to TraitType. "
339 "Did you mean 'default_value'?"
340 )
341
342 if len(metadata) > 0:
343 if len(self.metadata) > 0:
344 self._metadata = self.metadata.copy()
345 self._metadata.update(metadata)
346 else:
347 self._metadata = metadata
348 else:
349 self._metadata = self.metadata
350
351 self.init()
352
353 def init(self):
354 pass
355
356 def get_default_value(self):
357 """Create a new instance of the default value."""
358 return self.default_value
359
360 def instance_init(self):
361 """Part of the initialization which may depends on the underlying
362 HasTraits instance.
363
364 It is typically overloaded for specific trait types.
365
366 This method is called by :meth:`HasTraits.__new__` and in the
367 :meth:`TraitType.instance_init` method of trait types holding
368 other trait types.
369 """
370 pass
371
372 def init_default_value(self, obj):
373 """Instantiate the default value for the trait type.
374
375 This method is called by :meth:`TraitType.set_default_value` in the
376 case a default value is provided at construction time or later when
377 accessing the trait value for the first time in
378 :meth:`HasTraits.__get__`.
379 """
380 value = self.get_default_value()
381 value = self._validate(obj, value)
382 obj._trait_values[self.name] = value
383 return value
384
385 def set_default_value(self, obj):
386 """Set the default value on a per instance basis.
387
388 This method is called by :meth:`HasTraits.__new__` to instantiate and
389 validate the default value. The creation and validation of
390 default values must be delayed until the parent :class:`HasTraits`
391 class has been instantiated.
392 Parameters
393 ----------
394 obj : :class:`HasTraits` instance
395 The parent :class:`HasTraits` instance that has just been
396 created.
397 """
398 # Check for a deferred initializer defined in the same class as the
399 # trait declaration or above.
400 mro = type(obj).mro()
401 meth_name = '_%s_default' % self.name
402 for cls in mro[:mro.index(self.this_class)+1]:
403 if meth_name in cls.__dict__:
404 break
405 else:
406 # We didn't find one. Do static initialization.
407 self.init_default_value(obj)
408 return
409 # Complete the dynamic initialization.
410 obj._trait_dyn_inits[self.name] = meth_name
411
412 def __get__(self, obj, cls=None):
413 """Get the value of the trait by self.name for the instance.
414
415 Default values are instantiated when :meth:`HasTraits.__new__`
416 is called. Thus by the time this method gets called either the
417 default value or a user defined value (they called :meth:`__set__`)
418 is in the :class:`HasTraits` instance.
419 """
420 if obj is None:
421 return self
422 else:
423 try:
424 value = obj._trait_values[self.name]
425 except KeyError:
426 # Check for a dynamic initializer.
427 if self.name in obj._trait_dyn_inits:
428 method = getattr(obj, obj._trait_dyn_inits[self.name])
429 value = method()
430 # FIXME: Do we really validate here?
431 value = self._validate(obj, value)
432 obj._trait_values[self.name] = value
433 return value
434 else:
435 return self.init_default_value(obj)
436 except Exception:
437 # HasTraits should call set_default_value to populate
438 # this. So this should never be reached.
439 raise TraitError('Unexpected error in TraitType: '
440 'default value not set properly')
441 else:
442 return value
443
444 def __set__(self, obj, value):
445 new_value = self._validate(obj, value)
446 try:
447 old_value = obj._trait_values[self.name]
448 except KeyError:
449 old_value = Undefined
450
451 obj._trait_values[self.name] = new_value
452 try:
453 silent = bool(old_value == new_value)
454 except:
455 # if there is an error in comparing, default to notify
456 silent = False
457 if silent is not True:
458 # we explicitly compare silent to True just in case the equality
459 # comparison above returns something other than True/False
460 obj._notify_trait(self.name, old_value, new_value)
461
462 def _validate(self, obj, value):
463 if value is None and self.allow_none:
464 return value
465 if hasattr(self, 'validate'):
466 value = self.validate(obj, value)
467 if obj._cross_validation_lock is False:
468 value = self._cross_validate(obj, value)
469 return value
470
471 def _cross_validate(self, obj, value):
472 if hasattr(obj, '_%s_validate' % self.name):
473 cross_validate = getattr(obj, '_%s_validate' % self.name)
474 value = cross_validate(value, self)
475 return value
476
477 def __or__(self, other):
478 if isinstance(other, Union):
479 return Union([self] + other.trait_types)
480 else:
481 return Union([self, other])
482
483 def info(self):
484 return self.info_text
485
486 def error(self, obj, value):
487 if obj is not None:
488 e = "The '%s' trait of %s instance must be %s, but a value of %s was specified." \
489 % (self.name, class_of(obj),
490 self.info(), repr_type(value))
491 else:
492 e = "The '%s' trait must be %s, but a value of %r was specified." \
493 % (self.name, self.info(), repr_type(value))
494 raise TraitError(e)
495
496 def get_metadata(self, key, default=None):
497 return getattr(self, '_metadata', {}).get(key, default)
498
499 def set_metadata(self, key, value):
500 getattr(self, '_metadata', {})[key] = value
501
502
503 #-----------------------------------------------------------------------------
504 # The HasTraits implementation
505 #-----------------------------------------------------------------------------
506
507
508 class MetaHasTraits(type):
509 """A metaclass for HasTraits.
510
511 This metaclass makes sure that any TraitType class attributes are
512 instantiated and sets their name attribute.
513 """
514
515 def __new__(mcls, name, bases, classdict):
516 """Create the HasTraits class.
517
518 This instantiates all TraitTypes in the class dict and sets their
519 :attr:`name` attribute.
520 """
521 # print "MetaHasTraitlets (mcls, name): ", mcls, name
522 # print "MetaHasTraitlets (bases): ", bases
523 # print "MetaHasTraitlets (classdict): ", classdict
524 for k,v in iteritems(classdict):
525 if isinstance(v, TraitType):
526 v.name = k
527 elif inspect.isclass(v):
528 if issubclass(v, TraitType):
529 vinst = v()
530 vinst.name = k
531 classdict[k] = vinst
532 return super(MetaHasTraits, mcls).__new__(mcls, name, bases, classdict)
533
534 def __init__(cls, name, bases, classdict):
535 """Finish initializing the HasTraits class.
536
537 This sets the :attr:`this_class` attribute of each TraitType in the
538 class dict to the newly created class ``cls``.
539 """
540 for k, v in iteritems(classdict):
541 if isinstance(v, TraitType):
542 v.this_class = cls
543 super(MetaHasTraits, cls).__init__(name, bases, classdict)
544
545
546 class HasTraits(py3compat.with_metaclass(MetaHasTraits, object)):
547
548 def __new__(cls, *args, **kw):
549 # This is needed because object.__new__ only accepts
550 # the cls argument.
551 new_meth = super(HasTraits, cls).__new__
552 if new_meth is object.__new__:
553 inst = new_meth(cls)
554 else:
555 inst = new_meth(cls, **kw)
556 inst._trait_values = {}
557 inst._trait_notifiers = {}
558 inst._trait_dyn_inits = {}
559 inst._cross_validation_lock = True
560 # Here we tell all the TraitType instances to set their default
561 # values on the instance.
562 for key in dir(cls):
563 # Some descriptors raise AttributeError like zope.interface's
564 # __provides__ attributes even though they exist. This causes
565 # AttributeErrors even though they are listed in dir(cls).
566 try:
567 value = getattr(cls, key)
568 except AttributeError:
569 pass
570 else:
571 if isinstance(value, TraitType):
572 value.instance_init()
573 if key not in kw:
574 value.set_default_value(inst)
575 inst._cross_validation_lock = False
576 return inst
577
578 def __init__(self, *args, **kw):
579 # Allow trait values to be set using keyword arguments.
580 # We need to use setattr for this to trigger validation and
581 # notifications.
582 with self.hold_trait_notifications():
583 for key, value in iteritems(kw):
584 setattr(self, key, value)
585
586 @contextlib.contextmanager
587 def hold_trait_notifications(self):
588 """Context manager for bundling trait change notifications and cross
589 validation.
590
591 Use this when doing multiple trait assignments (init, config), to avoid
592 race conditions in trait notifiers requesting other trait values.
593 All trait notifications will fire after all values have been assigned.
594 """
595 if self._cross_validation_lock is True:
596 yield
597 return
598 else:
599 self._cross_validation_lock = True
600 cache = {}
601 notifications = {}
602 _notify_trait = self._notify_trait
603
604 def cache_values(*a):
605 cache[a[0]] = a
606
607 def hold_notifications(*a):
608 notifications[a[0]] = a
609
610 self._notify_trait = cache_values
611
612 try:
613 yield
614 finally:
615 try:
616 self._notify_trait = hold_notifications
617 for name in cache:
618 if hasattr(self, '_%s_validate' % name):
619 cross_validate = getattr(self, '_%s_validate' % name)
620 setattr(self, name, cross_validate(getattr(self, name), self))
621 except TraitError as e:
622 self._notify_trait = lambda *x: None
623 for name in cache:
624 if cache[name][1] is not Undefined:
625 setattr(self, name, cache[name][1])
626 else:
627 delattr(self, name)
628 cache = {}
629 notifications = {}
630 raise e
631 finally:
632 self._notify_trait = _notify_trait
633 self._cross_validation_lock = False
634 if isinstance(_notify_trait, types.MethodType):
635 # FIXME: remove when support is bumped to 3.4.
636 # when original method is restored,
637 # remove the redundant value from __dict__
638 # (only used to preserve pickleability on Python < 3.4)
639 self.__dict__.pop('_notify_trait', None)
640 # trigger delayed notifications
641 for v in dict(cache, **notifications).values():
642 self._notify_trait(*v)
643
644 def _notify_trait(self, name, old_value, new_value):
645
646 # First dynamic ones
647 callables = []
648 callables.extend(self._trait_notifiers.get(name,[]))
649 callables.extend(self._trait_notifiers.get('anytrait',[]))
650
651 # Now static ones
652 try:
653 cb = getattr(self, '_%s_changed' % name)
654 except:
655 pass
656 else:
657 callables.append(cb)
658
659 # Call them all now
660 for c in callables:
661 # Traits catches and logs errors here. I allow them to raise
662 if callable(c):
663 argspec = getargspec(c)
664
665 nargs = len(argspec[0])
666 # Bound methods have an additional 'self' argument
667 # I don't know how to treat unbound methods, but they
668 # can't really be used for callbacks.
669 if isinstance(c, types.MethodType):
670 offset = -1
671 else:
672 offset = 0
673 if nargs + offset == 0:
674 c()
675 elif nargs + offset == 1:
676 c(name)
677 elif nargs + offset == 2:
678 c(name, new_value)
679 elif nargs + offset == 3:
680 c(name, old_value, new_value)
681 else:
682 raise TraitError('a trait changed callback '
683 'must have 0-3 arguments.')
684 else:
685 raise TraitError('a trait changed callback '
686 'must be callable.')
687
688
689 def _add_notifiers(self, handler, name):
690 if name not in self._trait_notifiers:
691 nlist = []
692 self._trait_notifiers[name] = nlist
693 else:
694 nlist = self._trait_notifiers[name]
695 if handler not in nlist:
696 nlist.append(handler)
697
698 def _remove_notifiers(self, handler, name):
699 if name in self._trait_notifiers:
700 nlist = self._trait_notifiers[name]
701 try:
702 index = nlist.index(handler)
703 except ValueError:
704 pass
705 else:
706 del nlist[index]
707
708 def on_trait_change(self, handler, name=None, remove=False):
709 """Setup a handler to be called when a trait changes.
710
711 This is used to setup dynamic notifications of trait changes.
712
713 Static handlers can be created by creating methods on a HasTraits
714 subclass with the naming convention '_[traitname]_changed'. Thus,
715 to create static handler for the trait 'a', create the method
716 _a_changed(self, name, old, new) (fewer arguments can be used, see
717 below).
718
719 Parameters
720 ----------
721 handler : callable
722 A callable that is called when a trait changes. Its
723 signature can be handler(), handler(name), handler(name, new)
724 or handler(name, old, new).
725 name : list, str, None
726 If None, the handler will apply to all traits. If a list
727 of str, handler will apply to all names in the list. If a
728 str, the handler will apply just to that name.
729 remove : bool
730 If False (the default), then install the handler. If True
731 then unintall it.
732 """
733 if remove:
734 names = parse_notifier_name(name)
735 for n in names:
736 self._remove_notifiers(handler, n)
737 else:
738 names = parse_notifier_name(name)
739 for n in names:
740 self._add_notifiers(handler, n)
741
742 @classmethod
743 def class_trait_names(cls, **metadata):
744 """Get a list of all the names of this class' traits.
745
746 This method is just like the :meth:`trait_names` method,
747 but is unbound.
748 """
749 return cls.class_traits(**metadata).keys()
750
751 @classmethod
752 def class_traits(cls, **metadata):
753 """Get a `dict` of all the traits of this class. The dictionary
754 is keyed on the name and the values are the TraitType objects.
755
756 This method is just like the :meth:`traits` method, but is unbound.
757
758 The TraitTypes returned don't know anything about the values
759 that the various HasTrait's instances are holding.
760
761 The metadata kwargs allow functions to be passed in which
762 filter traits based on metadata values. The functions should
763 take a single value as an argument and return a boolean. If
764 any function returns False, then the trait is not included in
765 the output. This does not allow for any simple way of
766 testing that a metadata name exists and has any
767 value because get_metadata returns None if a metadata key
768 doesn't exist.
769 """
770 traits = dict([memb for memb in getmembers(cls) if
771 isinstance(memb[1], TraitType)])
772
773 if len(metadata) == 0:
774 return traits
775
776 for meta_name, meta_eval in metadata.items():
777 if type(meta_eval) is not FunctionType:
778 metadata[meta_name] = _SimpleTest(meta_eval)
779
780 result = {}
781 for name, trait in traits.items():
782 for meta_name, meta_eval in metadata.items():
783 if not meta_eval(trait.get_metadata(meta_name)):
784 break
785 else:
786 result[name] = trait
787
788 return result
789
790 def trait_names(self, **metadata):
791 """Get a list of all the names of this class' traits."""
792 return self.traits(**metadata).keys()
793
794 def traits(self, **metadata):
795 """Get a `dict` of all the traits of this class. The dictionary
796 is keyed on the name and the values are the TraitType objects.
797
798 The TraitTypes returned don't know anything about the values
799 that the various HasTrait's instances are holding.
800
801 The metadata kwargs allow functions to be passed in which
802 filter traits based on metadata values. The functions should
803 take a single value as an argument and return a boolean. If
804 any function returns False, then the trait is not included in
805 the output. This does not allow for any simple way of
806 testing that a metadata name exists and has any
807 value because get_metadata returns None if a metadata key
808 doesn't exist.
809 """
810 traits = dict([memb for memb in getmembers(self.__class__) if
811 isinstance(memb[1], TraitType)])
812
813 if len(metadata) == 0:
814 return traits
815
816 for meta_name, meta_eval in metadata.items():
817 if type(meta_eval) is not FunctionType:
818 metadata[meta_name] = _SimpleTest(meta_eval)
819
820 result = {}
821 for name, trait in traits.items():
822 for meta_name, meta_eval in metadata.items():
823 if not meta_eval(trait.get_metadata(meta_name)):
824 break
825 else:
826 result[name] = trait
827
828 return result
829
830 def trait_metadata(self, traitname, key, default=None):
831 """Get metadata values for trait by key."""
832 try:
833 trait = getattr(self.__class__, traitname)
834 except AttributeError:
835 raise TraitError("Class %s does not have a trait named %s" %
836 (self.__class__.__name__, traitname))
837 else:
838 return trait.get_metadata(key, default)
839
840 def add_trait(self, traitname, trait):
841 """Dynamically add a trait attribute to the HasTraits instance."""
842 self.__class__ = type(self.__class__.__name__, (self.__class__,),
843 {traitname: trait})
844 trait.set_default_value(self)
845
846 #-----------------------------------------------------------------------------
847 # Actual TraitTypes implementations/subclasses
848 #-----------------------------------------------------------------------------
849
850 #-----------------------------------------------------------------------------
851 # TraitTypes subclasses for handling classes and instances of classes
852 #-----------------------------------------------------------------------------
853
854
855 class ClassBasedTraitType(TraitType):
856 """
857 A trait with error reporting and string -> type resolution for Type,
858 Instance and This.
859 """
860
861 def _resolve_string(self, string):
862 """
863 Resolve a string supplied for a type into an actual object.
864 """
865 return import_item(string)
866
867 def error(self, obj, value):
868 kind = type(value)
869 if (not py3compat.PY3) and kind is InstanceType:
870 msg = 'class %s' % value.__class__.__name__
871 else:
872 msg = '%s (i.e. %s)' % ( str( kind )[1:-1], repr( value ) )
873
874 if obj is not None:
875 e = "The '%s' trait of %s instance must be %s, but a value of %s was specified." \
876 % (self.name, class_of(obj),
877 self.info(), msg)
878 else:
879 e = "The '%s' trait must be %s, but a value of %r was specified." \
880 % (self.name, self.info(), msg)
881
882 raise TraitError(e)
883
884
885 class Type(ClassBasedTraitType):
886 """A trait whose value must be a subclass of a specified class."""
887
888 def __init__ (self, default_value=None, klass=None, allow_none=False,
889 **metadata):
890 """Construct a Type trait
891
892 A Type trait specifies that its values must be subclasses of
893 a particular class.
894
895 If only ``default_value`` is given, it is used for the ``klass`` as
896 well.
897
898 Parameters
899 ----------
900 default_value : class, str or None
901 The default value must be a subclass of klass. If an str,
902 the str must be a fully specified class name, like 'foo.bar.Bah'.
903 The string is resolved into real class, when the parent
904 :class:`HasTraits` class is instantiated.
905 klass : class, str, None
906 Values of this trait must be a subclass of klass. The klass
907 may be specified in a string like: 'foo.bar.MyClass'.
908 The string is resolved into real class, when the parent
909 :class:`HasTraits` class is instantiated.
910 allow_none : bool [ default True ]
911 Indicates whether None is allowed as an assignable value. Even if
912 ``False``, the default value may be ``None``.
913 """
914 if default_value is None:
915 if klass is None:
916 klass = object
917 elif klass is None:
918 klass = default_value
919
920 if not (inspect.isclass(klass) or isinstance(klass, py3compat.string_types)):
921 raise TraitError("A Type trait must specify a class.")
922
923 self.klass = klass
924
925 super(Type, self).__init__(default_value, allow_none=allow_none, **metadata)
926
927 def validate(self, obj, value):
928 """Validates that the value is a valid object instance."""
929 if isinstance(value, py3compat.string_types):
930 try:
931 value = self._resolve_string(value)
932 except ImportError:
933 raise TraitError("The '%s' trait of %s instance must be a type, but "
934 "%r could not be imported" % (self.name, obj, value))
935 try:
936 if issubclass(value, self.klass):
937 return value
938 except:
939 pass
940
941 self.error(obj, value)
942
943 def info(self):
944 """ Returns a description of the trait."""
945 if isinstance(self.klass, py3compat.string_types):
946 klass = self.klass
947 else:
948 klass = self.klass.__name__
949 result = 'a subclass of ' + klass
950 if self.allow_none:
951 return result + ' or None'
952 return result
953
954 def instance_init(self):
955 self._resolve_classes()
956 super(Type, self).instance_init()
957
958 def _resolve_classes(self):
959 if isinstance(self.klass, py3compat.string_types):
960 self.klass = self._resolve_string(self.klass)
961 if isinstance(self.default_value, py3compat.string_types):
962 self.default_value = self._resolve_string(self.default_value)
963
964 def get_default_value(self):
965 return self.default_value
966
967
968 class DefaultValueGenerator(object):
969 """A class for generating new default value instances."""
970
971 def __init__(self, *args, **kw):
972 self.args = args
973 self.kw = kw
974
975 def generate(self, klass):
976 return klass(*self.args, **self.kw)
977
978
979 class Instance(ClassBasedTraitType):
980 """A trait whose value must be an instance of a specified class.
981
982 The value can also be an instance of a subclass of the specified class.
983
984 Subclasses can declare default classes by overriding the klass attribute
985 """
986
987 klass = None
988
989 def __init__(self, klass=None, args=None, kw=None, allow_none=False,
990 **metadata ):
991 """Construct an Instance trait.
992
993 This trait allows values that are instances of a particular
994 class or its subclasses. Our implementation is quite different
995 from that of enthough.traits as we don't allow instances to be used
996 for klass and we handle the ``args`` and ``kw`` arguments differently.
997
998 Parameters
999 ----------
1000 klass : class, str
1001 The class that forms the basis for the trait. Class names
1002 can also be specified as strings, like 'foo.bar.Bar'.
1003 args : tuple
1004 Positional arguments for generating the default value.
1005 kw : dict
1006 Keyword arguments for generating the default value.
1007 allow_none : bool [default True]
1008 Indicates whether None is allowed as a value.
1009
1010 Notes
1011 -----
1012 If both ``args`` and ``kw`` are None, then the default value is None.
1013 If ``args`` is a tuple and ``kw`` is a dict, then the default is
1014 created as ``klass(*args, **kw)``. If exactly one of ``args`` or ``kw`` is
1015 None, the None is replaced by ``()`` or ``{}``, respectively.
1016 """
1017 if klass is None:
1018 klass = self.klass
1019
1020 if (klass is not None) and (inspect.isclass(klass) or isinstance(klass, py3compat.string_types)):
1021 self.klass = klass
1022 else:
1023 raise TraitError('The klass attribute must be a class'
1024 ' not: %r' % klass)
1025
1026 # self.klass is a class, so handle default_value
1027 if args is None and kw is None:
1028 default_value = None
1029 else:
1030 if args is None:
1031 # kw is not None
1032 args = ()
1033 elif kw is None:
1034 # args is not None
1035 kw = {}
1036
1037 if not isinstance(kw, dict):
1038 raise TraitError("The 'kw' argument must be a dict or None.")
1039 if not isinstance(args, tuple):
1040 raise TraitError("The 'args' argument must be a tuple or None.")
1041
1042 default_value = DefaultValueGenerator(*args, **kw)
1043
1044 super(Instance, self).__init__(default_value, allow_none=allow_none, **metadata)
1045
1046 def validate(self, obj, value):
1047 if isinstance(value, self.klass):
1048 return value
1049 else:
1050 self.error(obj, value)
1051
1052 def info(self):
1053 if isinstance(self.klass, py3compat.string_types):
1054 klass = self.klass
1055 else:
1056 klass = self.klass.__name__
1057 result = class_of(klass)
1058 if self.allow_none:
1059 return result + ' or None'
1060
1061 return result
1062
1063 def instance_init(self):
1064 self._resolve_classes()
1065 super(Instance, self).instance_init()
1066
1067 def _resolve_classes(self):
1068 if isinstance(self.klass, py3compat.string_types):
1069 self.klass = self._resolve_string(self.klass)
1070
1071 def get_default_value(self):
1072 """Instantiate a default value instance.
1073
1074 This is called when the containing HasTraits classes'
1075 :meth:`__new__` method is called to ensure that a unique instance
1076 is created for each HasTraits instance.
1077 """
1078 dv = self.default_value
1079 if isinstance(dv, DefaultValueGenerator):
1080 return dv.generate(self.klass)
1081 else:
1082 return dv
1083
1084
1085 class ForwardDeclaredMixin(object):
1086 """
1087 Mixin for forward-declared versions of Instance and Type.
1088 """
1089 def _resolve_string(self, string):
1090 """
1091 Find the specified class name by looking for it in the module in which
1092 our this_class attribute was defined.
1093 """
1094 modname = self.this_class.__module__
1095 return import_item('.'.join([modname, string]))
1096
1097
1098 class ForwardDeclaredType(ForwardDeclaredMixin, Type):
1099 """
1100 Forward-declared version of Type.
1101 """
1102 pass
1103
1104
1105 class ForwardDeclaredInstance(ForwardDeclaredMixin, Instance):
1106 """
1107 Forward-declared version of Instance.
1108 """
1109 pass
1110
1111
1112 class This(ClassBasedTraitType):
1113 """A trait for instances of the class containing this trait.
1114
1115 Because how how and when class bodies are executed, the ``This``
1116 trait can only have a default value of None. This, and because we
1117 always validate default values, ``allow_none`` is *always* true.
1118 """
1119
1120 info_text = 'an instance of the same type as the receiver or None'
1121
1122 def __init__(self, **metadata):
1123 super(This, self).__init__(None, **metadata)
1124
1125 def validate(self, obj, value):
1126 # What if value is a superclass of obj.__class__? This is
1127 # complicated if it was the superclass that defined the This
1128 # trait.
1129 if isinstance(value, self.this_class) or (value is None):
1130 return value
1131 else:
1132 self.error(obj, value)
1133
1134
1135 class Union(TraitType):
1136 """A trait type representing a Union type."""
1137
1138 def __init__(self, trait_types, **metadata):
1139 """Construct a Union trait.
1140
1141 This trait allows values that are allowed by at least one of the
1142 specified trait types. A Union traitlet cannot have metadata on
1143 its own, besides the metadata of the listed types.
1144
1145 Parameters
1146 ----------
1147 trait_types: sequence
1148 The list of trait types of length at least 1.
1149
1150 Notes
1151 -----
1152 Union([Float(), Bool(), Int()]) attempts to validate the provided values
1153 with the validation function of Float, then Bool, and finally Int.
1154 """
1155 self.trait_types = trait_types
1156 self.info_text = " or ".join([tt.info_text for tt in self.trait_types])
1157 self.default_value = self.trait_types[0].get_default_value()
1158 super(Union, self).__init__(**metadata)
1159
1160 def instance_init(self):
1161 for trait_type in self.trait_types:
1162 trait_type.name = self.name
1163 trait_type.this_class = self.this_class
1164 trait_type.instance_init()
1165 super(Union, self).instance_init()
1166
1167 def validate(self, obj, value):
1168 for trait_type in self.trait_types:
1169 try:
1170 v = trait_type._validate(obj, value)
1171 self._metadata = trait_type._metadata
1172 return v
1173 except TraitError:
1174 continue
1175 self.error(obj, value)
1176
1177 def __or__(self, other):
1178 if isinstance(other, Union):
1179 return Union(self.trait_types + other.trait_types)
1180 else:
1181 return Union(self.trait_types + [other])
1182
1183 #-----------------------------------------------------------------------------
1184 # Basic TraitTypes implementations/subclasses
1185 #-----------------------------------------------------------------------------
1186
1187
1188 class Any(TraitType):
1189 default_value = None
1190 info_text = 'any value'
1191
1192
1193 class Int(TraitType):
1194 """An int trait."""
1195
1196 default_value = 0
1197 info_text = 'an int'
1198
1199 def validate(self, obj, value):
1200 if isinstance(value, int):
1201 return value
1202 self.error(obj, value)
1203
1204 class CInt(Int):
1205 """A casting version of the int trait."""
1206
1207 def validate(self, obj, value):
1208 try:
1209 return int(value)
1210 except:
1211 self.error(obj, value)
1212
1213 if py3compat.PY3:
1214 Long, CLong = Int, CInt
1215 Integer = Int
1216 else:
1217 class Long(TraitType):
1218 """A long integer trait."""
1219
1220 default_value = 0
1221 info_text = 'a long'
1222
1223 def validate(self, obj, value):
1224 if isinstance(value, long):
1225 return value
1226 if isinstance(value, int):
1227 return long(value)
1228 self.error(obj, value)
1229
1230
1231 class CLong(Long):
1232 """A casting version of the long integer trait."""
1233
1234 def validate(self, obj, value):
1235 try:
1236 return long(value)
1237 except:
1238 self.error(obj, value)
1239
1240 class Integer(TraitType):
1241 """An integer trait.
1242
1243 Longs that are unnecessary (<= sys.maxint) are cast to ints."""
1244
1245 default_value = 0
1246 info_text = 'an integer'
1247
1248 def validate(self, obj, value):
1249 if isinstance(value, int):
1250 return value
1251 if isinstance(value, long):
1252 # downcast longs that fit in int:
1253 # note that int(n > sys.maxint) returns a long, so
1254 # we don't need a condition on this cast
1255 return int(value)
1256 if sys.platform == "cli":
1257 from System import Int64
1258 if isinstance(value, Int64):
1259 return int(value)
1260 self.error(obj, value)
1261
1262
1263 class Float(TraitType):
1264 """A float trait."""
1265
1266 default_value = 0.0
1267 info_text = 'a float'
1268
1269 def validate(self, obj, value):
1270 if isinstance(value, float):
1271 return value
1272 if isinstance(value, int):
1273 return float(value)
1274 self.error(obj, value)
1275
1276
1277 class CFloat(Float):
1278 """A casting version of the float trait."""
1279
1280 def validate(self, obj, value):
1281 try:
1282 return float(value)
1283 except:
1284 self.error(obj, value)
1285
1286 class Complex(TraitType):
1287 """A trait for complex numbers."""
1288
1289 default_value = 0.0 + 0.0j
1290 info_text = 'a complex number'
1291
1292 def validate(self, obj, value):
1293 if isinstance(value, complex):
1294 return value
1295 if isinstance(value, (float, int)):
1296 return complex(value)
1297 self.error(obj, value)
1298
1299
1300 class CComplex(Complex):
1301 """A casting version of the complex number trait."""
1302
1303 def validate (self, obj, value):
1304 try:
1305 return complex(value)
1306 except:
1307 self.error(obj, value)
1308
1309 # We should always be explicit about whether we're using bytes or unicode, both
1310 # for Python 3 conversion and for reliable unicode behaviour on Python 2. So
1311 # we don't have a Str type.
1312 class Bytes(TraitType):
1313 """A trait for byte strings."""
1314
1315 default_value = b''
1316 info_text = 'a bytes object'
1317
1318 def validate(self, obj, value):
1319 if isinstance(value, bytes):
1320 return value
1321 self.error(obj, value)
1322
1323
1324 class CBytes(Bytes):
1325 """A casting version of the byte string trait."""
1326
1327 def validate(self, obj, value):
1328 try:
1329 return bytes(value)
1330 except:
1331 self.error(obj, value)
1332
1333
1334 class Unicode(TraitType):
1335 """A trait for unicode strings."""
1336
1337 default_value = u''
1338 info_text = 'a unicode string'
1339
1340 def validate(self, obj, value):
1341 if isinstance(value, py3compat.unicode_type):
1342 return value
1343 if isinstance(value, bytes):
1344 try:
1345 return value.decode('ascii', 'strict')
1346 except UnicodeDecodeError:
1347 msg = "Could not decode {!r} for unicode trait '{}' of {} instance."
1348 raise TraitError(msg.format(value, self.name, class_of(obj)))
1349 self.error(obj, value)
1350
1351
1352 class CUnicode(Unicode):
1353 """A casting version of the unicode trait."""
1354
1355 def validate(self, obj, value):
1356 try:
1357 return py3compat.unicode_type(value)
1358 except:
1359 self.error(obj, value)
1360
1361
1362 class ObjectName(TraitType):
1363 """A string holding a valid object name in this version of Python.
1364
1365 This does not check that the name exists in any scope."""
1366 info_text = "a valid object identifier in Python"
1367
1368 if py3compat.PY3:
1369 # Python 3:
1370 coerce_str = staticmethod(lambda _,s: s)
1371
1372 else:
1373 # Python 2:
1374 def coerce_str(self, obj, value):
1375 "In Python 2, coerce ascii-only unicode to str"
1376 if isinstance(value, unicode):
1377 try:
1378 return str(value)
1379 except UnicodeEncodeError:
1380 self.error(obj, value)
1381 return value
1382
1383 def validate(self, obj, value):
1384 value = self.coerce_str(obj, value)
1385
1386 if isinstance(value, string_types) and py3compat.isidentifier(value):
1387 return value
1388 self.error(obj, value)
1389
1390 class DottedObjectName(ObjectName):
1391 """A string holding a valid dotted object name in Python, such as A.b3._c"""
1392 def validate(self, obj, value):
1393 value = self.coerce_str(obj, value)
1394
1395 if isinstance(value, string_types) and py3compat.isidentifier(value, dotted=True):
1396 return value
1397 self.error(obj, value)
1398
1399
1400 class Bool(TraitType):
1401 """A boolean (True, False) trait."""
1402
1403 default_value = False
1404 info_text = 'a boolean'
1405
1406 def validate(self, obj, value):
1407 if isinstance(value, bool):
1408 return value
1409 self.error(obj, value)
1410
1411
1412 class CBool(Bool):
1413 """A casting version of the boolean trait."""
1414
1415 def validate(self, obj, value):
1416 try:
1417 return bool(value)
1418 except:
1419 self.error(obj, value)
1420
1421
1422 class Enum(TraitType):
1423 """An enum that whose value must be in a given sequence."""
1424
1425 def __init__(self, values, default_value=None, **metadata):
1426 self.values = values
1427 super(Enum, self).__init__(default_value, **metadata)
1428
1429 def validate(self, obj, value):
1430 if value in self.values:
1431 return value
1432 self.error(obj, value)
1433
1434 def info(self):
1435 """ Returns a description of the trait."""
1436 result = 'any of ' + repr(self.values)
1437 if self.allow_none:
1438 return result + ' or None'
1439 return result
1440
1441 class CaselessStrEnum(Enum):
1442 """An enum of strings that are caseless in validate."""
1443
1444 def validate(self, obj, value):
1445 if not isinstance(value, py3compat.string_types):
1446 self.error(obj, value)
1447
1448 for v in self.values:
1449 if v.lower() == value.lower():
1450 return v
1451 self.error(obj, value)
1452
1453 class Container(Instance):
1454 """An instance of a container (list, set, etc.)
1455
1456 To be subclassed by overriding klass.
1457 """
1458 klass = None
1459 _cast_types = ()
1460 _valid_defaults = SequenceTypes
1461 _trait = None
1462
1463 def __init__(self, trait=None, default_value=None, allow_none=False,
1464 **metadata):
1465 """Create a container trait type from a list, set, or tuple.
1466
1467 The default value is created by doing ``List(default_value)``,
1468 which creates a copy of the ``default_value``.
1469
1470 ``trait`` can be specified, which restricts the type of elements
1471 in the container to that TraitType.
1472
1473 If only one arg is given and it is not a Trait, it is taken as
1474 ``default_value``:
1475
1476 ``c = List([1,2,3])``
1477
1478 Parameters
1479 ----------
1480
1481 trait : TraitType [ optional ]
1482 the type for restricting the contents of the Container. If unspecified,
1483 types are not checked.
1484
1485 default_value : SequenceType [ optional ]
1486 The default value for the Trait. Must be list/tuple/set, and
1487 will be cast to the container type.
1488
1489 allow_none : bool [ default False ]
1490 Whether to allow the value to be None
1491
1492 **metadata : any
1493 further keys for extensions to the Trait (e.g. config)
1494
1495 """
1496 # allow List([values]):
1497 if default_value is None and not is_trait(trait):
1498 default_value = trait
1499 trait = None
1500
1501 if default_value is None:
1502 args = ()
1503 elif isinstance(default_value, self._valid_defaults):
1504 args = (default_value,)
1505 else:
1506 raise TypeError('default value of %s was %s' %(self.__class__.__name__, default_value))
1507
1508 if is_trait(trait):
1509 self._trait = trait() if isinstance(trait, type) else trait
1510 self._trait.name = 'element'
1511 elif trait is not None:
1512 raise TypeError("`trait` must be a Trait or None, got %s"%repr_type(trait))
1513
1514 super(Container,self).__init__(klass=self.klass, args=args,
1515 allow_none=allow_none, **metadata)
1516
1517 def element_error(self, obj, element, validator):
1518 e = "Element of the '%s' trait of %s instance must be %s, but a value of %s was specified." \
1519 % (self.name, class_of(obj), validator.info(), repr_type(element))
1520 raise TraitError(e)
1521
1522 def validate(self, obj, value):
1523 if isinstance(value, self._cast_types):
1524 value = self.klass(value)
1525 value = super(Container, self).validate(obj, value)
1526 if value is None:
1527 return value
1528
1529 value = self.validate_elements(obj, value)
1530
1531 return value
1532
1533 def validate_elements(self, obj, value):
1534 validated = []
1535 if self._trait is None or isinstance(self._trait, Any):
1536 return value
1537 for v in value:
1538 try:
1539 v = self._trait._validate(obj, v)
1540 except TraitError:
1541 self.element_error(obj, v, self._trait)
1542 else:
1543 validated.append(v)
1544 return self.klass(validated)
1545
1546 def instance_init(self):
1547 if isinstance(self._trait, TraitType):
1548 self._trait.this_class = self.this_class
1549 self._trait.instance_init()
1550 super(Container, self).instance_init()
1551
1552
1553 class List(Container):
1554 """An instance of a Python list."""
1555 klass = list
1556 _cast_types = (tuple,)
1557
1558 def __init__(self, trait=None, default_value=None, minlen=0, maxlen=sys.maxsize, **metadata):
1559 """Create a List trait type from a list, set, or tuple.
1560
1561 The default value is created by doing ``List(default_value)``,
1562 which creates a copy of the ``default_value``.
1563
1564 ``trait`` can be specified, which restricts the type of elements
1565 in the container to that TraitType.
1566
1567 If only one arg is given and it is not a Trait, it is taken as
1568 ``default_value``:
1569
1570 ``c = List([1,2,3])``
1571
1572 Parameters
1573 ----------
1574
1575 trait : TraitType [ optional ]
1576 the type for restricting the contents of the Container. If unspecified,
1577 types are not checked.
1578
1579 default_value : SequenceType [ optional ]
1580 The default value for the Trait. Must be list/tuple/set, and
1581 will be cast to the container type.
1582
1583 minlen : Int [ default 0 ]
1584 The minimum length of the input list
1585
1586 maxlen : Int [ default sys.maxsize ]
1587 The maximum length of the input list
1588
1589 allow_none : bool [ default False ]
1590 Whether to allow the value to be None
1591
1592 **metadata : any
1593 further keys for extensions to the Trait (e.g. config)
1594
1595 """
1596 self._minlen = minlen
1597 self._maxlen = maxlen
1598 super(List, self).__init__(trait=trait, default_value=default_value,
1599 **metadata)
1600
1601 def length_error(self, obj, value):
1602 e = "The '%s' trait of %s instance must be of length %i <= L <= %i, but a value of %s was specified." \
1603 % (self.name, class_of(obj), self._minlen, self._maxlen, value)
1604 raise TraitError(e)
1605
1606 def validate_elements(self, obj, value):
1607 length = len(value)
1608 if length < self._minlen or length > self._maxlen:
1609 self.length_error(obj, value)
1610
1611 return super(List, self).validate_elements(obj, value)
1612
1613 def validate(self, obj, value):
1614 value = super(List, self).validate(obj, value)
1615 value = self.validate_elements(obj, value)
1616 return value
1617
1618
1619 class Set(List):
1620 """An instance of a Python set."""
1621 klass = set
1622 _cast_types = (tuple, list)
1623
1624
1625 class Tuple(Container):
1626 """An instance of a Python tuple."""
1627 klass = tuple
1628 _cast_types = (list,)
1629
1630 def __init__(self, *traits, **metadata):
1631 """Tuple(*traits, default_value=None, **medatata)
1632
1633 Create a tuple from a list, set, or tuple.
1634
1635 Create a fixed-type tuple with Traits:
1636
1637 ``t = Tuple(Int, Str, CStr)``
1638
1639 would be length 3, with Int,Str,CStr for each element.
1640
1641 If only one arg is given and it is not a Trait, it is taken as
1642 default_value:
1643
1644 ``t = Tuple((1,2,3))``
1645
1646 Otherwise, ``default_value`` *must* be specified by keyword.
1647
1648 Parameters
1649 ----------
1650
1651 *traits : TraitTypes [ optional ]
1652 the types for restricting the contents of the Tuple. If unspecified,
1653 types are not checked. If specified, then each positional argument
1654 corresponds to an element of the tuple. Tuples defined with traits
1655 are of fixed length.
1656
1657 default_value : SequenceType [ optional ]
1658 The default value for the Tuple. Must be list/tuple/set, and
1659 will be cast to a tuple. If `traits` are specified, the
1660 `default_value` must conform to the shape and type they specify.
1661
1662 allow_none : bool [ default False ]
1663 Whether to allow the value to be None
1664
1665 **metadata : any
1666 further keys for extensions to the Trait (e.g. config)
1667
1668 """
1669 default_value = metadata.pop('default_value', None)
1670 allow_none = metadata.pop('allow_none', True)
1671
1672 # allow Tuple((values,)):
1673 if len(traits) == 1 and default_value is None and not is_trait(traits[0]):
1674 default_value = traits[0]
1675 traits = ()
1676
1677 if default_value is None:
1678 args = ()
1679 elif isinstance(default_value, self._valid_defaults):
1680 args = (default_value,)
1681 else:
1682 raise TypeError('default value of %s was %s' %(self.__class__.__name__, default_value))
1683
1684 self._traits = []
1685 for trait in traits:
1686 t = trait() if isinstance(trait, type) else trait
1687 t.name = 'element'
1688 self._traits.append(t)
1689
1690 if self._traits and default_value is None:
1691 # don't allow default to be an empty container if length is specified
1692 args = None
1693 super(Container,self).__init__(klass=self.klass, args=args, allow_none=allow_none, **metadata)
1694
1695 def validate_elements(self, obj, value):
1696 if not self._traits:
1697 # nothing to validate
1698 return value
1699 if len(value) != len(self._traits):
1700 e = "The '%s' trait of %s instance requires %i elements, but a value of %s was specified." \
1701 % (self.name, class_of(obj), len(self._traits), repr_type(value))
1702 raise TraitError(e)
1703
1704 validated = []
1705 for t, v in zip(self._traits, value):
1706 try:
1707 v = t._validate(obj, v)
1708 except TraitError:
1709 self.element_error(obj, v, t)
1710 else:
1711 validated.append(v)
1712 return tuple(validated)
1713
1714 def instance_init(self):
1715 for trait in self._traits:
1716 if isinstance(trait, TraitType):
1717 trait.this_class = self.this_class
1718 trait.instance_init()
1719 super(Container, self).instance_init()
1720
1721
1722 class Dict(Instance):
1723 """An instance of a Python dict."""
1724 _trait = None
1725
1726 def __init__(self, trait=None, default_value=NoDefaultSpecified, allow_none=False, **metadata):
1727 """Create a dict trait type from a dict.
1728
1729 The default value is created by doing ``dict(default_value)``,
1730 which creates a copy of the ``default_value``.
1731
1732 trait : TraitType [ optional ]
1733 the type for restricting the contents of the Container. If unspecified,
1734 types are not checked.
1735
1736 default_value : SequenceType [ optional ]
1737 The default value for the Dict. Must be dict, tuple, or None, and
1738 will be cast to a dict if not None. If `trait` is specified, the
1739 `default_value` must conform to the constraints it specifies.
1740
1741 allow_none : bool [ default False ]
1742 Whether to allow the value to be None
1743
1744 """
1745 if default_value is NoDefaultSpecified and trait is not None:
1746 if not is_trait(trait):
1747 default_value = trait
1748 trait = None
1749 if default_value is NoDefaultSpecified:
1750 default_value = {}
1751 if default_value is None:
1752 args = None
1753 elif isinstance(default_value, dict):
1754 args = (default_value,)
1755 elif isinstance(default_value, SequenceTypes):
1756 args = (default_value,)
1757 else:
1758 raise TypeError('default value of Dict was %s' % default_value)
1759
1760 if is_trait(trait):
1761 self._trait = trait() if isinstance(trait, type) else trait
1762 self._trait.name = 'element'
1763 elif trait is not None:
1764 raise TypeError("`trait` must be a Trait or None, got %s"%repr_type(trait))
1765
1766 super(Dict,self).__init__(klass=dict, args=args,
1767 allow_none=allow_none, **metadata)
1768
1769 def element_error(self, obj, element, validator):
1770 e = "Element of the '%s' trait of %s instance must be %s, but a value of %s was specified." \
1771 % (self.name, class_of(obj), validator.info(), repr_type(element))
1772 raise TraitError(e)
1773
1774 def validate(self, obj, value):
1775 value = super(Dict, self).validate(obj, value)
1776 if value is None:
1777 return value
1778 value = self.validate_elements(obj, value)
1779 return value
1780
1781 def validate_elements(self, obj, value):
1782 if self._trait is None or isinstance(self._trait, Any):
1783 return value
1784 validated = {}
1785 for key in value:
1786 v = value[key]
1787 try:
1788 v = self._trait._validate(obj, v)
1789 except TraitError:
1790 self.element_error(obj, v, self._trait)
1791 else:
1792 validated[key] = v
1793 return self.klass(validated)
1794
1795 def instance_init(self):
1796 if isinstance(self._trait, TraitType):
1797 self._trait.this_class = self.this_class
1798 self._trait.instance_init()
1799 super(Dict, self).instance_init()
1800
1801
1802 class EventfulDict(Instance):
1803 """An instance of an EventfulDict."""
1804
1805 def __init__(self, default_value={}, allow_none=False, **metadata):
1806 """Create a EventfulDict trait type from a dict.
1807
1808 The default value is created by doing
1809 ``eventful.EvenfulDict(default_value)``, which creates a copy of the
1810 ``default_value``.
1811 """
1812 if default_value is None:
1813 args = None
1814 elif isinstance(default_value, dict):
1815 args = (default_value,)
1816 elif isinstance(default_value, SequenceTypes):
1817 args = (default_value,)
1818 else:
1819 raise TypeError('default value of EventfulDict was %s' % default_value)
1820
1821 super(EventfulDict, self).__init__(klass=eventful.EventfulDict, args=args,
1822 allow_none=allow_none, **metadata)
1823
1824
1825 class EventfulList(Instance):
1826 """An instance of an EventfulList."""
1827
1828 def __init__(self, default_value=None, allow_none=False, **metadata):
1829 """Create a EventfulList trait type from a dict.
1830
1831 The default value is created by doing
1832 ``eventful.EvenfulList(default_value)``, which creates a copy of the
1833 ``default_value``.
1834 """
1835 if default_value is None:
1836 args = ((),)
1837 else:
1838 args = (default_value,)
1839
1840 super(EventfulList, self).__init__(klass=eventful.EventfulList, args=args,
1841 allow_none=allow_none, **metadata)
1842
1843
1844 class TCPAddress(TraitType):
1845 """A trait for an (ip, port) tuple.
1846
1847 This allows for both IPv4 IP addresses as well as hostnames.
1848 """
1849
1850 default_value = ('127.0.0.1', 0)
1851 info_text = 'an (ip, port) tuple'
1852
1853 def validate(self, obj, value):
1854 if isinstance(value, tuple):
1855 if len(value) == 2:
1856 if isinstance(value[0], py3compat.string_types) and isinstance(value[1], int):
1857 port = value[1]
1858 if port >= 0 and port <= 65535:
1859 return value
1860 self.error(obj, value)
1861
1862 class CRegExp(TraitType):
1863 """A casting compiled regular expression trait.
1864
1865 Accepts both strings and compiled regular expressions. The resulting
1866 attribute will be a compiled regular expression."""
1867
1868 info_text = 'a regular expression'
1869
1870 def validate(self, obj, value):
1871 try:
1872 return re.compile(value)
1873 except:
1874 self.error(obj, value)
@@ -5,7 +5,7 b''
5
5
6 from unittest import TestCase
6 from unittest import TestCase
7 from IPython.utils.traitlets import HasTraits
7 from IPython.utils.traitlets import HasTraits
8 from IPython.utils.tests.test_traitlets import TraitTestBase
8 from traitlets.tests.test_traitlets import TraitTestBase
9 from IPython.html.widgets import Color
9 from IPython.html.widgets import Color
10
10
11
11
@@ -174,6 +174,7 b' shims = {'
174 'parallel': 'ipython_parallel',
174 'parallel': 'ipython_parallel',
175 'kernel': 'ipython_kernel',
175 'kernel': 'ipython_kernel',
176 'kernel.inprocess': 'ipython_kernel.inprocess',
176 'kernel.inprocess': 'ipython_kernel.inprocess',
177 'config': 'traitlets',
177 }
178 }
178
179
179 # Name -> (include, exclude, dependencies_met)
180 # Name -> (include, exclude, dependencies_met)
@@ -270,10 +271,6 b" if not have['pygments'] or not have['jinja2']:"
270 if not have['terminado']:
271 if not have['terminado']:
271 sec.exclude('terminal')
272 sec.exclude('terminal')
272
273
273 # config:
274 # Config files aren't really importable stand-alone
275 test_sections['config'].exclude('profile')
276
277 # nbconvert:
274 # nbconvert:
278 sec = test_sections['nbconvert']
275 sec = test_sections['nbconvert']
279 sec.requires('pygments', 'jinja2', 'jsonschema', 'mistune')
276 sec.requires('pygments', 'jinja2', 'jsonschema', 'mistune')
@@ -217,7 +217,10 b' def ipexec(fname, options=None, commands=()):'
217 full_fname = os.path.join(test_dir, fname)
217 full_fname = os.path.join(test_dir, fname)
218 full_cmd = ipython_cmd + cmdargs + [full_fname]
218 full_cmd = ipython_cmd + cmdargs + [full_fname]
219 env = os.environ.copy()
219 env = os.environ.copy()
220 env.pop('PYTHONWARNINGS', None) # Avoid extraneous warnings appearing on stderr
220 # FIXME: ignore all warnings in ipexec while we have shims
221 # should we keep suppressing warnings here, even after removing shims?
222 env['PYTHONWARNINGS'] = 'ignore'
223 # env.pop('PYTHONWARNINGS', None) # Avoid extraneous warnings appearing on stderr
221 for k, v in env.items():
224 for k, v in env.items():
222 # Debug a bizarre failure we've seen on Windows:
225 # Debug a bizarre failure we've seen on Windows:
223 # TypeError: environment can only contain strings
226 # TypeError: environment can only contain strings
This diff has been collapsed as it changes many lines, (1875 lines changed) Show them Hide them
@@ -1,1874 +1,3 b''
1 # encoding: utf-8
1 from __future__ import absolute_import
2 """
3 A lightweight Traits like module.
4
2
5 This is designed to provide a lightweight, simple, pure Python version of
3 from traitlets import *
6 many of the capabilities of enthought.traits. This includes:
7
8 * Validation
9 * Type specification with defaults
10 * Static and dynamic notification
11 * Basic predefined types
12 * An API that is similar to enthought.traits
13
14 We don't support:
15
16 * Delegation
17 * Automatic GUI generation
18 * A full set of trait types. Most importantly, we don't provide container
19 traits (list, dict, tuple) that can trigger notifications if their
20 contents change.
21 * API compatibility with enthought.traits
22
23 There are also some important difference in our design:
24
25 * enthought.traits does not validate default values. We do.
26
27 We choose to create this module because we need these capabilities, but
28 we need them to be pure Python so they work in all Python implementations,
29 including Jython and IronPython.
30
31 Inheritance diagram:
32
33 .. inheritance-diagram:: IPython.utils.traitlets
34 :parts: 3
35 """
36
37 # Copyright (c) IPython Development Team.
38 # Distributed under the terms of the Modified BSD License.
39 #
40 # Adapted from enthought.traits, Copyright (c) Enthought, Inc.,
41 # also under the terms of the Modified BSD License.
42
43 import contextlib
44 import inspect
45 import re
46 import sys
47 import types
48 from types import FunctionType
49 try:
50 from types import ClassType, InstanceType
51 ClassTypes = (ClassType, type)
52 except:
53 ClassTypes = (type,)
54 from warnings import warn
55
56 from .getargspec import getargspec
57 from .importstring import import_item
58 from IPython.utils import py3compat
59 from IPython.utils import eventful
60 from IPython.utils.py3compat import iteritems, string_types
61 from IPython.testing.skipdoctest import skip_doctest
62
63 SequenceTypes = (list, tuple, set, frozenset)
64
65 #-----------------------------------------------------------------------------
66 # Basic classes
67 #-----------------------------------------------------------------------------
68
69
70 class NoDefaultSpecified ( object ): pass
71 NoDefaultSpecified = NoDefaultSpecified()
72
73
74 class Undefined ( object ): pass
75 Undefined = Undefined()
76
77 class TraitError(Exception):
78 pass
79
80 #-----------------------------------------------------------------------------
81 # Utilities
82 #-----------------------------------------------------------------------------
83
84
85 def class_of ( object ):
86 """ Returns a string containing the class name of an object with the
87 correct indefinite article ('a' or 'an') preceding it (e.g., 'an Image',
88 'a PlotValue').
89 """
90 if isinstance( object, py3compat.string_types ):
91 return add_article( object )
92
93 return add_article( object.__class__.__name__ )
94
95
96 def add_article ( name ):
97 """ Returns a string containing the correct indefinite article ('a' or 'an')
98 prefixed to the specified string.
99 """
100 if name[:1].lower() in 'aeiou':
101 return 'an ' + name
102
103 return 'a ' + name
104
105
106 def repr_type(obj):
107 """ Return a string representation of a value and its type for readable
108 error messages.
109 """
110 the_type = type(obj)
111 if (not py3compat.PY3) and the_type is InstanceType:
112 # Old-style class.
113 the_type = obj.__class__
114 msg = '%r %r' % (obj, the_type)
115 return msg
116
117
118 def is_trait(t):
119 """ Returns whether the given value is an instance or subclass of TraitType.
120 """
121 return (isinstance(t, TraitType) or
122 (isinstance(t, type) and issubclass(t, TraitType)))
123
124
125 def parse_notifier_name(name):
126 """Convert the name argument to a list of names.
127
128 Examples
129 --------
130
131 >>> parse_notifier_name('a')
132 ['a']
133 >>> parse_notifier_name(['a','b'])
134 ['a', 'b']
135 >>> parse_notifier_name(None)
136 ['anytrait']
137 """
138 if isinstance(name, string_types):
139 return [name]
140 elif name is None:
141 return ['anytrait']
142 elif isinstance(name, (list, tuple)):
143 for n in name:
144 assert isinstance(n, string_types), "names must be strings"
145 return name
146
147
148 class _SimpleTest:
149 def __init__ ( self, value ): self.value = value
150 def __call__ ( self, test ):
151 return test == self.value
152 def __repr__(self):
153 return "<SimpleTest(%r)" % self.value
154 def __str__(self):
155 return self.__repr__()
156
157
158 def getmembers(object, predicate=None):
159 """A safe version of inspect.getmembers that handles missing attributes.
160
161 This is useful when there are descriptor based attributes that for
162 some reason raise AttributeError even though they exist. This happens
163 in zope.inteface with the __provides__ attribute.
164 """
165 results = []
166 for key in dir(object):
167 try:
168 value = getattr(object, key)
169 except AttributeError:
170 pass
171 else:
172 if not predicate or predicate(value):
173 results.append((key, value))
174 results.sort()
175 return results
176
177 def _validate_link(*tuples):
178 """Validate arguments for traitlet link functions"""
179 for t in tuples:
180 if not len(t) == 2:
181 raise TypeError("Each linked traitlet must be specified as (HasTraits, 'trait_name'), not %r" % t)
182 obj, trait_name = t
183 if not isinstance(obj, HasTraits):
184 raise TypeError("Each object must be HasTraits, not %r" % type(obj))
185 if not trait_name in obj.traits():
186 raise TypeError("%r has no trait %r" % (obj, trait_name))
187
188 @skip_doctest
189 class link(object):
190 """Link traits from different objects together so they remain in sync.
191
192 Parameters
193 ----------
194 *args : pairs of objects/attributes
195
196 Examples
197 --------
198
199 >>> c = link((obj1, 'value'), (obj2, 'value'), (obj3, 'value'))
200 >>> obj1.value = 5 # updates other objects as well
201 """
202 updating = False
203 def __init__(self, *args):
204 if len(args) < 2:
205 raise TypeError('At least two traitlets must be provided.')
206 _validate_link(*args)
207
208 self.objects = {}
209
210 initial = getattr(args[0][0], args[0][1])
211 for obj, attr in args:
212 setattr(obj, attr, initial)
213
214 callback = self._make_closure(obj, attr)
215 obj.on_trait_change(callback, attr)
216 self.objects[(obj, attr)] = callback
217
218 @contextlib.contextmanager
219 def _busy_updating(self):
220 self.updating = True
221 try:
222 yield
223 finally:
224 self.updating = False
225
226 def _make_closure(self, sending_obj, sending_attr):
227 def update(name, old, new):
228 self._update(sending_obj, sending_attr, new)
229 return update
230
231 def _update(self, sending_obj, sending_attr, new):
232 if self.updating:
233 return
234 with self._busy_updating():
235 for obj, attr in self.objects.keys():
236 setattr(obj, attr, new)
237
238 def unlink(self):
239 for key, callback in self.objects.items():
240 (obj, attr) = key
241 obj.on_trait_change(callback, attr, remove=True)
242
243 @skip_doctest
244 class directional_link(object):
245 """Link the trait of a source object with traits of target objects.
246
247 Parameters
248 ----------
249 source : pair of object, name
250 targets : pairs of objects/attributes
251
252 Examples
253 --------
254
255 >>> c = directional_link((src, 'value'), (tgt1, 'value'), (tgt2, 'value'))
256 >>> src.value = 5 # updates target objects
257 >>> tgt1.value = 6 # does not update other objects
258 """
259 updating = False
260
261 def __init__(self, source, *targets):
262 if len(targets) < 1:
263 raise TypeError('At least two traitlets must be provided.')
264 _validate_link(source, *targets)
265 self.source = source
266 self.targets = targets
267
268 # Update current value
269 src_attr_value = getattr(source[0], source[1])
270 for obj, attr in targets:
271 setattr(obj, attr, src_attr_value)
272
273 # Wire
274 self.source[0].on_trait_change(self._update, self.source[1])
275
276 @contextlib.contextmanager
277 def _busy_updating(self):
278 self.updating = True
279 try:
280 yield
281 finally:
282 self.updating = False
283
284 def _update(self, name, old, new):
285 if self.updating:
286 return
287 with self._busy_updating():
288 for obj, attr in self.targets:
289 setattr(obj, attr, new)
290
291 def unlink(self):
292 self.source[0].on_trait_change(self._update, self.source[1], remove=True)
293 self.source = None
294 self.targets = []
295
296 dlink = directional_link
297
298
299 #-----------------------------------------------------------------------------
300 # Base TraitType for all traits
301 #-----------------------------------------------------------------------------
302
303
304 class TraitType(object):
305 """A base class for all trait descriptors.
306
307 Notes
308 -----
309 Our implementation of traits is based on Python's descriptor
310 prototol. This class is the base class for all such descriptors. The
311 only magic we use is a custom metaclass for the main :class:`HasTraits`
312 class that does the following:
313
314 1. Sets the :attr:`name` attribute of every :class:`TraitType`
315 instance in the class dict to the name of the attribute.
316 2. Sets the :attr:`this_class` attribute of every :class:`TraitType`
317 instance in the class dict to the *class* that declared the trait.
318 This is used by the :class:`This` trait to allow subclasses to
319 accept superclasses for :class:`This` values.
320 """
321
322 metadata = {}
323 default_value = Undefined
324 allow_none = False
325 info_text = 'any value'
326
327 def __init__(self, default_value=NoDefaultSpecified, allow_none=None, **metadata):
328 """Create a TraitType.
329 """
330 if default_value is not NoDefaultSpecified:
331 self.default_value = default_value
332 if allow_none is not None:
333 self.allow_none = allow_none
334
335 if 'default' in metadata:
336 # Warn the user that they probably meant default_value.
337 warn(
338 "Parameter 'default' passed to TraitType. "
339 "Did you mean 'default_value'?"
340 )
341
342 if len(metadata) > 0:
343 if len(self.metadata) > 0:
344 self._metadata = self.metadata.copy()
345 self._metadata.update(metadata)
346 else:
347 self._metadata = metadata
348 else:
349 self._metadata = self.metadata
350
351 self.init()
352
353 def init(self):
354 pass
355
356 def get_default_value(self):
357 """Create a new instance of the default value."""
358 return self.default_value
359
360 def instance_init(self):
361 """Part of the initialization which may depends on the underlying
362 HasTraits instance.
363
364 It is typically overloaded for specific trait types.
365
366 This method is called by :meth:`HasTraits.__new__` and in the
367 :meth:`TraitType.instance_init` method of trait types holding
368 other trait types.
369 """
370 pass
371
372 def init_default_value(self, obj):
373 """Instantiate the default value for the trait type.
374
375 This method is called by :meth:`TraitType.set_default_value` in the
376 case a default value is provided at construction time or later when
377 accessing the trait value for the first time in
378 :meth:`HasTraits.__get__`.
379 """
380 value = self.get_default_value()
381 value = self._validate(obj, value)
382 obj._trait_values[self.name] = value
383 return value
384
385 def set_default_value(self, obj):
386 """Set the default value on a per instance basis.
387
388 This method is called by :meth:`HasTraits.__new__` to instantiate and
389 validate the default value. The creation and validation of
390 default values must be delayed until the parent :class:`HasTraits`
391 class has been instantiated.
392 Parameters
393 ----------
394 obj : :class:`HasTraits` instance
395 The parent :class:`HasTraits` instance that has just been
396 created.
397 """
398 # Check for a deferred initializer defined in the same class as the
399 # trait declaration or above.
400 mro = type(obj).mro()
401 meth_name = '_%s_default' % self.name
402 for cls in mro[:mro.index(self.this_class)+1]:
403 if meth_name in cls.__dict__:
404 break
405 else:
406 # We didn't find one. Do static initialization.
407 self.init_default_value(obj)
408 return
409 # Complete the dynamic initialization.
410 obj._trait_dyn_inits[self.name] = meth_name
411
412 def __get__(self, obj, cls=None):
413 """Get the value of the trait by self.name for the instance.
414
415 Default values are instantiated when :meth:`HasTraits.__new__`
416 is called. Thus by the time this method gets called either the
417 default value or a user defined value (they called :meth:`__set__`)
418 is in the :class:`HasTraits` instance.
419 """
420 if obj is None:
421 return self
422 else:
423 try:
424 value = obj._trait_values[self.name]
425 except KeyError:
426 # Check for a dynamic initializer.
427 if self.name in obj._trait_dyn_inits:
428 method = getattr(obj, obj._trait_dyn_inits[self.name])
429 value = method()
430 # FIXME: Do we really validate here?
431 value = self._validate(obj, value)
432 obj._trait_values[self.name] = value
433 return value
434 else:
435 return self.init_default_value(obj)
436 except Exception:
437 # HasTraits should call set_default_value to populate
438 # this. So this should never be reached.
439 raise TraitError('Unexpected error in TraitType: '
440 'default value not set properly')
441 else:
442 return value
443
444 def __set__(self, obj, value):
445 new_value = self._validate(obj, value)
446 try:
447 old_value = obj._trait_values[self.name]
448 except KeyError:
449 old_value = Undefined
450
451 obj._trait_values[self.name] = new_value
452 try:
453 silent = bool(old_value == new_value)
454 except:
455 # if there is an error in comparing, default to notify
456 silent = False
457 if silent is not True:
458 # we explicitly compare silent to True just in case the equality
459 # comparison above returns something other than True/False
460 obj._notify_trait(self.name, old_value, new_value)
461
462 def _validate(self, obj, value):
463 if value is None and self.allow_none:
464 return value
465 if hasattr(self, 'validate'):
466 value = self.validate(obj, value)
467 if obj._cross_validation_lock is False:
468 value = self._cross_validate(obj, value)
469 return value
470
471 def _cross_validate(self, obj, value):
472 if hasattr(obj, '_%s_validate' % self.name):
473 cross_validate = getattr(obj, '_%s_validate' % self.name)
474 value = cross_validate(value, self)
475 return value
476
477 def __or__(self, other):
478 if isinstance(other, Union):
479 return Union([self] + other.trait_types)
480 else:
481 return Union([self, other])
482
483 def info(self):
484 return self.info_text
485
486 def error(self, obj, value):
487 if obj is not None:
488 e = "The '%s' trait of %s instance must be %s, but a value of %s was specified." \
489 % (self.name, class_of(obj),
490 self.info(), repr_type(value))
491 else:
492 e = "The '%s' trait must be %s, but a value of %r was specified." \
493 % (self.name, self.info(), repr_type(value))
494 raise TraitError(e)
495
496 def get_metadata(self, key, default=None):
497 return getattr(self, '_metadata', {}).get(key, default)
498
499 def set_metadata(self, key, value):
500 getattr(self, '_metadata', {})[key] = value
501
502
503 #-----------------------------------------------------------------------------
504 # The HasTraits implementation
505 #-----------------------------------------------------------------------------
506
507
508 class MetaHasTraits(type):
509 """A metaclass for HasTraits.
510
511 This metaclass makes sure that any TraitType class attributes are
512 instantiated and sets their name attribute.
513 """
514
515 def __new__(mcls, name, bases, classdict):
516 """Create the HasTraits class.
517
518 This instantiates all TraitTypes in the class dict and sets their
519 :attr:`name` attribute.
520 """
521 # print "MetaHasTraitlets (mcls, name): ", mcls, name
522 # print "MetaHasTraitlets (bases): ", bases
523 # print "MetaHasTraitlets (classdict): ", classdict
524 for k,v in iteritems(classdict):
525 if isinstance(v, TraitType):
526 v.name = k
527 elif inspect.isclass(v):
528 if issubclass(v, TraitType):
529 vinst = v()
530 vinst.name = k
531 classdict[k] = vinst
532 return super(MetaHasTraits, mcls).__new__(mcls, name, bases, classdict)
533
534 def __init__(cls, name, bases, classdict):
535 """Finish initializing the HasTraits class.
536
537 This sets the :attr:`this_class` attribute of each TraitType in the
538 class dict to the newly created class ``cls``.
539 """
540 for k, v in iteritems(classdict):
541 if isinstance(v, TraitType):
542 v.this_class = cls
543 super(MetaHasTraits, cls).__init__(name, bases, classdict)
544
545
546 class HasTraits(py3compat.with_metaclass(MetaHasTraits, object)):
547
548 def __new__(cls, *args, **kw):
549 # This is needed because object.__new__ only accepts
550 # the cls argument.
551 new_meth = super(HasTraits, cls).__new__
552 if new_meth is object.__new__:
553 inst = new_meth(cls)
554 else:
555 inst = new_meth(cls, **kw)
556 inst._trait_values = {}
557 inst._trait_notifiers = {}
558 inst._trait_dyn_inits = {}
559 inst._cross_validation_lock = True
560 # Here we tell all the TraitType instances to set their default
561 # values on the instance.
562 for key in dir(cls):
563 # Some descriptors raise AttributeError like zope.interface's
564 # __provides__ attributes even though they exist. This causes
565 # AttributeErrors even though they are listed in dir(cls).
566 try:
567 value = getattr(cls, key)
568 except AttributeError:
569 pass
570 else:
571 if isinstance(value, TraitType):
572 value.instance_init()
573 if key not in kw:
574 value.set_default_value(inst)
575 inst._cross_validation_lock = False
576 return inst
577
578 def __init__(self, *args, **kw):
579 # Allow trait values to be set using keyword arguments.
580 # We need to use setattr for this to trigger validation and
581 # notifications.
582 with self.hold_trait_notifications():
583 for key, value in iteritems(kw):
584 setattr(self, key, value)
585
586 @contextlib.contextmanager
587 def hold_trait_notifications(self):
588 """Context manager for bundling trait change notifications and cross
589 validation.
590
591 Use this when doing multiple trait assignments (init, config), to avoid
592 race conditions in trait notifiers requesting other trait values.
593 All trait notifications will fire after all values have been assigned.
594 """
595 if self._cross_validation_lock is True:
596 yield
597 return
598 else:
599 self._cross_validation_lock = True
600 cache = {}
601 notifications = {}
602 _notify_trait = self._notify_trait
603
604 def cache_values(*a):
605 cache[a[0]] = a
606
607 def hold_notifications(*a):
608 notifications[a[0]] = a
609
610 self._notify_trait = cache_values
611
612 try:
613 yield
614 finally:
615 try:
616 self._notify_trait = hold_notifications
617 for name in cache:
618 if hasattr(self, '_%s_validate' % name):
619 cross_validate = getattr(self, '_%s_validate' % name)
620 setattr(self, name, cross_validate(getattr(self, name), self))
621 except TraitError as e:
622 self._notify_trait = lambda *x: None
623 for name in cache:
624 if cache[name][1] is not Undefined:
625 setattr(self, name, cache[name][1])
626 else:
627 delattr(self, name)
628 cache = {}
629 notifications = {}
630 raise e
631 finally:
632 self._notify_trait = _notify_trait
633 self._cross_validation_lock = False
634 if isinstance(_notify_trait, types.MethodType):
635 # FIXME: remove when support is bumped to 3.4.
636 # when original method is restored,
637 # remove the redundant value from __dict__
638 # (only used to preserve pickleability on Python < 3.4)
639 self.__dict__.pop('_notify_trait', None)
640 # trigger delayed notifications
641 for v in dict(cache, **notifications).values():
642 self._notify_trait(*v)
643
644 def _notify_trait(self, name, old_value, new_value):
645
646 # First dynamic ones
647 callables = []
648 callables.extend(self._trait_notifiers.get(name,[]))
649 callables.extend(self._trait_notifiers.get('anytrait',[]))
650
651 # Now static ones
652 try:
653 cb = getattr(self, '_%s_changed' % name)
654 except:
655 pass
656 else:
657 callables.append(cb)
658
659 # Call them all now
660 for c in callables:
661 # Traits catches and logs errors here. I allow them to raise
662 if callable(c):
663 argspec = getargspec(c)
664
665 nargs = len(argspec[0])
666 # Bound methods have an additional 'self' argument
667 # I don't know how to treat unbound methods, but they
668 # can't really be used for callbacks.
669 if isinstance(c, types.MethodType):
670 offset = -1
671 else:
672 offset = 0
673 if nargs + offset == 0:
674 c()
675 elif nargs + offset == 1:
676 c(name)
677 elif nargs + offset == 2:
678 c(name, new_value)
679 elif nargs + offset == 3:
680 c(name, old_value, new_value)
681 else:
682 raise TraitError('a trait changed callback '
683 'must have 0-3 arguments.')
684 else:
685 raise TraitError('a trait changed callback '
686 'must be callable.')
687
688
689 def _add_notifiers(self, handler, name):
690 if name not in self._trait_notifiers:
691 nlist = []
692 self._trait_notifiers[name] = nlist
693 else:
694 nlist = self._trait_notifiers[name]
695 if handler not in nlist:
696 nlist.append(handler)
697
698 def _remove_notifiers(self, handler, name):
699 if name in self._trait_notifiers:
700 nlist = self._trait_notifiers[name]
701 try:
702 index = nlist.index(handler)
703 except ValueError:
704 pass
705 else:
706 del nlist[index]
707
708 def on_trait_change(self, handler, name=None, remove=False):
709 """Setup a handler to be called when a trait changes.
710
711 This is used to setup dynamic notifications of trait changes.
712
713 Static handlers can be created by creating methods on a HasTraits
714 subclass with the naming convention '_[traitname]_changed'. Thus,
715 to create static handler for the trait 'a', create the method
716 _a_changed(self, name, old, new) (fewer arguments can be used, see
717 below).
718
719 Parameters
720 ----------
721 handler : callable
722 A callable that is called when a trait changes. Its
723 signature can be handler(), handler(name), handler(name, new)
724 or handler(name, old, new).
725 name : list, str, None
726 If None, the handler will apply to all traits. If a list
727 of str, handler will apply to all names in the list. If a
728 str, the handler will apply just to that name.
729 remove : bool
730 If False (the default), then install the handler. If True
731 then unintall it.
732 """
733 if remove:
734 names = parse_notifier_name(name)
735 for n in names:
736 self._remove_notifiers(handler, n)
737 else:
738 names = parse_notifier_name(name)
739 for n in names:
740 self._add_notifiers(handler, n)
741
742 @classmethod
743 def class_trait_names(cls, **metadata):
744 """Get a list of all the names of this class' traits.
745
746 This method is just like the :meth:`trait_names` method,
747 but is unbound.
748 """
749 return cls.class_traits(**metadata).keys()
750
751 @classmethod
752 def class_traits(cls, **metadata):
753 """Get a `dict` of all the traits of this class. The dictionary
754 is keyed on the name and the values are the TraitType objects.
755
756 This method is just like the :meth:`traits` method, but is unbound.
757
758 The TraitTypes returned don't know anything about the values
759 that the various HasTrait's instances are holding.
760
761 The metadata kwargs allow functions to be passed in which
762 filter traits based on metadata values. The functions should
763 take a single value as an argument and return a boolean. If
764 any function returns False, then the trait is not included in
765 the output. This does not allow for any simple way of
766 testing that a metadata name exists and has any
767 value because get_metadata returns None if a metadata key
768 doesn't exist.
769 """
770 traits = dict([memb for memb in getmembers(cls) if
771 isinstance(memb[1], TraitType)])
772
773 if len(metadata) == 0:
774 return traits
775
776 for meta_name, meta_eval in metadata.items():
777 if type(meta_eval) is not FunctionType:
778 metadata[meta_name] = _SimpleTest(meta_eval)
779
780 result = {}
781 for name, trait in traits.items():
782 for meta_name, meta_eval in metadata.items():
783 if not meta_eval(trait.get_metadata(meta_name)):
784 break
785 else:
786 result[name] = trait
787
788 return result
789
790 def trait_names(self, **metadata):
791 """Get a list of all the names of this class' traits."""
792 return self.traits(**metadata).keys()
793
794 def traits(self, **metadata):
795 """Get a `dict` of all the traits of this class. The dictionary
796 is keyed on the name and the values are the TraitType objects.
797
798 The TraitTypes returned don't know anything about the values
799 that the various HasTrait's instances are holding.
800
801 The metadata kwargs allow functions to be passed in which
802 filter traits based on metadata values. The functions should
803 take a single value as an argument and return a boolean. If
804 any function returns False, then the trait is not included in
805 the output. This does not allow for any simple way of
806 testing that a metadata name exists and has any
807 value because get_metadata returns None if a metadata key
808 doesn't exist.
809 """
810 traits = dict([memb for memb in getmembers(self.__class__) if
811 isinstance(memb[1], TraitType)])
812
813 if len(metadata) == 0:
814 return traits
815
816 for meta_name, meta_eval in metadata.items():
817 if type(meta_eval) is not FunctionType:
818 metadata[meta_name] = _SimpleTest(meta_eval)
819
820 result = {}
821 for name, trait in traits.items():
822 for meta_name, meta_eval in metadata.items():
823 if not meta_eval(trait.get_metadata(meta_name)):
824 break
825 else:
826 result[name] = trait
827
828 return result
829
830 def trait_metadata(self, traitname, key, default=None):
831 """Get metadata values for trait by key."""
832 try:
833 trait = getattr(self.__class__, traitname)
834 except AttributeError:
835 raise TraitError("Class %s does not have a trait named %s" %
836 (self.__class__.__name__, traitname))
837 else:
838 return trait.get_metadata(key, default)
839
840 def add_trait(self, traitname, trait):
841 """Dynamically add a trait attribute to the HasTraits instance."""
842 self.__class__ = type(self.__class__.__name__, (self.__class__,),
843 {traitname: trait})
844 trait.set_default_value(self)
845
846 #-----------------------------------------------------------------------------
847 # Actual TraitTypes implementations/subclasses
848 #-----------------------------------------------------------------------------
849
850 #-----------------------------------------------------------------------------
851 # TraitTypes subclasses for handling classes and instances of classes
852 #-----------------------------------------------------------------------------
853
854
855 class ClassBasedTraitType(TraitType):
856 """
857 A trait with error reporting and string -> type resolution for Type,
858 Instance and This.
859 """
860
861 def _resolve_string(self, string):
862 """
863 Resolve a string supplied for a type into an actual object.
864 """
865 return import_item(string)
866
867 def error(self, obj, value):
868 kind = type(value)
869 if (not py3compat.PY3) and kind is InstanceType:
870 msg = 'class %s' % value.__class__.__name__
871 else:
872 msg = '%s (i.e. %s)' % ( str( kind )[1:-1], repr( value ) )
873
874 if obj is not None:
875 e = "The '%s' trait of %s instance must be %s, but a value of %s was specified." \
876 % (self.name, class_of(obj),
877 self.info(), msg)
878 else:
879 e = "The '%s' trait must be %s, but a value of %r was specified." \
880 % (self.name, self.info(), msg)
881
882 raise TraitError(e)
883
884
885 class Type(ClassBasedTraitType):
886 """A trait whose value must be a subclass of a specified class."""
887
888 def __init__ (self, default_value=None, klass=None, allow_none=False,
889 **metadata):
890 """Construct a Type trait
891
892 A Type trait specifies that its values must be subclasses of
893 a particular class.
894
895 If only ``default_value`` is given, it is used for the ``klass`` as
896 well.
897
898 Parameters
899 ----------
900 default_value : class, str or None
901 The default value must be a subclass of klass. If an str,
902 the str must be a fully specified class name, like 'foo.bar.Bah'.
903 The string is resolved into real class, when the parent
904 :class:`HasTraits` class is instantiated.
905 klass : class, str, None
906 Values of this trait must be a subclass of klass. The klass
907 may be specified in a string like: 'foo.bar.MyClass'.
908 The string is resolved into real class, when the parent
909 :class:`HasTraits` class is instantiated.
910 allow_none : bool [ default True ]
911 Indicates whether None is allowed as an assignable value. Even if
912 ``False``, the default value may be ``None``.
913 """
914 if default_value is None:
915 if klass is None:
916 klass = object
917 elif klass is None:
918 klass = default_value
919
920 if not (inspect.isclass(klass) or isinstance(klass, py3compat.string_types)):
921 raise TraitError("A Type trait must specify a class.")
922
923 self.klass = klass
924
925 super(Type, self).__init__(default_value, allow_none=allow_none, **metadata)
926
927 def validate(self, obj, value):
928 """Validates that the value is a valid object instance."""
929 if isinstance(value, py3compat.string_types):
930 try:
931 value = self._resolve_string(value)
932 except ImportError:
933 raise TraitError("The '%s' trait of %s instance must be a type, but "
934 "%r could not be imported" % (self.name, obj, value))
935 try:
936 if issubclass(value, self.klass):
937 return value
938 except:
939 pass
940
941 self.error(obj, value)
942
943 def info(self):
944 """ Returns a description of the trait."""
945 if isinstance(self.klass, py3compat.string_types):
946 klass = self.klass
947 else:
948 klass = self.klass.__name__
949 result = 'a subclass of ' + klass
950 if self.allow_none:
951 return result + ' or None'
952 return result
953
954 def instance_init(self):
955 self._resolve_classes()
956 super(Type, self).instance_init()
957
958 def _resolve_classes(self):
959 if isinstance(self.klass, py3compat.string_types):
960 self.klass = self._resolve_string(self.klass)
961 if isinstance(self.default_value, py3compat.string_types):
962 self.default_value = self._resolve_string(self.default_value)
963
964 def get_default_value(self):
965 return self.default_value
966
967
968 class DefaultValueGenerator(object):
969 """A class for generating new default value instances."""
970
971 def __init__(self, *args, **kw):
972 self.args = args
973 self.kw = kw
974
975 def generate(self, klass):
976 return klass(*self.args, **self.kw)
977
978
979 class Instance(ClassBasedTraitType):
980 """A trait whose value must be an instance of a specified class.
981
982 The value can also be an instance of a subclass of the specified class.
983
984 Subclasses can declare default classes by overriding the klass attribute
985 """
986
987 klass = None
988
989 def __init__(self, klass=None, args=None, kw=None, allow_none=False,
990 **metadata ):
991 """Construct an Instance trait.
992
993 This trait allows values that are instances of a particular
994 class or its subclasses. Our implementation is quite different
995 from that of enthough.traits as we don't allow instances to be used
996 for klass and we handle the ``args`` and ``kw`` arguments differently.
997
998 Parameters
999 ----------
1000 klass : class, str
1001 The class that forms the basis for the trait. Class names
1002 can also be specified as strings, like 'foo.bar.Bar'.
1003 args : tuple
1004 Positional arguments for generating the default value.
1005 kw : dict
1006 Keyword arguments for generating the default value.
1007 allow_none : bool [default True]
1008 Indicates whether None is allowed as a value.
1009
1010 Notes
1011 -----
1012 If both ``args`` and ``kw`` are None, then the default value is None.
1013 If ``args`` is a tuple and ``kw`` is a dict, then the default is
1014 created as ``klass(*args, **kw)``. If exactly one of ``args`` or ``kw`` is
1015 None, the None is replaced by ``()`` or ``{}``, respectively.
1016 """
1017 if klass is None:
1018 klass = self.klass
1019
1020 if (klass is not None) and (inspect.isclass(klass) or isinstance(klass, py3compat.string_types)):
1021 self.klass = klass
1022 else:
1023 raise TraitError('The klass attribute must be a class'
1024 ' not: %r' % klass)
1025
1026 # self.klass is a class, so handle default_value
1027 if args is None and kw is None:
1028 default_value = None
1029 else:
1030 if args is None:
1031 # kw is not None
1032 args = ()
1033 elif kw is None:
1034 # args is not None
1035 kw = {}
1036
1037 if not isinstance(kw, dict):
1038 raise TraitError("The 'kw' argument must be a dict or None.")
1039 if not isinstance(args, tuple):
1040 raise TraitError("The 'args' argument must be a tuple or None.")
1041
1042 default_value = DefaultValueGenerator(*args, **kw)
1043
1044 super(Instance, self).__init__(default_value, allow_none=allow_none, **metadata)
1045
1046 def validate(self, obj, value):
1047 if isinstance(value, self.klass):
1048 return value
1049 else:
1050 self.error(obj, value)
1051
1052 def info(self):
1053 if isinstance(self.klass, py3compat.string_types):
1054 klass = self.klass
1055 else:
1056 klass = self.klass.__name__
1057 result = class_of(klass)
1058 if self.allow_none:
1059 return result + ' or None'
1060
1061 return result
1062
1063 def instance_init(self):
1064 self._resolve_classes()
1065 super(Instance, self).instance_init()
1066
1067 def _resolve_classes(self):
1068 if isinstance(self.klass, py3compat.string_types):
1069 self.klass = self._resolve_string(self.klass)
1070
1071 def get_default_value(self):
1072 """Instantiate a default value instance.
1073
1074 This is called when the containing HasTraits classes'
1075 :meth:`__new__` method is called to ensure that a unique instance
1076 is created for each HasTraits instance.
1077 """
1078 dv = self.default_value
1079 if isinstance(dv, DefaultValueGenerator):
1080 return dv.generate(self.klass)
1081 else:
1082 return dv
1083
1084
1085 class ForwardDeclaredMixin(object):
1086 """
1087 Mixin for forward-declared versions of Instance and Type.
1088 """
1089 def _resolve_string(self, string):
1090 """
1091 Find the specified class name by looking for it in the module in which
1092 our this_class attribute was defined.
1093 """
1094 modname = self.this_class.__module__
1095 return import_item('.'.join([modname, string]))
1096
1097
1098 class ForwardDeclaredType(ForwardDeclaredMixin, Type):
1099 """
1100 Forward-declared version of Type.
1101 """
1102 pass
1103
1104
1105 class ForwardDeclaredInstance(ForwardDeclaredMixin, Instance):
1106 """
1107 Forward-declared version of Instance.
1108 """
1109 pass
1110
1111
1112 class This(ClassBasedTraitType):
1113 """A trait for instances of the class containing this trait.
1114
1115 Because how how and when class bodies are executed, the ``This``
1116 trait can only have a default value of None. This, and because we
1117 always validate default values, ``allow_none`` is *always* true.
1118 """
1119
1120 info_text = 'an instance of the same type as the receiver or None'
1121
1122 def __init__(self, **metadata):
1123 super(This, self).__init__(None, **metadata)
1124
1125 def validate(self, obj, value):
1126 # What if value is a superclass of obj.__class__? This is
1127 # complicated if it was the superclass that defined the This
1128 # trait.
1129 if isinstance(value, self.this_class) or (value is None):
1130 return value
1131 else:
1132 self.error(obj, value)
1133
1134
1135 class Union(TraitType):
1136 """A trait type representing a Union type."""
1137
1138 def __init__(self, trait_types, **metadata):
1139 """Construct a Union trait.
1140
1141 This trait allows values that are allowed by at least one of the
1142 specified trait types. A Union traitlet cannot have metadata on
1143 its own, besides the metadata of the listed types.
1144
1145 Parameters
1146 ----------
1147 trait_types: sequence
1148 The list of trait types of length at least 1.
1149
1150 Notes
1151 -----
1152 Union([Float(), Bool(), Int()]) attempts to validate the provided values
1153 with the validation function of Float, then Bool, and finally Int.
1154 """
1155 self.trait_types = trait_types
1156 self.info_text = " or ".join([tt.info_text for tt in self.trait_types])
1157 self.default_value = self.trait_types[0].get_default_value()
1158 super(Union, self).__init__(**metadata)
1159
1160 def instance_init(self):
1161 for trait_type in self.trait_types:
1162 trait_type.name = self.name
1163 trait_type.this_class = self.this_class
1164 trait_type.instance_init()
1165 super(Union, self).instance_init()
1166
1167 def validate(self, obj, value):
1168 for trait_type in self.trait_types:
1169 try:
1170 v = trait_type._validate(obj, value)
1171 self._metadata = trait_type._metadata
1172 return v
1173 except TraitError:
1174 continue
1175 self.error(obj, value)
1176
1177 def __or__(self, other):
1178 if isinstance(other, Union):
1179 return Union(self.trait_types + other.trait_types)
1180 else:
1181 return Union(self.trait_types + [other])
1182
1183 #-----------------------------------------------------------------------------
1184 # Basic TraitTypes implementations/subclasses
1185 #-----------------------------------------------------------------------------
1186
1187
1188 class Any(TraitType):
1189 default_value = None
1190 info_text = 'any value'
1191
1192
1193 class Int(TraitType):
1194 """An int trait."""
1195
1196 default_value = 0
1197 info_text = 'an int'
1198
1199 def validate(self, obj, value):
1200 if isinstance(value, int):
1201 return value
1202 self.error(obj, value)
1203
1204 class CInt(Int):
1205 """A casting version of the int trait."""
1206
1207 def validate(self, obj, value):
1208 try:
1209 return int(value)
1210 except:
1211 self.error(obj, value)
1212
1213 if py3compat.PY3:
1214 Long, CLong = Int, CInt
1215 Integer = Int
1216 else:
1217 class Long(TraitType):
1218 """A long integer trait."""
1219
1220 default_value = 0
1221 info_text = 'a long'
1222
1223 def validate(self, obj, value):
1224 if isinstance(value, long):
1225 return value
1226 if isinstance(value, int):
1227 return long(value)
1228 self.error(obj, value)
1229
1230
1231 class CLong(Long):
1232 """A casting version of the long integer trait."""
1233
1234 def validate(self, obj, value):
1235 try:
1236 return long(value)
1237 except:
1238 self.error(obj, value)
1239
1240 class Integer(TraitType):
1241 """An integer trait.
1242
1243 Longs that are unnecessary (<= sys.maxint) are cast to ints."""
1244
1245 default_value = 0
1246 info_text = 'an integer'
1247
1248 def validate(self, obj, value):
1249 if isinstance(value, int):
1250 return value
1251 if isinstance(value, long):
1252 # downcast longs that fit in int:
1253 # note that int(n > sys.maxint) returns a long, so
1254 # we don't need a condition on this cast
1255 return int(value)
1256 if sys.platform == "cli":
1257 from System import Int64
1258 if isinstance(value, Int64):
1259 return int(value)
1260 self.error(obj, value)
1261
1262
1263 class Float(TraitType):
1264 """A float trait."""
1265
1266 default_value = 0.0
1267 info_text = 'a float'
1268
1269 def validate(self, obj, value):
1270 if isinstance(value, float):
1271 return value
1272 if isinstance(value, int):
1273 return float(value)
1274 self.error(obj, value)
1275
1276
1277 class CFloat(Float):
1278 """A casting version of the float trait."""
1279
1280 def validate(self, obj, value):
1281 try:
1282 return float(value)
1283 except:
1284 self.error(obj, value)
1285
1286 class Complex(TraitType):
1287 """A trait for complex numbers."""
1288
1289 default_value = 0.0 + 0.0j
1290 info_text = 'a complex number'
1291
1292 def validate(self, obj, value):
1293 if isinstance(value, complex):
1294 return value
1295 if isinstance(value, (float, int)):
1296 return complex(value)
1297 self.error(obj, value)
1298
1299
1300 class CComplex(Complex):
1301 """A casting version of the complex number trait."""
1302
1303 def validate (self, obj, value):
1304 try:
1305 return complex(value)
1306 except:
1307 self.error(obj, value)
1308
1309 # We should always be explicit about whether we're using bytes or unicode, both
1310 # for Python 3 conversion and for reliable unicode behaviour on Python 2. So
1311 # we don't have a Str type.
1312 class Bytes(TraitType):
1313 """A trait for byte strings."""
1314
1315 default_value = b''
1316 info_text = 'a bytes object'
1317
1318 def validate(self, obj, value):
1319 if isinstance(value, bytes):
1320 return value
1321 self.error(obj, value)
1322
1323
1324 class CBytes(Bytes):
1325 """A casting version of the byte string trait."""
1326
1327 def validate(self, obj, value):
1328 try:
1329 return bytes(value)
1330 except:
1331 self.error(obj, value)
1332
1333
1334 class Unicode(TraitType):
1335 """A trait for unicode strings."""
1336
1337 default_value = u''
1338 info_text = 'a unicode string'
1339
1340 def validate(self, obj, value):
1341 if isinstance(value, py3compat.unicode_type):
1342 return value
1343 if isinstance(value, bytes):
1344 try:
1345 return value.decode('ascii', 'strict')
1346 except UnicodeDecodeError:
1347 msg = "Could not decode {!r} for unicode trait '{}' of {} instance."
1348 raise TraitError(msg.format(value, self.name, class_of(obj)))
1349 self.error(obj, value)
1350
1351
1352 class CUnicode(Unicode):
1353 """A casting version of the unicode trait."""
1354
1355 def validate(self, obj, value):
1356 try:
1357 return py3compat.unicode_type(value)
1358 except:
1359 self.error(obj, value)
1360
1361
1362 class ObjectName(TraitType):
1363 """A string holding a valid object name in this version of Python.
1364
1365 This does not check that the name exists in any scope."""
1366 info_text = "a valid object identifier in Python"
1367
1368 if py3compat.PY3:
1369 # Python 3:
1370 coerce_str = staticmethod(lambda _,s: s)
1371
1372 else:
1373 # Python 2:
1374 def coerce_str(self, obj, value):
1375 "In Python 2, coerce ascii-only unicode to str"
1376 if isinstance(value, unicode):
1377 try:
1378 return str(value)
1379 except UnicodeEncodeError:
1380 self.error(obj, value)
1381 return value
1382
1383 def validate(self, obj, value):
1384 value = self.coerce_str(obj, value)
1385
1386 if isinstance(value, string_types) and py3compat.isidentifier(value):
1387 return value
1388 self.error(obj, value)
1389
1390 class DottedObjectName(ObjectName):
1391 """A string holding a valid dotted object name in Python, such as A.b3._c"""
1392 def validate(self, obj, value):
1393 value = self.coerce_str(obj, value)
1394
1395 if isinstance(value, string_types) and py3compat.isidentifier(value, dotted=True):
1396 return value
1397 self.error(obj, value)
1398
1399
1400 class Bool(TraitType):
1401 """A boolean (True, False) trait."""
1402
1403 default_value = False
1404 info_text = 'a boolean'
1405
1406 def validate(self, obj, value):
1407 if isinstance(value, bool):
1408 return value
1409 self.error(obj, value)
1410
1411
1412 class CBool(Bool):
1413 """A casting version of the boolean trait."""
1414
1415 def validate(self, obj, value):
1416 try:
1417 return bool(value)
1418 except:
1419 self.error(obj, value)
1420
1421
1422 class Enum(TraitType):
1423 """An enum that whose value must be in a given sequence."""
1424
1425 def __init__(self, values, default_value=None, **metadata):
1426 self.values = values
1427 super(Enum, self).__init__(default_value, **metadata)
1428
1429 def validate(self, obj, value):
1430 if value in self.values:
1431 return value
1432 self.error(obj, value)
1433
1434 def info(self):
1435 """ Returns a description of the trait."""
1436 result = 'any of ' + repr(self.values)
1437 if self.allow_none:
1438 return result + ' or None'
1439 return result
1440
1441 class CaselessStrEnum(Enum):
1442 """An enum of strings that are caseless in validate."""
1443
1444 def validate(self, obj, value):
1445 if not isinstance(value, py3compat.string_types):
1446 self.error(obj, value)
1447
1448 for v in self.values:
1449 if v.lower() == value.lower():
1450 return v
1451 self.error(obj, value)
1452
1453 class Container(Instance):
1454 """An instance of a container (list, set, etc.)
1455
1456 To be subclassed by overriding klass.
1457 """
1458 klass = None
1459 _cast_types = ()
1460 _valid_defaults = SequenceTypes
1461 _trait = None
1462
1463 def __init__(self, trait=None, default_value=None, allow_none=False,
1464 **metadata):
1465 """Create a container trait type from a list, set, or tuple.
1466
1467 The default value is created by doing ``List(default_value)``,
1468 which creates a copy of the ``default_value``.
1469
1470 ``trait`` can be specified, which restricts the type of elements
1471 in the container to that TraitType.
1472
1473 If only one arg is given and it is not a Trait, it is taken as
1474 ``default_value``:
1475
1476 ``c = List([1,2,3])``
1477
1478 Parameters
1479 ----------
1480
1481 trait : TraitType [ optional ]
1482 the type for restricting the contents of the Container. If unspecified,
1483 types are not checked.
1484
1485 default_value : SequenceType [ optional ]
1486 The default value for the Trait. Must be list/tuple/set, and
1487 will be cast to the container type.
1488
1489 allow_none : bool [ default False ]
1490 Whether to allow the value to be None
1491
1492 **metadata : any
1493 further keys for extensions to the Trait (e.g. config)
1494
1495 """
1496 # allow List([values]):
1497 if default_value is None and not is_trait(trait):
1498 default_value = trait
1499 trait = None
1500
1501 if default_value is None:
1502 args = ()
1503 elif isinstance(default_value, self._valid_defaults):
1504 args = (default_value,)
1505 else:
1506 raise TypeError('default value of %s was %s' %(self.__class__.__name__, default_value))
1507
1508 if is_trait(trait):
1509 self._trait = trait() if isinstance(trait, type) else trait
1510 self._trait.name = 'element'
1511 elif trait is not None:
1512 raise TypeError("`trait` must be a Trait or None, got %s"%repr_type(trait))
1513
1514 super(Container,self).__init__(klass=self.klass, args=args,
1515 allow_none=allow_none, **metadata)
1516
1517 def element_error(self, obj, element, validator):
1518 e = "Element of the '%s' trait of %s instance must be %s, but a value of %s was specified." \
1519 % (self.name, class_of(obj), validator.info(), repr_type(element))
1520 raise TraitError(e)
1521
1522 def validate(self, obj, value):
1523 if isinstance(value, self._cast_types):
1524 value = self.klass(value)
1525 value = super(Container, self).validate(obj, value)
1526 if value is None:
1527 return value
1528
1529 value = self.validate_elements(obj, value)
1530
1531 return value
1532
1533 def validate_elements(self, obj, value):
1534 validated = []
1535 if self._trait is None or isinstance(self._trait, Any):
1536 return value
1537 for v in value:
1538 try:
1539 v = self._trait._validate(obj, v)
1540 except TraitError:
1541 self.element_error(obj, v, self._trait)
1542 else:
1543 validated.append(v)
1544 return self.klass(validated)
1545
1546 def instance_init(self):
1547 if isinstance(self._trait, TraitType):
1548 self._trait.this_class = self.this_class
1549 self._trait.instance_init()
1550 super(Container, self).instance_init()
1551
1552
1553 class List(Container):
1554 """An instance of a Python list."""
1555 klass = list
1556 _cast_types = (tuple,)
1557
1558 def __init__(self, trait=None, default_value=None, minlen=0, maxlen=sys.maxsize, **metadata):
1559 """Create a List trait type from a list, set, or tuple.
1560
1561 The default value is created by doing ``List(default_value)``,
1562 which creates a copy of the ``default_value``.
1563
1564 ``trait`` can be specified, which restricts the type of elements
1565 in the container to that TraitType.
1566
1567 If only one arg is given and it is not a Trait, it is taken as
1568 ``default_value``:
1569
1570 ``c = List([1,2,3])``
1571
1572 Parameters
1573 ----------
1574
1575 trait : TraitType [ optional ]
1576 the type for restricting the contents of the Container. If unspecified,
1577 types are not checked.
1578
1579 default_value : SequenceType [ optional ]
1580 The default value for the Trait. Must be list/tuple/set, and
1581 will be cast to the container type.
1582
1583 minlen : Int [ default 0 ]
1584 The minimum length of the input list
1585
1586 maxlen : Int [ default sys.maxsize ]
1587 The maximum length of the input list
1588
1589 allow_none : bool [ default False ]
1590 Whether to allow the value to be None
1591
1592 **metadata : any
1593 further keys for extensions to the Trait (e.g. config)
1594
1595 """
1596 self._minlen = minlen
1597 self._maxlen = maxlen
1598 super(List, self).__init__(trait=trait, default_value=default_value,
1599 **metadata)
1600
1601 def length_error(self, obj, value):
1602 e = "The '%s' trait of %s instance must be of length %i <= L <= %i, but a value of %s was specified." \
1603 % (self.name, class_of(obj), self._minlen, self._maxlen, value)
1604 raise TraitError(e)
1605
1606 def validate_elements(self, obj, value):
1607 length = len(value)
1608 if length < self._minlen or length > self._maxlen:
1609 self.length_error(obj, value)
1610
1611 return super(List, self).validate_elements(obj, value)
1612
1613 def validate(self, obj, value):
1614 value = super(List, self).validate(obj, value)
1615 value = self.validate_elements(obj, value)
1616 return value
1617
1618
1619 class Set(List):
1620 """An instance of a Python set."""
1621 klass = set
1622 _cast_types = (tuple, list)
1623
1624
1625 class Tuple(Container):
1626 """An instance of a Python tuple."""
1627 klass = tuple
1628 _cast_types = (list,)
1629
1630 def __init__(self, *traits, **metadata):
1631 """Tuple(*traits, default_value=None, **medatata)
1632
1633 Create a tuple from a list, set, or tuple.
1634
1635 Create a fixed-type tuple with Traits:
1636
1637 ``t = Tuple(Int, Str, CStr)``
1638
1639 would be length 3, with Int,Str,CStr for each element.
1640
1641 If only one arg is given and it is not a Trait, it is taken as
1642 default_value:
1643
1644 ``t = Tuple((1,2,3))``
1645
1646 Otherwise, ``default_value`` *must* be specified by keyword.
1647
1648 Parameters
1649 ----------
1650
1651 *traits : TraitTypes [ optional ]
1652 the types for restricting the contents of the Tuple. If unspecified,
1653 types are not checked. If specified, then each positional argument
1654 corresponds to an element of the tuple. Tuples defined with traits
1655 are of fixed length.
1656
1657 default_value : SequenceType [ optional ]
1658 The default value for the Tuple. Must be list/tuple/set, and
1659 will be cast to a tuple. If `traits` are specified, the
1660 `default_value` must conform to the shape and type they specify.
1661
1662 allow_none : bool [ default False ]
1663 Whether to allow the value to be None
1664
1665 **metadata : any
1666 further keys for extensions to the Trait (e.g. config)
1667
1668 """
1669 default_value = metadata.pop('default_value', None)
1670 allow_none = metadata.pop('allow_none', True)
1671
1672 # allow Tuple((values,)):
1673 if len(traits) == 1 and default_value is None and not is_trait(traits[0]):
1674 default_value = traits[0]
1675 traits = ()
1676
1677 if default_value is None:
1678 args = ()
1679 elif isinstance(default_value, self._valid_defaults):
1680 args = (default_value,)
1681 else:
1682 raise TypeError('default value of %s was %s' %(self.__class__.__name__, default_value))
1683
1684 self._traits = []
1685 for trait in traits:
1686 t = trait() if isinstance(trait, type) else trait
1687 t.name = 'element'
1688 self._traits.append(t)
1689
1690 if self._traits and default_value is None:
1691 # don't allow default to be an empty container if length is specified
1692 args = None
1693 super(Container,self).__init__(klass=self.klass, args=args, allow_none=allow_none, **metadata)
1694
1695 def validate_elements(self, obj, value):
1696 if not self._traits:
1697 # nothing to validate
1698 return value
1699 if len(value) != len(self._traits):
1700 e = "The '%s' trait of %s instance requires %i elements, but a value of %s was specified." \
1701 % (self.name, class_of(obj), len(self._traits), repr_type(value))
1702 raise TraitError(e)
1703
1704 validated = []
1705 for t, v in zip(self._traits, value):
1706 try:
1707 v = t._validate(obj, v)
1708 except TraitError:
1709 self.element_error(obj, v, t)
1710 else:
1711 validated.append(v)
1712 return tuple(validated)
1713
1714 def instance_init(self):
1715 for trait in self._traits:
1716 if isinstance(trait, TraitType):
1717 trait.this_class = self.this_class
1718 trait.instance_init()
1719 super(Container, self).instance_init()
1720
1721
1722 class Dict(Instance):
1723 """An instance of a Python dict."""
1724 _trait = None
1725
1726 def __init__(self, trait=None, default_value=NoDefaultSpecified, allow_none=False, **metadata):
1727 """Create a dict trait type from a dict.
1728
1729 The default value is created by doing ``dict(default_value)``,
1730 which creates a copy of the ``default_value``.
1731
1732 trait : TraitType [ optional ]
1733 the type for restricting the contents of the Container. If unspecified,
1734 types are not checked.
1735
1736 default_value : SequenceType [ optional ]
1737 The default value for the Dict. Must be dict, tuple, or None, and
1738 will be cast to a dict if not None. If `trait` is specified, the
1739 `default_value` must conform to the constraints it specifies.
1740
1741 allow_none : bool [ default False ]
1742 Whether to allow the value to be None
1743
1744 """
1745 if default_value is NoDefaultSpecified and trait is not None:
1746 if not is_trait(trait):
1747 default_value = trait
1748 trait = None
1749 if default_value is NoDefaultSpecified:
1750 default_value = {}
1751 if default_value is None:
1752 args = None
1753 elif isinstance(default_value, dict):
1754 args = (default_value,)
1755 elif isinstance(default_value, SequenceTypes):
1756 args = (default_value,)
1757 else:
1758 raise TypeError('default value of Dict was %s' % default_value)
1759
1760 if is_trait(trait):
1761 self._trait = trait() if isinstance(trait, type) else trait
1762 self._trait.name = 'element'
1763 elif trait is not None:
1764 raise TypeError("`trait` must be a Trait or None, got %s"%repr_type(trait))
1765
1766 super(Dict,self).__init__(klass=dict, args=args,
1767 allow_none=allow_none, **metadata)
1768
1769 def element_error(self, obj, element, validator):
1770 e = "Element of the '%s' trait of %s instance must be %s, but a value of %s was specified." \
1771 % (self.name, class_of(obj), validator.info(), repr_type(element))
1772 raise TraitError(e)
1773
1774 def validate(self, obj, value):
1775 value = super(Dict, self).validate(obj, value)
1776 if value is None:
1777 return value
1778 value = self.validate_elements(obj, value)
1779 return value
1780
1781 def validate_elements(self, obj, value):
1782 if self._trait is None or isinstance(self._trait, Any):
1783 return value
1784 validated = {}
1785 for key in value:
1786 v = value[key]
1787 try:
1788 v = self._trait._validate(obj, v)
1789 except TraitError:
1790 self.element_error(obj, v, self._trait)
1791 else:
1792 validated[key] = v
1793 return self.klass(validated)
1794
1795 def instance_init(self):
1796 if isinstance(self._trait, TraitType):
1797 self._trait.this_class = self.this_class
1798 self._trait.instance_init()
1799 super(Dict, self).instance_init()
1800
1801
1802 class EventfulDict(Instance):
1803 """An instance of an EventfulDict."""
1804
1805 def __init__(self, default_value={}, allow_none=False, **metadata):
1806 """Create a EventfulDict trait type from a dict.
1807
1808 The default value is created by doing
1809 ``eventful.EvenfulDict(default_value)``, which creates a copy of the
1810 ``default_value``.
1811 """
1812 if default_value is None:
1813 args = None
1814 elif isinstance(default_value, dict):
1815 args = (default_value,)
1816 elif isinstance(default_value, SequenceTypes):
1817 args = (default_value,)
1818 else:
1819 raise TypeError('default value of EventfulDict was %s' % default_value)
1820
1821 super(EventfulDict, self).__init__(klass=eventful.EventfulDict, args=args,
1822 allow_none=allow_none, **metadata)
1823
1824
1825 class EventfulList(Instance):
1826 """An instance of an EventfulList."""
1827
1828 def __init__(self, default_value=None, allow_none=False, **metadata):
1829 """Create a EventfulList trait type from a dict.
1830
1831 The default value is created by doing
1832 ``eventful.EvenfulList(default_value)``, which creates a copy of the
1833 ``default_value``.
1834 """
1835 if default_value is None:
1836 args = ((),)
1837 else:
1838 args = (default_value,)
1839
1840 super(EventfulList, self).__init__(klass=eventful.EventfulList, args=args,
1841 allow_none=allow_none, **metadata)
1842
1843
1844 class TCPAddress(TraitType):
1845 """A trait for an (ip, port) tuple.
1846
1847 This allows for both IPv4 IP addresses as well as hostnames.
1848 """
1849
1850 default_value = ('127.0.0.1', 0)
1851 info_text = 'an (ip, port) tuple'
1852
1853 def validate(self, obj, value):
1854 if isinstance(value, tuple):
1855 if len(value) == 2:
1856 if isinstance(value[0], py3compat.string_types) and isinstance(value[1], int):
1857 port = value[1]
1858 if port >= 0 and port <= 65535:
1859 return value
1860 self.error(obj, value)
1861
1862 class CRegExp(TraitType):
1863 """A casting compiled regular expression trait.
1864
1865 Accepts both strings and compiled regular expressions. The resulting
1866 attribute will be a compiled regular expression."""
1867
1868 info_text = 'a regular expression'
1869
1870 def validate(self, obj, value):
1871 try:
1872 return re.compile(value)
1873 except:
1874 self.error(obj, value)
1 NO CONTENT: file renamed from IPython/config/__init__.py to traitlets/config/__init__.py
NO CONTENT: file renamed from IPython/config/__init__.py to traitlets/config/__init__.py
@@ -16,12 +16,12 b' from collections import defaultdict'
16
16
17 from decorator import decorator
17 from decorator import decorator
18
18
19 from IPython.config.configurable import SingletonConfigurable
19 from traitlets.config.configurable import SingletonConfigurable
20 from IPython.config.loader import (
20 from traitlets.config.loader import (
21 KVArgParseConfigLoader, PyFileConfigLoader, Config, ArgumentError, ConfigFileNotFound, JSONFileConfigLoader
21 KVArgParseConfigLoader, PyFileConfigLoader, Config, ArgumentError, ConfigFileNotFound, JSONFileConfigLoader
22 )
22 )
23
23
24 from IPython.utils.traitlets import (
24 from traitlets.traitlets import (
25 Unicode, List, Enum, Dict, Instance, TraitError
25 Unicode, List, Enum, Dict, Instance, TraitError
26 )
26 )
27 from IPython.utils.importstring import import_item
27 from IPython.utils.importstring import import_item
@@ -227,7 +227,7 b' class Application(SingletonConfigurable):'
227 # and the second being the help string for the subcommand
227 # and the second being the help string for the subcommand
228 subcommands = Dict()
228 subcommands = Dict()
229 # parse_command_line will initialize a subapp, if requested
229 # parse_command_line will initialize a subapp, if requested
230 subapp = Instance('IPython.config.application.Application', allow_none=True)
230 subapp = Instance('traitlets.config.application.Application', allow_none=True)
231
231
232 # extra command-line arguments that don't set config values
232 # extra command-line arguments that don't set config values
233 extra_args = List(Unicode)
233 extra_args = List(Unicode)
@@ -10,7 +10,7 b' import logging'
10 from copy import deepcopy
10 from copy import deepcopy
11
11
12 from .loader import Config, LazyConfigValue
12 from .loader import Config, LazyConfigValue
13 from IPython.utils.traitlets import HasTraits, Instance
13 from traitlets.traitlets import HasTraits, Instance
14 from IPython.utils.text import indent, wrap_paragraphs
14 from IPython.utils.text import indent, wrap_paragraphs
15 from IPython.utils.py3compat import iteritems
15 from IPython.utils.py3compat import iteritems
16
16
@@ -34,7 +34,7 b' class MultipleInstanceError(ConfigurableError):'
34 class Configurable(HasTraits):
34 class Configurable(HasTraits):
35
35
36 config = Instance(Config, (), {})
36 config = Instance(Config, (), {})
37 parent = Instance('IPython.config.configurable.Configurable', allow_none=True)
37 parent = Instance('traitlets.config.configurable.Configurable', allow_none=True)
38
38
39 def __init__(self, **kwargs):
39 def __init__(self, **kwargs):
40 """Create a configurable given a config config.
40 """Create a configurable given a config config.
@@ -329,7 +329,7 b' class SingletonConfigurable(Configurable):'
329
329
330 Create a singleton class using instance, and retrieve it::
330 Create a singleton class using instance, and retrieve it::
331
331
332 >>> from IPython.config.configurable import SingletonConfigurable
332 >>> from traitlets.config.configurable import SingletonConfigurable
333 >>> class Foo(SingletonConfigurable): pass
333 >>> class Foo(SingletonConfigurable): pass
334 >>> foo = Foo.instance()
334 >>> foo = Foo.instance()
335 >>> foo == Foo.instance()
335 >>> foo == Foo.instance()
@@ -17,7 +17,7 b' from IPython.utils.path import filefind, get_ipython_dir'
17 from IPython.utils import py3compat
17 from IPython.utils import py3compat
18 from IPython.utils.encoding import DEFAULT_ENCODING
18 from IPython.utils.encoding import DEFAULT_ENCODING
19 from IPython.utils.py3compat import unicode_type, iteritems
19 from IPython.utils.py3compat import unicode_type, iteritems
20 from IPython.utils.traitlets import HasTraits, List, Any
20 from traitlets.traitlets import HasTraits, List, Any
21
21
22 #-----------------------------------------------------------------------------
22 #-----------------------------------------------------------------------------
23 # Exceptions
23 # Exceptions
@@ -330,7 +330,7 b' class ConfigLoader(object):'
330 """A base class for config loaders.
330 """A base class for config loaders.
331
331
332 log : instance of :class:`logging.Logger` to use.
332 log : instance of :class:`logging.Logger` to use.
333 By default loger of :meth:`IPython.config.application.Application.instance()`
333 By default loger of :meth:`traitlets.config.application.Application.instance()`
334 will be used
334 will be used
335
335
336 Examples
336 Examples
@@ -558,7 +558,7 b' class KeyValueConfigLoader(CommandLineConfigLoader):'
558 Examples
558 Examples
559 --------
559 --------
560
560
561 >>> from IPython.config.loader import KeyValueConfigLoader
561 >>> from traitlets.config.loader import KeyValueConfigLoader
562 >>> cl = KeyValueConfigLoader()
562 >>> cl = KeyValueConfigLoader()
563 >>> d = cl.load_config(["--A.name='brian'","--B.number=0"])
563 >>> d = cl.load_config(["--A.name='brian'","--B.number=0"])
564 >>> sorted(d.items())
564 >>> sorted(d.items())
@@ -7,9 +7,9 b' import io'
7 import json
7 import json
8 import os
8 import os
9
9
10 from IPython.config import LoggingConfigurable
10 from traitlets.config import LoggingConfigurable
11 from IPython.utils.py3compat import PY3
11 from IPython.utils.py3compat import PY3
12 from IPython.utils.traitlets import Unicode
12 from traitlets.traitlets import Unicode
13
13
14
14
15 def recursive_update(target, new):
15 def recursive_update(target, new):
1 NO CONTENT: file renamed from IPython/config/tests/__init__.py to traitlets/config/tests/__init__.py
NO CONTENT: file renamed from IPython/config/tests/__init__.py to traitlets/config/tests/__init__.py
@@ -1,6 +1,6 b''
1 # coding: utf-8
1 # coding: utf-8
2 """
2 """
3 Tests for IPython.config.application.Application
3 Tests for traitlets.config.application.Application
4 """
4 """
5
5
6 # Copyright (c) IPython Development Team.
6 # Copyright (c) IPython Development Team.
@@ -15,15 +15,15 b' pjoin = os.path.join'
15
15
16 import nose.tools as nt
16 import nose.tools as nt
17
17
18 from IPython.config.configurable import Configurable
18 from traitlets.config.configurable import Configurable
19 from IPython.config.loader import Config
19 from traitlets.config.loader import Config
20
20
21 from IPython.config.application import (
21 from traitlets.config.application import (
22 Application
22 Application
23 )
23 )
24
24
25 from IPython.utils.tempdir import TemporaryDirectory
25 from IPython.utils.tempdir import TemporaryDirectory
26 from IPython.utils.traitlets import (
26 from traitlets.traitlets import (
27 Bool, Unicode, Integer, List, Dict
27 Bool, Unicode, Integer, List, Dict
28 )
28 )
29
29
@@ -1,21 +1,21 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """Tests for IPython.config.configurable"""
2 """Tests for traitlets.config.configurable"""
3
3
4 # Copyright (c) IPython Development Team.
4 # Copyright (c) IPython Development Team.
5 # Distributed under the terms of the Modified BSD License.
5 # Distributed under the terms of the Modified BSD License.
6
6
7 from unittest import TestCase
7 from unittest import TestCase
8
8
9 from IPython.config.configurable import (
9 from traitlets.config.configurable import (
10 Configurable,
10 Configurable,
11 SingletonConfigurable
11 SingletonConfigurable
12 )
12 )
13
13
14 from IPython.utils.traitlets import (
14 from traitlets.traitlets import (
15 Integer, Float, Unicode, List, Dict, Set,
15 Integer, Float, Unicode, List, Dict, Set,
16 )
16 )
17
17
18 from IPython.config.loader import Config
18 from traitlets.config.loader import Config
19 from IPython.utils.py3compat import PY3
19 from IPython.utils.py3compat import PY3
20
20
21
21
@@ -1,5 +1,5 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """Tests for IPython.config.loader"""
2 """Tests for traitlets.config.loader"""
3
3
4 # Copyright (c) IPython Development Team.
4 # Copyright (c) IPython Development Team.
5 # Distributed under the terms of the Modified BSD License.
5 # Distributed under the terms of the Modified BSD License.
@@ -18,7 +18,7 b' import nose.tools as nt'
18
18
19
19
20
20
21 from IPython.config.loader import (
21 from traitlets.config.loader import (
22 Config,
22 Config,
23 LazyConfigValue,
23 LazyConfigValue,
24 PyFileConfigLoader,
24 PyFileConfigLoader,
1 NO CONTENT: file renamed from IPython/utils/tests/test_traitlets.py to traitlets/tests/test_traitlets.py
NO CONTENT: file renamed from IPython/utils/tests/test_traitlets.py to traitlets/tests/test_traitlets.py
General Comments 0
You need to be logged in to leave comments. Login now