[Nipy-devel] attributes vs. traits

Brian Hawthorne brian.lee.hawthorne at gmail.com
Mon May 22 16:37:13 CDT 2006


On 5/22/06, Jonathan Taylor <jonathan.taylor at stanford.edu> wrote:
>
> i basically want to be able to use traits for some simple applications,
> so i am ok with leaving them out of the core library (but i don't know
> where the boundary between core and application should be set quite
> yet... but neuroimaging.{image,reference} would definitely fall into
> "core" in my mind)
>
> i could live with a working "traitsbridge" but i have a feeling that it
> might be a lot of work to get working in full generality. if the
> attributes used in the core are simple enough, then i think this should
> work fine (once i really get a feel for the attributes system). this
> way, traits can be left out as a dependency of the "core" but may be
> necessary for some applications. we could perhaps insist that any "core"
> attributes be mappable to a trait through the traitsbridge. some obvious
> ones
> are all the standard python numeric types, as well as the basic numpy
> array types, strings, tuples/lists of such objects, color/rgba?
>


> while this would mean that
> we would not use all of the attributes' functionality in core objects,
> neither would we use all of traits' functionality in core and we could
> consider our core objects "strongly" typed in pure python. this does
> seems a little unpythonic, though.


i think distinguishing between applications and core is an excellent way to
look at the problem.  i envision our image class is to neuroimaging what
ndarray is to numpy, and should behave as similarly to ndarray as possible
(principle of least surprise).  the Axis, CoordinateSystem, Mapping, Grid,
and GridIterator class hierarchies are all auxilliary to the image (internal
components of the image implementation), and should (almost) never need to
be referred to by application programmers except in situations where one is
for example extending image, so might need to tweak the internal behaviour
(like in the fMRIImage).  note that ndarray does not use traits, but does
perform some sort of type checking and readonly checking, for example, try
setting an ndarray's shape to something other than a sequence of ints, and
nbytes is readonly.  i think traits would make much more sense on the
application side, since the graphical editing is one of its key strong
points.

another worry i have is inheritance: unless the traitsbridge is quite
> general, then i would worry about trying to "bridge" attributed
> subclasses. following my line of argument above, this might suggest that
> our core objects should be so fundamental that they shouldn't need to be
> subclassed by users which sounds a little presumptuous. on the other
> hand, if they subclass them and use attributes that can pass over the
> bridge, then nothing is lost.
>
> on another note, i have no idea how much work this is .... brian?


regarding the bridge, i was imagining something like this (rough sketch):
---------------------------------------
from attributes import attribute
from enthought.traits import HasTraits, Trait

class WrapperTrait (Trait):
    # this is where some work would be
    def __init__(self, name, types): pass

def traitforval(name, val):
    return WrapperTrait(name, (type(val),))

def traitforatt(att):
    return WrapperTrait(att.name, att.implements)

def attsof(obj):
    return [(name,getattr(obj,name)) for name in dir(obj)]

def traitswrap(obj):
    newtraits = {}

    # collect traits for unmanaged attributes
    newtraits.update([(name,traitforval(name,val)) for name,val in
vars(obj)]):

    # collect traits for managed attributes
    newtraits.update([(name,traitforatt(att)) for name,att in attsof(obj)]\
                      if issubclass(att, attribute)):

    def __init__(self, obj): self._wrappedobject = obj
    newtraits["__init__"] = __init__
    return type("TraitsProxy", (HasTraits,), newtraits)(obj)
------------------------------------------

then in practice, we would use the traitswrap function to return a HasTraits
object with traits corresponding to the attributes of the wrapped object.
for example, if you want to edit your object "attributey", do this:

traitswrap(attributey).configure_traits()

in the above implementation sketch, the work would go into the WrapperTrait
(maybe a trait factory, not a trait subclass), which would know how to map
attribute types to trait types, and overload trait getting/setting
functionality to delegate to the underlying wrapped object.  not knowing the
traits internals at this time, i can't say exactly how that would be done,
but it shouldn't be too hard.

regarding the ReadOnly trait, looks like i was just plain wrong on that
count.  we must have been looking at some different traits documentation; i
looked it up today in the traits user manual, and it seems pretty clearly
described.  makes me feel a little better though; i was really surprised and
worried before to think that traits didn't support that sort of thing out of
the box.  though as you pointed out, you need to do some extra work to
implement type checking for readonly traits (but since it's expected that
they'll be set internally by the host class, that's not such a big deal, as
you noted).

- brian
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://projects.scipy.org/pipermail/nipy-devel/attachments/20060522/8151a51b/attachment-0002.html 


More information about the Nipy-devel mailing list