##// END OF EJS Templates
Start using py3compat module.
Start using py3compat module.

File last commit:

r4574:a8c54759
r4731:ee492f81
Show More
traitlets.py
1396 lines | 44.9 KiB | text/x-python | PythonLexer
Brian Granger
First prototype of component, traitlets and a config loader.
r2157 # encoding: utf-8
"""
A lightweight Traits like module.
Brian Granger
More work on traitlets.py. I have added tests for existing traitlets.
r2175 This is designed to provide a lightweight, simple, pure Python version of
many of the capabilities of enthought.traits. This includes:
* Validation
* Type specification with defaults
* Static and dynamic notification
* Basic predefined types
* An API that is similar to enthought.traits
We don't support:
* Delegation
* Automatic GUI generation
Brian Granger
A few more small traitlets features.
r2179 * A full set of trait types. Most importantly, we don't provide container
Dav Clark
Final changes traitlet -> trait for review
r2385 traits (list, dict, tuple) that can trigger notifications if their
Brian Granger
A few more small traitlets features.
r2179 contents change.
Brian Granger
More work on traitlets.py. I have added tests for existing traitlets.
r2175 * API compatibility with enthought.traits
Brian Granger
A few more small traitlets features.
r2179 There are also some important difference in our design:
* enthought.traits does not validate default values. We do.
Brian Granger
More work on traitlets.py. I have added tests for existing traitlets.
r2175 We choose to create this module because we need these capabilities, but
we need them to be pure Python so they work in all Python implementations,
including Jython and IronPython.
Brian Granger
First prototype of component, traitlets and a config loader.
r2157 Authors:
* Brian Granger
* Enthought, Inc. Some of the code in this file comes from enthought.traits
and is licensed under the BSD license. Also, many of the ideas also come
from enthought.traits even though our implementation is very different.
"""
#-----------------------------------------------------------------------------
# Copyright (C) 2008-2009 The IPython Development Team
#
# Distributed under the terms of the BSD License. The full license is in
# the file COPYING, distributed as part of this software.
#-----------------------------------------------------------------------------
#-----------------------------------------------------------------------------
# Imports
#-----------------------------------------------------------------------------
Brian Granger
Added support for Type and Instance traitlets with testing.
r2177
Brian Granger
First prototype of component, traitlets and a config loader.
r2157 import inspect
Thomas Kluyver
Add ObjectName and DottedObjectName trait types for referring to Python identifiers.
r4047 import re
Brian Granger
Added support for Type and Instance traitlets with testing.
r2177 import sys
Brian Granger
First prototype of component, traitlets and a config loader.
r2157 import types
Brian Granger
More work on InteractiveShell and ipmaker. It works!
r2204 from types import (
InstanceType, ClassType, FunctionType,
ListType, TupleType
)
Thomas Kluyver
Cleaning up old code to simplify 2to3 conversion.
r3108 from .importstring import import_item
Brian Granger
A number of changes to how traitlets and components work....
r2229
Brian Granger
Added support for Type and Instance traitlets with testing.
r2177 ClassTypes = (ClassType, type)
Brian Granger
First prototype of component, traitlets and a config loader.
r2157
MinRK
Refactor newparallel to use Config system...
r3604 SequenceTypes = (ListType, TupleType, set, frozenset)
Brian Granger
More work on InteractiveShell and ipmaker. It works!
r2204
Brian Granger
First prototype of component, traitlets and a config loader.
r2157 #-----------------------------------------------------------------------------
# Basic classes
#-----------------------------------------------------------------------------
class NoDefaultSpecified ( object ): pass
NoDefaultSpecified = NoDefaultSpecified()
class Undefined ( object ): pass
Undefined = Undefined()
Dav Clark
Iniital stab at renames for traitlets
r2384 class TraitError(Exception):
pass
Brian Granger
First prototype of component, traitlets and a config loader.
r2157
#-----------------------------------------------------------------------------
# Utilities
#-----------------------------------------------------------------------------
def class_of ( object ):
""" Returns a string containing the class name of an object with the
correct indefinite article ('a' or 'an') preceding it (e.g., 'an Image',
'a PlotValue').
"""
if isinstance( object, basestring ):
return add_article( object )
return add_article( object.__class__.__name__ )
def add_article ( name ):
""" Returns a string containing the correct indefinite article ('a' or 'an')
prefixed to the specified string.
"""
if name[:1].lower() in 'aeiou':
return 'an ' + name
return 'a ' + name
def repr_type(obj):
""" Return a string representation of a value and its type for readable
error messages.
"""
the_type = type(obj)
if the_type is InstanceType:
# Old-style class.
the_type = obj.__class__
msg = '%r %r' % (obj, the_type)
return msg
def parse_notifier_name(name):
Brian Granger
More work on traitlets.py. I have added tests for existing traitlets.
r2175 """Convert the name argument to a list of names.
Examples
--------
>>> parse_notifier_name('a')
['a']
>>> parse_notifier_name(['a','b'])
['a', 'b']
>>> parse_notifier_name(None)
Dav Clark
Iniital stab at renames for traitlets
r2384 ['anytrait']
Brian Granger
More work on traitlets.py. I have added tests for existing traitlets.
r2175 """
Brian Granger
First prototype of component, traitlets and a config loader.
r2157 if isinstance(name, str):
return [name]
elif name is None:
Dav Clark
Iniital stab at renames for traitlets
r2384 return ['anytrait']
Brian Granger
First prototype of component, traitlets and a config loader.
r2157 elif isinstance(name, (list, tuple)):
for n in name:
assert isinstance(n, str), "names must be strings"
return name
Brian Granger
Improvement to how config is handled in Components....
r2184
class _SimpleTest:
def __init__ ( self, value ): self.value = value
def __call__ ( self, test ):
return test == self.value
def __repr__(self):
return "<SimpleTest(%r)" % self.value
def __str__(self):
return self.__repr__()
Brian Granger
Work on refactoring ipcontroller to new config system.
r2287 def getmembers(object, predicate=None):
"""A safe version of inspect.getmembers that handles missing attributes.
This is useful when there are descriptor based attributes that for
some reason raise AttributeError even though they exist. This happens
in zope.inteface with the __provides__ attribute.
"""
results = []
for key in dir(object):
try:
value = getattr(object, key)
except AttributeError:
pass
else:
if not predicate or predicate(value):
results.append((key, value))
results.sort()
return results
Brian Granger
First prototype of component, traitlets and a config loader.
r2157 #-----------------------------------------------------------------------------
Dav Clark
Final changes traitlet -> trait for review
r2385 # Base TraitType for all traits
Brian Granger
First prototype of component, traitlets and a config loader.
r2157 #-----------------------------------------------------------------------------
Dav Clark
Final changes traitlet -> trait for review
r2385 class TraitType(object):
"""A base class for all trait descriptors.
Brian Granger
Fixing subtle bug in the traitlets with This....
r2183
Notes
-----
Dav Clark
Final changes traitlet -> trait for review
r2385 Our implementation of traits is based on Python's descriptor
Brian Granger
Fixing subtle bug in the traitlets with This....
r2183 prototol. This class is the base class for all such descriptors. The
Dav Clark
Iniital stab at renames for traitlets
r2384 only magic we use is a custom metaclass for the main :class:`HasTraits`
Brian Granger
Fixing subtle bug in the traitlets with This....
r2183 class that does the following:
Dav Clark
Final changes traitlet -> trait for review
r2385 1. Sets the :attr:`name` attribute of every :class:`TraitType`
Brian Granger
Fixing subtle bug in the traitlets with This....
r2183 instance in the class dict to the name of the attribute.
Dav Clark
Final changes traitlet -> trait for review
r2385 2. Sets the :attr:`this_class` attribute of every :class:`TraitType`
instance in the class dict to the *class* that declared the trait.
This is used by the :class:`This` trait to allow subclasses to
Brian Granger
Fixing subtle bug in the traitlets with This....
r2183 accept superclasses for :class:`This` values.
"""
Brian Granger
First prototype of component, traitlets and a config loader.
r2157
metadata = {}
Brian Granger
Added support for Type and Instance traitlets with testing.
r2177 default_value = Undefined
Brian Granger
First prototype of component, traitlets and a config loader.
r2157 info_text = 'any value'
def __init__(self, default_value=NoDefaultSpecified, **metadata):
Dav Clark
Final changes traitlet -> trait for review
r2385 """Create a TraitType.
Brian Granger
Added support for Type and Instance traitlets with testing.
r2177 """
Brian Granger
First prototype of component, traitlets and a config loader.
r2157 if default_value is not NoDefaultSpecified:
self.default_value = default_value
Brian Granger
Improvement to how config is handled in Components....
r2184
if len(metadata) > 0:
if len(self.metadata) > 0:
self._metadata = self.metadata.copy()
self._metadata.update(metadata)
else:
self._metadata = metadata
else:
self._metadata = self.metadata
Brian Granger
Added support for Type and Instance traitlets with testing.
r2177 self.init()
Brian Granger
First prototype of component, traitlets and a config loader.
r2157
Brian Granger
Added support for Type and Instance traitlets with testing.
r2177 def init(self):
pass
def get_default_value(self):
"""Create a new instance of the default value."""
Brian Granger
Minor work on kernelmanager....
r2742 return self.default_value
Brian Granger
Added support for Type and Instance traitlets with testing.
r2177
Brian Granger
A number of changes to how traitlets and components work....
r2229 def instance_init(self, obj):
Dav Clark
Iniital stab at renames for traitlets
r2384 """This is called by :meth:`HasTraits.__new__` to finish init'ing.
Brian Granger
A number of changes to how traitlets and components work....
r2229
Some stages of initialization must be delayed until the parent
Dav Clark
Iniital stab at renames for traitlets
r2384 :class:`HasTraits` instance has been created. This method is
called in :meth:`HasTraits.__new__` after the instance has been
Brian Granger
A number of changes to how traitlets and components work....
r2229 created.
This method trigger the creation and validation of default values
and also things like the resolution of str given class names in
:class:`Type` and :class`Instance`.
Parameters
----------
Dav Clark
Iniital stab at renames for traitlets
r2384 obj : :class:`HasTraits` instance
The parent :class:`HasTraits` instance that has just been
Brian Granger
A number of changes to how traitlets and components work....
r2229 created.
"""
self.set_default_value(obj)
Brian Granger
Important changes to simplify traitlets....
r2182 def set_default_value(self, obj):
Brian Granger
A number of changes to how traitlets and components work....
r2229 """Set the default value on a per instance basis.
This method is called by :meth:`instance_init` to create and
validate the default value. The creation and validation of
Dav Clark
Iniital stab at renames for traitlets
r2384 default values must be delayed until the parent :class:`HasTraits`
Brian Granger
A number of changes to how traitlets and components work....
r2229 class has been instantiated.
"""
Robert Kern
ENH: Add dynamic initializers (_x_default methods) to traitlets.
r3207 # Check for a deferred initializer defined in the same class as the
# trait declaration or above.
mro = type(obj).mro()
meth_name = '_%s_default' % self.name
for cls in mro[:mro.index(self.this_class)+1]:
if meth_name in cls.__dict__:
break
else:
# We didn't find one. Do static initialization.
dv = self.get_default_value()
newdv = self._validate(obj, dv)
obj._trait_values[self.name] = newdv
return
# Complete the dynamic initialization.
Robert Kern
BUG: Do not store class-specific state on TraitTypes since they may be shared through subclassing.
r3336 obj._trait_dyn_inits[self.name] = cls.__dict__[meth_name]
Brian Granger
Improvements to component.py....
r2180
Brian Granger
Important changes to simplify traitlets....
r2182 def __get__(self, obj, cls=None):
Dav Clark
Final changes traitlet -> trait for review
r2385 """Get the value of the trait by self.name for the instance.
Brian Granger
Improvements to component.py....
r2180
Dav Clark
Iniital stab at renames for traitlets
r2384 Default values are instantiated when :meth:`HasTraits.__new__`
Brian Granger
Important changes to simplify traitlets....
r2182 is called. Thus by the time this method gets called either the
default value or a user defined value (they called :meth:`__set__`)
Dav Clark
Iniital stab at renames for traitlets
r2384 is in the :class:`HasTraits` instance.
Brian Granger
Added support for Type and Instance traitlets with testing.
r2177 """
if obj is None:
Brian Granger
First prototype of component, traitlets and a config loader.
r2157 return self
else:
Brian Granger
Important changes to simplify traitlets....
r2182 try:
Dav Clark
Final changes traitlet -> trait for review
r2385 value = obj._trait_values[self.name]
Robert Kern
ENH: Add dynamic initializers (_x_default methods) to traitlets.
r3207 except KeyError:
# Check for a dynamic initializer.
Robert Kern
BUG: Do not store class-specific state on TraitTypes since they may be shared through subclassing.
r3336 if self.name in obj._trait_dyn_inits:
value = obj._trait_dyn_inits[self.name](obj)
Robert Kern
ENH: Add dynamic initializers (_x_default methods) to traitlets.
r3207 # FIXME: Do we really validate here?
value = self._validate(obj, value)
obj._trait_values[self.name] = value
return value
else:
raise TraitError('Unexpected error in TraitType: '
'both default value and dynamic initializer are '
'absent.')
except Exception:
Dav Clark
Iniital stab at renames for traitlets
r2384 # HasTraits should call set_default_value to populate
Brian Granger
Important changes to simplify traitlets....
r2182 # this. So this should never be reached.
Dav Clark
Final changes traitlet -> trait for review
r2385 raise TraitError('Unexpected error in TraitType: '
Brian Granger
Important changes to simplify traitlets....
r2182 'default value not set properly')
Brian Granger
Added support for Type and Instance traitlets with testing.
r2177 else:
Brian Granger
Important changes to simplify traitlets....
r2182 return value
Brian Granger
Added support for Type and Instance traitlets with testing.
r2177
Brian Granger
Important changes to simplify traitlets....
r2182 def __set__(self, obj, value):
Brian Granger
Added support for Type and Instance traitlets with testing.
r2177 new_value = self._validate(obj, value)
Brian Granger
Important changes to simplify traitlets....
r2182 old_value = self.__get__(obj)
if old_value != new_value:
Dav Clark
Final changes traitlet -> trait for review
r2385 obj._trait_values[self.name] = new_value
obj._notify_trait(self.name, old_value, new_value)
Brian Granger
First prototype of component, traitlets and a config loader.
r2157
Brian Granger
Added support for Type and Instance traitlets with testing.
r2177 def _validate(self, obj, value):
Brian Granger
First prototype of component, traitlets and a config loader.
r2157 if hasattr(self, 'validate'):
Brian Granger
Added support for Type and Instance traitlets with testing.
r2177 return self.validate(obj, value)
Brian Granger
First prototype of component, traitlets and a config loader.
r2157 elif hasattr(self, 'is_valid_for'):
valid = self.is_valid_for(value)
if valid:
return value
else:
Dav Clark
Final changes traitlet -> trait for review
r2385 raise TraitError('invalid value for type: %r' % value)
Brian Granger
First prototype of component, traitlets and a config loader.
r2157 elif hasattr(self, 'value_for'):
return self.value_for(value)
else:
return value
def info(self):
return self.info_text
def error(self, obj, value):
if obj is not None:
Dav Clark
Final changes traitlet -> trait for review
r2385 e = "The '%s' trait of %s instance must be %s, but a value of %s was specified." \
Brian Granger
First prototype of component, traitlets and a config loader.
r2157 % (self.name, class_of(obj),
self.info(), repr_type(value))
else:
Dav Clark
Final changes traitlet -> trait for review
r2385 e = "The '%s' trait must be %s, but a value of %r was specified." \
MinRK
Allow type checking on elements of List,Tuple,Set...
r3870 % (self.name, self.info(), repr_type(value))
Dav Clark
Final changes traitlet -> trait for review
r2385 raise TraitError(e)
Brian Granger
First prototype of component, traitlets and a config loader.
r2157
Brian Granger
Improvement to how config is handled in Components....
r2184 def get_metadata(self, key):
return getattr(self, '_metadata', {}).get(key, None)
def set_metadata(self, key, value):
getattr(self, '_metadata', {})[key] = value
Brian Granger
First prototype of component, traitlets and a config loader.
r2157
#-----------------------------------------------------------------------------
Dav Clark
Iniital stab at renames for traitlets
r2384 # The HasTraits implementation
Brian Granger
First prototype of component, traitlets and a config loader.
r2157 #-----------------------------------------------------------------------------
Dav Clark
Iniital stab at renames for traitlets
r2384 class MetaHasTraits(type):
"""A metaclass for HasTraits.
Brian Granger
First prototype of component, traitlets and a config loader.
r2157
Dav Clark
Final changes traitlet -> trait for review
r2385 This metaclass makes sure that any TraitType class attributes are
Brian Granger
First prototype of component, traitlets and a config loader.
r2157 instantiated and sets their name attribute.
"""
def __new__(mcls, name, bases, classdict):
Dav Clark
Iniital stab at renames for traitlets
r2384 """Create the HasTraits class.
Brian Granger
Fixing subtle bug in the traitlets with This....
r2183
Dav Clark
Final changes traitlet -> trait for review
r2385 This instantiates all TraitTypes in the class dict and sets their
Brian Granger
Fixing subtle bug in the traitlets with This....
r2183 :attr:`name` attribute.
"""
Brian Granger
Work on refactoring ipcontroller to new config system.
r2287 # print "MetaHasTraitlets (mcls, name): ", mcls, name
# print "MetaHasTraitlets (bases): ", bases
# print "MetaHasTraitlets (classdict): ", classdict
Brian Granger
First prototype of component, traitlets and a config loader.
r2157 for k,v in classdict.iteritems():
Dav Clark
Final changes traitlet -> trait for review
r2385 if isinstance(v, TraitType):
Brian Granger
First prototype of component, traitlets and a config loader.
r2157 v.name = k
elif inspect.isclass(v):
Dav Clark
Final changes traitlet -> trait for review
r2385 if issubclass(v, TraitType):
Brian Granger
First prototype of component, traitlets and a config loader.
r2157 vinst = v()
vinst.name = k
classdict[k] = vinst
Dav Clark
Iniital stab at renames for traitlets
r2384 return super(MetaHasTraits, mcls).__new__(mcls, name, bases, classdict)
Brian Granger
First prototype of component, traitlets and a config loader.
r2157
Brian Granger
Fixing subtle bug in the traitlets with This....
r2183 def __init__(cls, name, bases, classdict):
Dav Clark
Iniital stab at renames for traitlets
r2384 """Finish initializing the HasTraits class.
Brian Granger
Fixing subtle bug in the traitlets with This....
r2183
Dav Clark
Final changes traitlet -> trait for review
r2385 This sets the :attr:`this_class` attribute of each TraitType in the
Brian Granger
Fixing subtle bug in the traitlets with This....
r2183 class dict to the newly created class ``cls``.
"""
for k, v in classdict.iteritems():
Dav Clark
Final changes traitlet -> trait for review
r2385 if isinstance(v, TraitType):
Brian Granger
Fixing subtle bug in the traitlets with This....
r2183 v.this_class = cls
Dav Clark
Iniital stab at renames for traitlets
r2384 super(MetaHasTraits, cls).__init__(name, bases, classdict)
Brian Granger
First prototype of component, traitlets and a config loader.
r2157
Dav Clark
Iniital stab at renames for traitlets
r2384 class HasTraits(object):
Brian Granger
First prototype of component, traitlets and a config loader.
r2157
Dav Clark
Iniital stab at renames for traitlets
r2384 __metaclass__ = MetaHasTraits
Brian Granger
First prototype of component, traitlets and a config loader.
r2157
Brian Granger
Allow trait values to be set in the keyword arguments of __init__.
r2739 def __new__(cls, **kw):
Brian Granger
Fixed Python 2.6 warning with traitlets object.__new__....
r2255 # This is needed because in Python 2.6 object.__new__ only accepts
# the cls argument.
Dav Clark
Iniital stab at renames for traitlets
r2384 new_meth = super(HasTraits, cls).__new__
Brian Granger
Fixed Python 2.6 warning with traitlets object.__new__....
r2255 if new_meth is object.__new__:
inst = new_meth(cls)
else:
Brian Granger
Allow trait values to be set in the keyword arguments of __init__.
r2739 inst = new_meth(cls, **kw)
Dav Clark
Final changes traitlet -> trait for review
r2385 inst._trait_values = {}
inst._trait_notifiers = {}
Robert Kern
BUG: Do not store class-specific state on TraitTypes since they may be shared through subclassing.
r3336 inst._trait_dyn_inits = {}
Dav Clark
Final changes traitlet -> trait for review
r2385 # Here we tell all the TraitType instances to set their default
Brian Granger
Important changes to simplify traitlets....
r2182 # values on the instance.
for key in dir(cls):
Brian Granger
Work on refactoring ipcontroller to new config system.
r2287 # Some descriptors raise AttributeError like zope.interface's
# __provides__ attributes even though they exist. This causes
# AttributeErrors even though they are listed in dir(cls).
try:
value = getattr(cls, key)
except AttributeError:
pass
else:
Dav Clark
merged from ~fdo.perez/ipython/trunk-dev
r2469 if isinstance(value, TraitType):
Brian Granger
Work on refactoring ipcontroller to new config system.
r2287 value.instance_init(inst)
Dav Clark
merged from ~fdo.perez/ipython/trunk-dev
r2469
Brian Granger
Important changes to simplify traitlets....
r2182 return inst
Brian Granger
Adding support for HasTraits to take keyword arguments.
r2740 def __init__(self, **kw):
# Allow trait values to be set using keyword arguments.
Brian Granger
Fixing bugs and adding comment
r2745 # We need to use setattr for this to trigger validation and
# notifications.
Brian Granger
Allow trait values to be set in the keyword arguments of __init__.
r2739 for key, value in kw.iteritems():
setattr(self, key, value)
Brian Granger
First prototype of component, traitlets and a config loader.
r2157
Dav Clark
Final changes traitlet -> trait for review
r2385 def _notify_trait(self, name, old_value, new_value):
Brian Granger
More work on traitlets.py. I have added tests for existing traitlets.
r2175
# First dynamic ones
Dav Clark
Final changes traitlet -> trait for review
r2385 callables = self._trait_notifiers.get(name,[])
more_callables = self._trait_notifiers.get('anytrait',[])
Brian Granger
First prototype of component, traitlets and a config loader.
r2157 callables.extend(more_callables)
Brian Granger
More work on traitlets.py. I have added tests for existing traitlets.
r2175
# Now static ones
try:
cb = getattr(self, '_%s_changed' % name)
except:
pass
else:
callables.append(cb)
# Call them all now
Brian Granger
First prototype of component, traitlets and a config loader.
r2157 for c in callables:
# Traits catches and logs errors here. I allow them to raise
Brian Granger
More work on traitlets.py. I have added tests for existing traitlets.
r2175 if callable(c):
argspec = inspect.getargspec(c)
nargs = len(argspec[0])
# Bound methods have an additional 'self' argument
# I don't know how to treat unbound methods, but they
# can't really be used for callbacks.
if isinstance(c, types.MethodType):
offset = -1
else:
offset = 0
if nargs + offset == 0:
c()
elif nargs + offset == 1:
c(name)
elif nargs + offset == 2:
c(name, new_value)
elif nargs + offset == 3:
c(name, old_value, new_value)
else:
Dav Clark
Final changes traitlet -> trait for review
r2385 raise TraitError('a trait changed callback '
Brian Granger
More work on traitlets.py. I have added tests for existing traitlets.
r2175 'must have 0-3 arguments.')
else:
Dav Clark
Final changes traitlet -> trait for review
r2385 raise TraitError('a trait changed callback '
Brian Granger
More work on traitlets.py. I have added tests for existing traitlets.
r2175 'must be callable.')
Brian Granger
First prototype of component, traitlets and a config loader.
r2157
def _add_notifiers(self, handler, name):
Dav Clark
Final changes traitlet -> trait for review
r2385 if not self._trait_notifiers.has_key(name):
Brian Granger
First prototype of component, traitlets and a config loader.
r2157 nlist = []
Dav Clark
Final changes traitlet -> trait for review
r2385 self._trait_notifiers[name] = nlist
Brian Granger
First prototype of component, traitlets and a config loader.
r2157 else:
Dav Clark
Final changes traitlet -> trait for review
r2385 nlist = self._trait_notifiers[name]
Brian Granger
First prototype of component, traitlets and a config loader.
r2157 if handler not in nlist:
nlist.append(handler)
def _remove_notifiers(self, handler, name):
Dav Clark
Final changes traitlet -> trait for review
r2385 if self._trait_notifiers.has_key(name):
nlist = self._trait_notifiers[name]
Brian Granger
First prototype of component, traitlets and a config loader.
r2157 try:
index = nlist.index(handler)
except ValueError:
pass
else:
del nlist[index]
Dav Clark
Iniital stab at renames for traitlets
r2384 def on_trait_change(self, handler, name=None, remove=False):
Dav Clark
Final changes traitlet -> trait for review
r2385 """Setup a handler to be called when a trait changes.
Brian Granger
More work on traitlets.py. I have added tests for existing traitlets.
r2175
Dav Clark
Final changes traitlet -> trait for review
r2385 This is used to setup dynamic notifications of trait changes.
Brian Granger
More work on traitlets.py. I have added tests for existing traitlets.
r2175
Dav Clark
Iniital stab at renames for traitlets
r2384 Static handlers can be created by creating methods on a HasTraits
Dav Clark
Final changes traitlet -> trait for review
r2385 subclass with the naming convention '_[traitname]_changed'. Thus,
to create static handler for the trait 'a', create the method
Brian Granger
More work on traitlets.py. I have added tests for existing traitlets.
r2175 _a_changed(self, name, old, new) (fewer arguments can be used, see
below).
Parameters
----------
Brian Granger
Major work on the documentation....
r2277 handler : callable
Dav Clark
Final changes traitlet -> trait for review
r2385 A callable that is called when a trait changes. Its
Brian Granger
Major work on the documentation....
r2277 signature can be handler(), handler(name), handler(name, new)
or handler(name, old, new).
name : list, str, None
Dav Clark
Final changes traitlet -> trait for review
r2385 If None, the handler will apply to all traits. If a list
Brian Granger
Major work on the documentation....
r2277 of str, handler will apply to all names in the list. If a
str, the handler will apply just to that name.
remove : bool
If False (the default), then install the handler. If True
then unintall it.
Brian Granger
More work on traitlets.py. I have added tests for existing traitlets.
r2175 """
Brian Granger
First prototype of component, traitlets and a config loader.
r2157 if remove:
names = parse_notifier_name(name)
for n in names:
self._remove_notifiers(handler, n)
else:
names = parse_notifier_name(name)
for n in names:
self._add_notifiers(handler, n)
Brian Granger
Ongoing work on the config system....
r3789 @classmethod
def class_trait_names(cls, **metadata):
"""Get a list of all the names of this classes traits.
This method is just like the :meth:`trait_names` method, but is unbound.
"""
return cls.class_traits(**metadata).keys()
@classmethod
def class_traits(cls, **metadata):
"""Get a list of all the traits of this class.
This method is just like the :meth:`traits` method, but is unbound.
The TraitTypes returned don't know anything about the values
that the various HasTrait's instances are holding.
This follows the same algorithm as traits does and does not allow
for any simple way of specifying merely that a metadata name
exists, but has any value. This is because get_metadata returns
None if a metadata key doesn't exist.
"""
traits = dict([memb for memb in getmembers(cls) if \
isinstance(memb[1], TraitType)])
if len(metadata) == 0:
return traits
for meta_name, meta_eval in metadata.items():
if type(meta_eval) is not FunctionType:
metadata[meta_name] = _SimpleTest(meta_eval)
result = {}
for name, trait in traits.items():
for meta_name, meta_eval in metadata.items():
if not meta_eval(trait.get_metadata(meta_name)):
break
else:
result[name] = trait
return result
Dav Clark
Iniital stab at renames for traitlets
r2384 def trait_names(self, **metadata):
Dav Clark
Final changes traitlet -> trait for review
r2385 """Get a list of all the names of this classes traits."""
Dav Clark
Iniital stab at renames for traitlets
r2384 return self.traits(**metadata).keys()
Brian Granger
Improvement to how config is handled in Components....
r2184
Dav Clark
Iniital stab at renames for traitlets
r2384 def traits(self, **metadata):
Dav Clark
Final changes traitlet -> trait for review
r2385 """Get a list of all the traits of this class.
Brian Granger
Improvement to how config is handled in Components....
r2184
Dav Clark
Final changes traitlet -> trait for review
r2385 The TraitTypes returned don't know anything about the values
that the various HasTrait's instances are holding.
Brian Granger
Massive refactoring of of the core....
r2245
This follows the same algorithm as traits does and does not allow
for any simple way of specifying merely that a metadata name
exists, but has any value. This is because get_metadata returns
None if a metadata key doesn't exist.
Brian Granger
Improvement to how config is handled in Components....
r2184 """
Dav Clark
merged from ~fdo.perez/ipython/trunk-dev
r2469 traits = dict([memb for memb in getmembers(self.__class__) if \
Dav Clark
Final changes traitlet -> trait for review
r2385 isinstance(memb[1], TraitType)])
Brian Granger
Improvement to how config is handled in Components....
r2184
Brian Granger
Massive refactoring of of the core....
r2245 if len(metadata) == 0:
Dav Clark
Final changes traitlet -> trait for review
r2385 return traits
Brian Granger
Semi-final Application and minor work on traitlets.
r2200
Brian Granger
Improvement to how config is handled in Components....
r2184 for meta_name, meta_eval in metadata.items():
if type(meta_eval) is not FunctionType:
metadata[meta_name] = _SimpleTest(meta_eval)
result = {}
Dav Clark
Final changes traitlet -> trait for review
r2385 for name, trait in traits.items():
Brian Granger
Improvement to how config is handled in Components....
r2184 for meta_name, meta_eval in metadata.items():
Dav Clark
Final changes traitlet -> trait for review
r2385 if not meta_eval(trait.get_metadata(meta_name)):
Brian Granger
Improvement to how config is handled in Components....
r2184 break
else:
Dav Clark
Final changes traitlet -> trait for review
r2385 result[name] = trait
Brian Granger
Improvement to how config is handled in Components....
r2184
return result
Brian Granger
A few more small traitlets features.
r2179
Dav Clark
Final changes traitlet -> trait for review
r2385 def trait_metadata(self, traitname, key):
"""Get metadata values for trait by key."""
Brian Granger
Improvement to how config is handled in Components....
r2184 try:
Dav Clark
Final changes traitlet -> trait for review
r2385 trait = getattr(self.__class__, traitname)
Brian Granger
Improvement to how config is handled in Components....
r2184 except AttributeError:
Dav Clark
Final changes traitlet -> trait for review
r2385 raise TraitError("Class %s does not have a trait named %s" %
(self.__class__.__name__, traitname))
Brian Granger
Improvement to how config is handled in Components....
r2184 else:
Dav Clark
Final changes traitlet -> trait for review
r2385 return trait.get_metadata(key)
Brian Granger
Added support for Type and Instance traitlets with testing.
r2177
Brian Granger
First prototype of component, traitlets and a config loader.
r2157 #-----------------------------------------------------------------------------
Dav Clark
Final changes traitlet -> trait for review
r2385 # Actual TraitTypes implementations/subclasses
Brian Granger
First prototype of component, traitlets and a config loader.
r2157 #-----------------------------------------------------------------------------
Brian Granger
Added support for Type and Instance traitlets with testing.
r2177
#-----------------------------------------------------------------------------
Dav Clark
Final changes traitlet -> trait for review
r2385 # TraitTypes subclasses for handling classes and instances of classes
Brian Granger
Added support for Type and Instance traitlets with testing.
r2177 #-----------------------------------------------------------------------------
Dav Clark
Final changes traitlet -> trait for review
r2385 class ClassBasedTraitType(TraitType):
"""A trait with error reporting for Type, Instance and This."""
Brian Granger
Added support for Type and Instance traitlets with testing.
r2177
Brian Granger
Important changes to simplify traitlets....
r2182 def error(self, obj, value):
Brian Granger
Added support for Type and Instance traitlets with testing.
r2177 kind = type(value)
if kind is InstanceType:
msg = 'class %s' % value.__class__.__name__
else:
msg = '%s (i.e. %s)' % ( str( kind )[1:-1], repr( value ) )
MinRK
Allow type checking on elements of List,Tuple,Set...
r3870 if obj is not None:
e = "The '%s' trait of %s instance must be %s, but a value of %s was specified." \
% (self.name, class_of(obj),
self.info(), msg)
else:
e = "The '%s' trait must be %s, but a value of %r was specified." \
% (self.name, self.info(), msg)
raise TraitError(e)
Brian Granger
Added support for Type and Instance traitlets with testing.
r2177
Dav Clark
Final changes traitlet -> trait for review
r2385 class Type(ClassBasedTraitType):
"""A trait whose value must be a subclass of a specified class."""
Brian Granger
Added support for Type and Instance traitlets with testing.
r2177
def __init__ (self, default_value=None, klass=None, allow_none=True, **metadata ):
Dav Clark
Final changes traitlet -> trait for review
r2385 """Construct a Type trait
Brian Granger
Added support for Type and Instance traitlets with testing.
r2177
Dav Clark
Final changes traitlet -> trait for review
r2385 A Type trait specifies that its values must be subclasses of
Brian Granger
Added support for Type and Instance traitlets with testing.
r2177 a particular class.
Brian Granger
A number of changes to how traitlets and components work....
r2229 If only ``default_value`` is given, it is used for the ``klass`` as
well.
Brian Granger
Added support for Type and Instance traitlets with testing.
r2177 Parameters
----------
Brian Granger
A number of changes to how traitlets and components work....
r2229 default_value : class, str or None
The default value must be a subclass of klass. If an str,
the str must be a fully specified class name, like 'foo.bar.Bah'.
The string is resolved into real class, when the parent
Dav Clark
Iniital stab at renames for traitlets
r2384 :class:`HasTraits` class is instantiated.
Brian Granger
Added support for Type and Instance traitlets with testing.
r2177 klass : class, str, None
Dav Clark
Final changes traitlet -> trait for review
r2385 Values of this trait must be a subclass of klass. The klass
Brian Granger
Added support for Type and Instance traitlets with testing.
r2177 may be specified in a string like: 'foo.bar.MyClass'.
Brian Granger
A number of changes to how traitlets and components work....
r2229 The string is resolved into real class, when the parent
Dav Clark
Iniital stab at renames for traitlets
r2384 :class:`HasTraits` class is instantiated.
Brian Granger
Added support for Type and Instance traitlets with testing.
r2177 allow_none : boolean
Indicates whether None is allowed as an assignable value. Even if
``False``, the default value may be ``None``.
"""
if default_value is None:
if klass is None:
klass = object
elif klass is None:
klass = default_value
Brian Granger
A number of changes to how traitlets and components work....
r2229 if not (inspect.isclass(klass) or isinstance(klass, basestring)):
Dav Clark
Final changes traitlet -> trait for review
r2385 raise TraitError("A Type trait must specify a class.")
Brian Granger
Added support for Type and Instance traitlets with testing.
r2177
self.klass = klass
self._allow_none = allow_none
super(Type, self).__init__(default_value, **metadata)
def validate(self, obj, value):
"""Validates that the value is a valid object instance."""
try:
if issubclass(value, self.klass):
return value
except:
if (value is None) and (self._allow_none):
return value
self.error(obj, value)
def info(self):
""" Returns a description of the trait."""
Brian Granger
A number of changes to how traitlets and components work....
r2229 if isinstance(self.klass, basestring):
klass = self.klass
else:
klass = self.klass.__name__
Brian Granger
Added support for Type and Instance traitlets with testing.
r2177 result = 'a subclass of ' + klass
if self._allow_none:
return result + ' or None'
return result
Brian Granger
A number of changes to how traitlets and components work....
r2229 def instance_init(self, obj):
self._resolve_classes()
super(Type, self).instance_init(obj)
def _resolve_classes(self):
if isinstance(self.klass, basestring):
self.klass = import_item(self.klass)
if isinstance(self.default_value, basestring):
self.default_value = import_item(self.default_value)
def get_default_value(self):
return self.default_value
Brian Granger
Added support for Type and Instance traitlets with testing.
r2177
class DefaultValueGenerator(object):
"""A class for generating new default value instances."""
Brian Granger
A number of changes to how traitlets and components work....
r2229 def __init__(self, *args, **kw):
Brian Granger
Added support for Type and Instance traitlets with testing.
r2177 self.args = args
self.kw = kw
Brian Granger
A number of changes to how traitlets and components work....
r2229 def generate(self, klass):
return klass(*self.args, **self.kw)
Brian Granger
Added support for Type and Instance traitlets with testing.
r2177
Brian Granger
Important changes to simplify traitlets....
r2182
Dav Clark
Final changes traitlet -> trait for review
r2385 class Instance(ClassBasedTraitType):
Brian Granger
Added support for Type and Instance traitlets with testing.
r2177 """A trait whose value must be an instance of a specified class.
The value can also be an instance of a subclass of the specified class.
"""
Brian Granger
Important changes to simplify traitlets....
r2182 def __init__(self, klass=None, args=None, kw=None,
allow_none=True, **metadata ):
Dav Clark
Final changes traitlet -> trait for review
r2385 """Construct an Instance trait.
Brian Granger
Added support for Type and Instance traitlets with testing.
r2177
Dav Clark
Final changes traitlet -> trait for review
r2385 This trait allows values that are instances of a particular
Brian Granger
Important changes to simplify traitlets....
r2182 class or its sublclasses. Our implementation is quite different
from that of enthough.traits as we don't allow instances to be used
for klass and we handle the ``args`` and ``kw`` arguments differently.
Brian Granger
Added support for Type and Instance traitlets with testing.
r2177 Parameters
----------
Brian Granger
A number of changes to how traitlets and components work....
r2229 klass : class, str
Dav Clark
Final changes traitlet -> trait for review
r2385 The class that forms the basis for the trait. Class names
Brian Granger
A number of changes to how traitlets and components work....
r2229 can also be specified as strings, like 'foo.bar.Bar'.
Brian Granger
Added support for Type and Instance traitlets with testing.
r2177 args : tuple
Positional arguments for generating the default value.
kw : dict
Keyword arguments for generating the default value.
allow_none : bool
Indicates whether None is allowed as a value.
Default Value
-------------
Brian Granger
Important changes to simplify traitlets....
r2182 If both ``args`` and ``kw`` are None, then the default value is None.
If ``args`` is a tuple and ``kw`` is a dict, then the default is
created as ``klass(*args, **kw)``. If either ``args`` or ``kw`` is
not (but not both), None is replace by ``()`` or ``{}``.
Brian Granger
Added support for Type and Instance traitlets with testing.
r2177 """
self._allow_none = allow_none
Brian Granger
Important changes to simplify traitlets....
r2182
Brian Granger
A number of changes to how traitlets and components work....
r2229 if (klass is None) or (not (inspect.isclass(klass) or isinstance(klass, basestring))):
Dav Clark
Final changes traitlet -> trait for review
r2385 raise TraitError('The klass argument must be a class'
Brian Granger
Important changes to simplify traitlets....
r2182 ' you gave: %r' % klass)
self.klass = klass
# self.klass is a class, so handle default_value
if args is None and kw is None:
Brian Granger
Added support for Type and Instance traitlets with testing.
r2177 default_value = None
else:
if args is None:
Brian Granger
Important changes to simplify traitlets....
r2182 # kw is not None
Brian Granger
Added support for Type and Instance traitlets with testing.
r2177 args = ()
Brian Granger
Important changes to simplify traitlets....
r2182 elif kw is None:
# args is not None
kw = {}
Brian Granger
Added support for Type and Instance traitlets with testing.
r2177 if not isinstance(kw, dict):
Dav Clark
Final changes traitlet -> trait for review
r2385 raise TraitError("The 'kw' argument must be a dict or None.")
Brian Granger
Added support for Type and Instance traitlets with testing.
r2177 if not isinstance(args, tuple):
Dav Clark
Final changes traitlet -> trait for review
r2385 raise TraitError("The 'args' argument must be a tuple or None.")
Brian Granger
Added support for Type and Instance traitlets with testing.
r2177
Brian Granger
A number of changes to how traitlets and components work....
r2229 default_value = DefaultValueGenerator(*args, **kw)
Brian Granger
Added support for Type and Instance traitlets with testing.
r2177
super(Instance, self).__init__(default_value, **metadata)
def validate(self, obj, value):
if value is None:
if self._allow_none:
return value
Brian Granger
Important changes to simplify traitlets....
r2182 self.error(obj, value)
Brian Granger
Added support for Type and Instance traitlets with testing.
r2177
if isinstance(value, self.klass):
return value
else:
Brian Granger
Important changes to simplify traitlets....
r2182 self.error(obj, value)
Brian Granger
Added support for Type and Instance traitlets with testing.
r2177
Brian Granger
Important changes to simplify traitlets....
r2182 def info(self):
Brian Granger
A number of changes to how traitlets and components work....
r2229 if isinstance(self.klass, basestring):
klass = self.klass
else:
klass = self.klass.__name__
Brian Granger
Added support for Type and Instance traitlets with testing.
r2177 result = class_of(klass)
if self._allow_none:
return result + ' or None'
return result
Brian Granger
A number of changes to how traitlets and components work....
r2229 def instance_init(self, obj):
self._resolve_classes()
super(Instance, self).instance_init(obj)
def _resolve_classes(self):
if isinstance(self.klass, basestring):
self.klass = import_item(self.klass)
Brian Granger
Important changes to simplify traitlets....
r2182 def get_default_value(self):
Brian Granger
Added support for Type and Instance traitlets with testing.
r2177 """Instantiate a default value instance.
Dav Clark
Iniital stab at renames for traitlets
r2384 This is called when the containing HasTraits classes'
Brian Granger
Important changes to simplify traitlets....
r2182 :meth:`__new__` method is called to ensure that a unique instance
Dav Clark
Iniital stab at renames for traitlets
r2384 is created for each HasTraits instance.
Brian Granger
Added support for Type and Instance traitlets with testing.
r2177 """
dv = self.default_value
if isinstance(dv, DefaultValueGenerator):
Brian Granger
A number of changes to how traitlets and components work....
r2229 return dv.generate(self.klass)
Brian Granger
Added support for Type and Instance traitlets with testing.
r2177 else:
return dv
Dav Clark
Final changes traitlet -> trait for review
r2385 class This(ClassBasedTraitType):
"""A trait for instances of the class containing this trait.
Brian Granger
Improvements to component.py....
r2180
Brian Granger
Important changes to simplify traitlets....
r2182 Because how how and when class bodies are executed, the ``This``
Dav Clark
Final changes traitlet -> trait for review
r2385 trait can only have a default value of None. This, and because we
Brian Granger
Important changes to simplify traitlets....
r2182 always validate default values, ``allow_none`` is *always* true.
"""
Brian Granger
Improvements to component.py....
r2180
Brian Granger
Important changes to simplify traitlets....
r2182 info_text = 'an instance of the same type as the receiver or None'
Brian Granger
Improvements to component.py....
r2180
Brian Granger
Important changes to simplify traitlets....
r2182 def __init__(self, **metadata):
super(This, self).__init__(None, **metadata)
Brian Granger
Improvements to component.py....
r2180
Brian Granger
Important changes to simplify traitlets....
r2182 def validate(self, obj, value):
Brian Granger
Fixing subtle bug in the traitlets with This....
r2183 # What if value is a superclass of obj.__class__? This is
# complicated if it was the superclass that defined the This
Dav Clark
Final changes traitlet -> trait for review
r2385 # trait.
Brian Granger
Fixing subtle bug in the traitlets with This....
r2183 if isinstance(value, self.this_class) or (value is None):
Brian Granger
Improvements to component.py....
r2180 return value
else:
Brian Granger
Important changes to simplify traitlets....
r2182 self.error(obj, value)
Brian Granger
Improvements to component.py....
r2180
Brian Granger
Added support for Type and Instance traitlets with testing.
r2177 #-----------------------------------------------------------------------------
Dav Clark
Final changes traitlet -> trait for review
r2385 # Basic TraitTypes implementations/subclasses
Brian Granger
Added support for Type and Instance traitlets with testing.
r2177 #-----------------------------------------------------------------------------
Brian Granger
First prototype of component, traitlets and a config loader.
r2157
Dav Clark
Final changes traitlet -> trait for review
r2385 class Any(TraitType):
Brian Granger
First prototype of component, traitlets and a config loader.
r2157 default_value = None
info_text = 'any value'
Dav Clark
Final changes traitlet -> trait for review
r2385 class Int(TraitType):
"""A integer trait."""
Brian Granger
First prototype of component, traitlets and a config loader.
r2157
default_value = 0
info_text = 'an integer'
def validate(self, obj, value):
if isinstance(value, int):
return value
self.error(obj, value)
Brian Granger
Added casting versions of all the basic traitlet types.
r2178 class CInt(Int):
Dav Clark
Final changes traitlet -> trait for review
r2385 """A casting version of the int trait."""
Brian Granger
Added casting versions of all the basic traitlet types.
r2178
def validate(self, obj, value):
try:
return int(value)
except:
self.error(obj, value)
Brian Granger
First prototype of component, traitlets and a config loader.
r2157
Dav Clark
Final changes traitlet -> trait for review
r2385 class Long(TraitType):
"""A long integer trait."""
Brian Granger
First prototype of component, traitlets and a config loader.
r2157
default_value = 0L
info_text = 'a long'
def validate(self, obj, value):
if isinstance(value, long):
return value
if isinstance(value, int):
return long(value)
self.error(obj, value)
Brian Granger
Added casting versions of all the basic traitlet types.
r2178 class CLong(Long):
Dav Clark
Final changes traitlet -> trait for review
r2385 """A casting version of the long integer trait."""
Brian Granger
Added casting versions of all the basic traitlet types.
r2178
def validate(self, obj, value):
try:
return long(value)
except:
self.error(obj, value)
Dav Clark
Final changes traitlet -> trait for review
r2385 class Float(TraitType):
"""A float trait."""
Brian Granger
First prototype of component, traitlets and a config loader.
r2157
default_value = 0.0
info_text = 'a float'
def validate(self, obj, value):
if isinstance(value, float):
return value
if isinstance(value, int):
return float(value)
self.error(obj, value)
Brian Granger
Added casting versions of all the basic traitlet types.
r2178 class CFloat(Float):
Dav Clark
Final changes traitlet -> trait for review
r2385 """A casting version of the float trait."""
Brian Granger
Added casting versions of all the basic traitlet types.
r2178
def validate(self, obj, value):
try:
return float(value)
except:
self.error(obj, value)
Dav Clark
Final changes traitlet -> trait for review
r2385 class Complex(TraitType):
"""A trait for complex numbers."""
Brian Granger
First prototype of component, traitlets and a config loader.
r2157
default_value = 0.0 + 0.0j
info_text = 'a complex number'
def validate(self, obj, value):
if isinstance(value, complex):
return value
if isinstance(value, (float, int)):
return complex(value)
self.error(obj, value)
Brian Granger
Added casting versions of all the basic traitlet types.
r2178 class CComplex(Complex):
Dav Clark
Final changes traitlet -> trait for review
r2385 """A casting version of the complex number trait."""
Brian Granger
Added casting versions of all the basic traitlet types.
r2178
def validate (self, obj, value):
try:
return complex(value)
except:
self.error(obj, value)
Thomas Kluyver
Eliminate Str and CStr trait types except in IPython.parallel
r4046 # We should always be explicit about whether we're using bytes or unicode, both
# for Python 3 conversion and for reliable unicode behaviour on Python 2. So
# we don't have a Str type.
Thomas Kluyver
Arrange Str and Bytes traitlets to simplify automatic conversion to Python 3.
r4044 class Bytes(TraitType):
Dav Clark
Final changes traitlet -> trait for review
r2385 """A trait for strings."""
Brian Granger
First prototype of component, traitlets and a config loader.
r2157
default_value = ''
info_text = 'a string'
def validate(self, obj, value):
Thomas Kluyver
Arrange Str and Bytes traitlets to simplify automatic conversion to Python 3.
r4044 if isinstance(value, bytes):
Brian Granger
First prototype of component, traitlets and a config loader.
r2157 return value
self.error(obj, value)
Thomas Kluyver
Arrange Str and Bytes traitlets to simplify automatic conversion to Python 3.
r4044 class CBytes(Bytes):
Dav Clark
Final changes traitlet -> trait for review
r2385 """A casting version of the string trait."""
Brian Granger
Added casting versions of all the basic traitlet types.
r2178
def validate(self, obj, value):
try:
Thomas Kluyver
Arrange Str and Bytes traitlets to simplify automatic conversion to Python 3.
r4044 return bytes(value)
Brian Granger
Added casting versions of all the basic traitlet types.
r2178 except:
Thomas Kluyver
CBytes and CStr only try casting to bytes (=str), not to unicode.
r4045 self.error(obj, value)
Brian Granger
Added casting versions of all the basic traitlet types.
r2178
Dav Clark
Final changes traitlet -> trait for review
r2385 class Unicode(TraitType):
"""A trait for unicode strings."""
Brian Granger
First prototype of component, traitlets and a config loader.
r2157
default_value = u''
info_text = 'a unicode string'
def validate(self, obj, value):
if isinstance(value, unicode):
return value
Thomas Kluyver
Arrange Str and Bytes traitlets to simplify automatic conversion to Python 3.
r4044 if isinstance(value, bytes):
Brian Granger
First prototype of component, traitlets and a config loader.
r2157 return unicode(value)
self.error(obj, value)
Brian Granger
Added casting versions of all the basic traitlet types.
r2178 class CUnicode(Unicode):
Dav Clark
Final changes traitlet -> trait for review
r2385 """A casting version of the unicode trait."""
Brian Granger
Added casting versions of all the basic traitlet types.
r2178
def validate(self, obj, value):
try:
return unicode(value)
except:
self.error(obj, value)
Thomas Kluyver
Add ObjectName and DottedObjectName trait types for referring to Python identifiers.
r4047
class ObjectName(TraitType):
"""A string holding a valid object name in this version of Python.
This does not check that the name exists in any scope."""
info_text = "a valid object identifier in Python"
if sys.version_info[0] < 3:
# Python 2:
_name_re = re.compile(r"[a-zA-Z_][a-zA-Z0-9_]*$")
def isidentifier(self, s):
return bool(self._name_re.match(s))
def coerce_str(self, obj, value):
"In Python 2, coerce ascii-only unicode to str"
if isinstance(value, unicode):
try:
return str(value)
except UnicodeEncodeError:
self.error(obj, value)
return value
else:
# Python 3:
isidentifier = staticmethod(lambda s: s.isidentifier())
coerce_str = staticmethod(lambda _,s: s)
def validate(self, obj, value):
value = self.coerce_str(obj, value)
if isinstance(value, str) and self.isidentifier(value):
return value
self.error(obj, value)
class DottedObjectName(ObjectName):
"""A string holding a valid dotted object name in Python, such as A.b3._c"""
def validate(self, obj, value):
value = self.coerce_str(obj, value)
if isinstance(value, str) and all(self.isidentifier(x) \
for x in value.split('.')):
return value
self.error(obj, value)
Brian Granger
Added casting versions of all the basic traitlet types.
r2178
Brian Granger
First prototype of component, traitlets and a config loader.
r2157
Dav Clark
Final changes traitlet -> trait for review
r2385 class Bool(TraitType):
"""A boolean (True, False) trait."""
Brian Granger
Minor work on kernelmanager....
r2742
Brian Granger
First prototype of component, traitlets and a config loader.
r2157 default_value = False
info_text = 'a boolean'
def validate(self, obj, value):
if isinstance(value, bool):
return value
self.error(obj, value)
Brian Granger
Added casting versions of all the basic traitlet types.
r2178
class CBool(Bool):
Dav Clark
Final changes traitlet -> trait for review
r2385 """A casting version of the boolean trait."""
Brian Granger
Added casting versions of all the basic traitlet types.
r2178
def validate(self, obj, value):
try:
return bool(value)
except:
Brian Granger
More work on getting rid of ipmaker.
r2203 self.error(obj, value)
Brian Granger
More work on InteractiveShell and ipmaker. It works!
r2204
Dav Clark
Final changes traitlet -> trait for review
r2385 class Enum(TraitType):
Brian Granger
More work on InteractiveShell and ipmaker. It works!
r2204 """An enum that whose value must be in a given sequence."""
Brian Granger
More work on getting rid of ipmaker.
r2203
def __init__(self, values, default_value=None, allow_none=True, **metadata):
self.values = values
self._allow_none = allow_none
super(Enum, self).__init__(default_value, **metadata)
def validate(self, obj, value):
if value is None:
if self._allow_none:
return value
if value in self.values:
return value
self.error(obj, value)
def info(self):
""" Returns a description of the trait."""
result = 'any of ' + repr(self.values)
if self._allow_none:
return result + ' or None'
return result
class CaselessStrEnum(Enum):
Brian Granger
More work on InteractiveShell and ipmaker. It works!
r2204 """An enum of strings that are caseless in validate."""
Brian Granger
More work on getting rid of ipmaker.
r2203
def validate(self, obj, value):
if value is None:
if self._allow_none:
return value
MinRK
fix handling of unicode in KV loader...
r4162 if not isinstance(value, basestring):
Brian Granger
More work on getting rid of ipmaker.
r2203 self.error(obj, value)
for v in self.values:
if v.lower() == value.lower():
return v
Brian Granger
More work on InteractiveShell and ipmaker. It works!
r2204 self.error(obj, value)
MinRK
Allow type checking on elements of List,Tuple,Set...
r3870 class Container(Instance):
"""An instance of a container (list, set, etc.)
Brian Granger
More work on InteractiveShell and ipmaker. It works!
r2204
MinRK
Allow type checking on elements of List,Tuple,Set...
r3870 To be subclassed by overriding klass.
"""
klass = None
_valid_defaults = SequenceTypes
_trait = None
Brian Granger
More work on InteractiveShell and ipmaker. It works!
r2204
MinRK
Allow type checking on elements of List,Tuple,Set...
r3870 def __init__(self, trait=None, default_value=None, allow_none=True,
**metadata):
"""Create a container trait type from a list, set, or tuple.
Brian Granger
More work on InteractiveShell and ipmaker. It works!
r2204
MinRK
Allow type checking on elements of List,Tuple,Set...
r3870 The default value is created by doing ``List(default_value)``,
Brian Granger
More work on InteractiveShell and ipmaker. It works!
r2204 which creates a copy of the ``default_value``.
MinRK
Allow type checking on elements of List,Tuple,Set...
r3870
``trait`` can be specified, which restricts the type of elements
in the container to that TraitType.
If only one arg is given and it is not a Trait, it is taken as
``default_value``:
``c = List([1,2,3])``
Parameters
----------
trait : TraitType [ optional ]
the type for restricting the contents of the Container. If unspecified,
types are not checked.
default_value : SequenceType [ optional ]
The default value for the Trait. Must be list/tuple/set, and
will be cast to the container type.
allow_none : Bool [ default True ]
Whether to allow the value to be None
**metadata : any
further keys for extensions to the Trait (e.g. config)
Brian Granger
More work on InteractiveShell and ipmaker. It works!
r2204 """
MinRK
Allow type checking on elements of List,Tuple,Set...
r3870 istrait = lambda t: isinstance(t, type) and issubclass(t, TraitType)
# allow List([values]):
if default_value is None and not istrait(trait):
default_value = trait
trait = None
Brian Granger
More work on InteractiveShell and ipmaker. It works!
r2204 if default_value is None:
MinRK
Allow type checking on elements of List,Tuple,Set...
r3870 args = ()
elif isinstance(default_value, self._valid_defaults):
Brian Granger
More work on InteractiveShell and ipmaker. It works!
r2204 args = (default_value,)
Dav Clark
diff I sent to Fernando
r2380 else:
MinRK
Allow type checking on elements of List,Tuple,Set...
r3870 raise TypeError('default value of %s was %s' %(self.__class__.__name__, default_value))
if istrait(trait):
self._trait = trait()
self._trait.name = 'element'
elif trait is not None:
raise TypeError("`trait` must be a Trait or None, got %s"%repr_type(trait))
Brian Granger
More work on InteractiveShell and ipmaker. It works!
r2204
MinRK
Allow type checking on elements of List,Tuple,Set...
r3870 super(Container,self).__init__(klass=self.klass, args=args,
Brian Granger
More work on InteractiveShell and ipmaker. It works!
r2204 allow_none=allow_none, **metadata)
Brian Granger
Minor work on kernelmanager....
r2742
MinRK
Allow type checking on elements of List,Tuple,Set...
r3870 def element_error(self, obj, element, validator):
e = "Element of the '%s' trait of %s instance must be %s, but a value of %s was specified." \
% (self.name, class_of(obj), validator.info(), repr_type(element))
raise TraitError(e)
Brian Granger
Minor work on kernelmanager....
r2742
MinRK
Allow type checking on elements of List,Tuple,Set...
r3870 def validate(self, obj, value):
value = super(Container, self).validate(obj, value)
if value is None:
return value
MinRK
Refactor newparallel to use Config system...
r3604
MinRK
Allow type checking on elements of List,Tuple,Set...
r3870 value = self.validate_elements(obj, value)
return value
def validate_elements(self, obj, value):
validated = []
if self._trait is None or isinstance(self._trait, Any):
return value
for v in value:
try:
v = self._trait.validate(obj, v)
except TraitError:
self.element_error(obj, v, self._trait)
else:
validated.append(v)
return self.klass(validated)
class List(Container):
"""An instance of a Python list."""
klass = list
MinRK
Refactor newparallel to use Config system...
r3604
MinRK
Allow type checking on elements of List,Tuple,Set...
r3870 def __init__(self, trait=None, default_value=None, minlen=0, maxlen=sys.maxint,
allow_none=True, **metadata):
"""Create a List trait type from a list, set, or tuple.
The default value is created by doing ``List(default_value)``,
MinRK
Refactor newparallel to use Config system...
r3604 which creates a copy of the ``default_value``.
MinRK
Allow type checking on elements of List,Tuple,Set...
r3870
``trait`` can be specified, which restricts the type of elements
in the container to that TraitType.
If only one arg is given and it is not a Trait, it is taken as
``default_value``:
``c = List([1,2,3])``
Parameters
----------
trait : TraitType [ optional ]
the type for restricting the contents of the Container. If unspecified,
types are not checked.
default_value : SequenceType [ optional ]
The default value for the Trait. Must be list/tuple/set, and
will be cast to the container type.
minlen : Int [ default 0 ]
The minimum length of the input list
maxlen : Int [ default sys.maxint ]
The maximum length of the input list
allow_none : Bool [ default True ]
Whether to allow the value to be None
**metadata : any
further keys for extensions to the Trait (e.g. config)
MinRK
Refactor newparallel to use Config system...
r3604 """
MinRK
Allow type checking on elements of List,Tuple,Set...
r3870 self._minlen = minlen
self._maxlen = maxlen
super(List, self).__init__(trait=trait, default_value=default_value,
allow_none=allow_none, **metadata)
def length_error(self, obj, value):
e = "The '%s' trait of %s instance must be of length %i <= L <= %i, but a value of %s was specified." \
% (self.name, class_of(obj), self._minlen, self._maxlen, value)
raise TraitError(e)
def validate_elements(self, obj, value):
length = len(value)
if length < self._minlen or length > self._maxlen:
self.length_error(obj, value)
return super(List, self).validate_elements(obj, value)
class Set(Container):
"""An instance of a Python set."""
klass = set
class Tuple(Container):
"""An instance of a Python tuple."""
klass = tuple
def __init__(self, *traits, **metadata):
"""Tuple(*traits, default_value=None, allow_none=True, **medatata)
Create a tuple from a list, set, or tuple.
Create a fixed-type tuple with Traits:
``t = Tuple(Int, Str, CStr)``
would be length 3, with Int,Str,CStr for each element.
If only one arg is given and it is not a Trait, it is taken as
default_value:
``t = Tuple((1,2,3))``
Otherwise, ``default_value`` *must* be specified by keyword.
Parameters
----------
*traits : TraitTypes [ optional ]
the tsype for restricting the contents of the Tuple. If unspecified,
types are not checked. If specified, then each positional argument
corresponds to an element of the tuple. Tuples defined with traits
are of fixed length.
default_value : SequenceType [ optional ]
The default value for the Tuple. Must be list/tuple/set, and
will be cast to a tuple. If `traits` are specified, the
`default_value` must conform to the shape and type they specify.
allow_none : Bool [ default True ]
Whether to allow the value to be None
**metadata : any
further keys for extensions to the Trait (e.g. config)
"""
default_value = metadata.pop('default_value', None)
allow_none = metadata.pop('allow_none', True)
istrait = lambda t: isinstance(t, type) and issubclass(t, TraitType)
# allow Tuple((values,)):
if len(traits) == 1 and default_value is None and not istrait(traits[0]):
default_value = traits[0]
traits = ()
MinRK
Refactor newparallel to use Config system...
r3604 if default_value is None:
MinRK
Allow type checking on elements of List,Tuple,Set...
r3870 args = ()
elif isinstance(default_value, self._valid_defaults):
MinRK
Refactor newparallel to use Config system...
r3604 args = (default_value,)
else:
MinRK
Allow type checking on elements of List,Tuple,Set...
r3870 raise TypeError('default value of %s was %s' %(self.__class__.__name__, default_value))
self._traits = []
for trait in traits:
t = trait()
t.name = 'element'
self._traits.append(t)
if self._traits and default_value is None:
# don't allow default to be an empty container if length is specified
args = None
super(Container,self).__init__(klass=self.klass, args=args,
MinRK
Refactor newparallel to use Config system...
r3604 allow_none=allow_none, **metadata)
MinRK
Allow type checking on elements of List,Tuple,Set...
r3870 def validate_elements(self, obj, value):
if not self._traits:
# nothing to validate
return value
if len(value) != len(self._traits):
e = "The '%s' trait of %s instance requires %i elements, but a value of %s was specified." \
% (self.name, class_of(obj), len(self._traits), repr_type(value))
raise TraitError(e)
validated = []
for t,v in zip(self._traits, value):
try:
v = t.validate(obj, v)
except TraitError:
self.element_error(obj, v, t)
else:
validated.append(v)
return tuple(validated)
MinRK
Refactor newparallel to use Config system...
r3604
Brian Granger
Finishing work on configurables, plugins and extensions.
r2738 class Dict(Instance):
"""An instance of a Python dict."""
def __init__(self, default_value=None, allow_none=True, **metadata):
"""Create a dict trait type from a dict.
The default value is created by doing ``dict(default_value)``,
which creates a copy of the ``default_value``.
"""
if default_value is None:
args = ((),)
elif isinstance(default_value, dict):
args = (default_value,)
elif isinstance(default_value, SequenceTypes):
args = (default_value,)
else:
raise TypeError('default value of Dict was %s' % default_value)
super(Dict,self).__init__(klass=dict, args=args,
allow_none=allow_none, **metadata)
Brian Granger
Merge branch 'master' into kernelmanager...
r2752
Brian Granger
Minor work on kernelmanager....
r2742 class TCPAddress(TraitType):
"""A trait for an (ip, port) tuple.
This allows for both IPv4 IP addresses as well as hostnames.
"""
default_value = ('127.0.0.1', 0)
info_text = 'an (ip, port) tuple'
def validate(self, obj, value):
if isinstance(value, tuple):
if len(value) == 2:
if isinstance(value[0], basestring) and isinstance(value[1], int):
port = value[1]
if port >= 0 and port <= 65535:
return value
self.error(obj, value)