[Subversion] / PEAK / src / peak / binding / data_desc.pyx  

View of /PEAK/src/peak/binding/data_desc.pyx

Parent Directory | Revision Log
Revision: 766 - (download)
Fri Nov 29 22:20:23 2002 UTC (21 years, 5 months ago) by pje
File size: 1209 byte(s)
Refactored to allow "lazy" metadata computation, using bindings.
This means that you can use attribute bindings in metaclasses to assemble
metadata registries, such as those needed for XMI.

Unfortunately, for this to work on types, I had to change the fundamental
implementation of attribute bindings to a new implementation in Pyrex/C.
The problem is that only *data* descriptors from a metaclass are invoked
if there is an attribute value available in the type's dictionary or the
dictionary of one of its base types.  This means that trying to have
'Once' bindings that attach to classes via their metaclass, is inherently
unstable unless you make use of the bindings in strict reverse __mro__
order!  This problem has actually existed ever since I added the ability
to use bindings in metaclasses, but because of the way things were being
used, it "just happened" to look like it was working.

So I had to make 'Once' a data descriptor; unfortunately this means that
it has to check whether the value appears in the object's dictionary
*every* time the attribute is accessed.  That's still doable from Python,
but the bigger problem is that type dictionaries aren't accessible from
pure Python code, and the only way to implement the __set__ function on
a 'Once' descriptor is by writing to the dictionary.  So I wrote a Pyrex
extension type to support getting at the object's true dictionary, and
to implement a (relatively) fast __get__ method.  The result seems to
perform about as well as the old version, although I'm tempted to redo
some of it in pure C to get rid of a lot of overhead that would be
avoidable if Pyrex properly supported the '__get__' signature for
extension types.

Up next: standardizing the metaclass naming convention, documenting all this
stuff, then maybe on to XMI writing...
cdef extern from "Python.h":
    int PyType_Check(object o)

cdef extern from "py_obj.h":
    object GET_DICTIONARY(object o)

cdef extern from "object.h":
    pass


from peak.api import NOT_FOUND


class data_descr(object):

    """Data descriptor base class for 'Once' bindings"""
    
    def __set__(self, obj, value):
        d = GET_DICTIONARY(obj)
        d[self.attrName] = value


    def __delete__(self, obj):
        d = GET_DICTIONARY(obj)
        del d[self.attrName]















        
    def __get__(self, obj, typ=None):
    
        """Compute the attribute value and cache it

            Note: fails if attribute name not supplied or doesn't reference
            this descriptor!
        """

        if obj is None:
            return self

        n = self.attrName
        d = GET_DICTIONARY(obj)

        if n in d:
            return d[n]
            
        if not n or getattr(obj.__class__, n, None) is not self:
            self.usageError()

        d[n] = NOT_FOUND    # recursion guard

        try:
            value = self.computeValue(obj, obj.__dict__, n)
        except:
            del d[n]
            raise

        setattr(obj,n,value)
        return value



cvs-admin@eby-sarna.com

Powered by ViewCVS 1.0-dev

ViewCVS and CVS Help