[Subversion] / PEAK / src / peak / binding / components.py  

View of /PEAK/src/peak/binding/components.py

Parent Directory | Revision Log
Revision: 331 - (download) (as text)
Fri Feb 15 23:36:20 2002 UTC (22 years, 2 months ago) by pje
File size: 8162 byte(s)
Pre-release documentation and cleanup sweep, part 2.  Cleaned up the rest
of the 3-letter packages (SEF, MOF, and API), replacing StructuralModel
with SEF along the way.  Also moved some of the key metaclasses into their
own module, TW.API.Meta.
"""Basic, in-memory implementation of the Service-Element-Feature pattern"""

from TW.API import *
from TW.SEF.Interfaces import *
from TW.SEF.Interfaces import __all__ as allInterfaces

from types import TupleType
from Interface import Standard


__all__ = [
    'Base','App','Service','TypeService','DynamicBinding','StaticBinding',
    'StructuralFeature', 'Field', 'Collection', 'Reference', 'Sequence',
    'Classifier','PrimitiveType','Enumeration','DataType','Element'
]


# We export the interfaces too, so people don't have to dig for them...

__all__ += allInterfaces




class DynamicBindingMC(Meta.AssertInterfaces):

    def __get__(self, obj, typ=None):
        if obj is None: return self        
        newOb = self()
        newOb._setSEFparent(obj)
        obj.__dict__[newOb._componentName] = newOb
        return newOb


class DynamicBinding(object):
    __metaclass__ = DynamicBindingMC





class Base(object):

    """Base for all S-E-F classes"""

    __metaclasses__  = Meta.AssertInterfaces, Meta.ClassInit
    __implements__ = ISEF
    _sefParent     = None

    def getService(self,name=None):

        if name:
            if not isinstance(name,TupleType):
                name = tuple(name.split('.'))
                
            if hasattr(self,name[0]):
                o = getattr(self,name[0])
                if len(name)==1:
                    return o
                else:
                    return o.getService(name[1:])
            else:    
                parent = self.getSEFparent()
                if parent is not None:
                    return parent.getService(name)
        else:                
            return self.getSEFparent()


    def _setSEFparent(self,parent):
        from weakref import ref
        self.getSEFparent = ref(parent)

    def getSEFparent(self):
        return None

    def _componentName(self):
        return self.__class__.__name__

    _componentName = property(_componentName)


class App(Base):

    """Application class"""

    def newElement(self,elementType,*args,**kw):
        element = apply(getattr(self,elementType),args,kw)  # XXX won't do dotted names
        element._fData = {}
        element._setSEFparent(self)
        return element


class Service(DynamicBinding, Base):

    """Instance (as opposed to class)"""

    __implements__ = IService
    

class TypeService(Service):

    """Service that supports a (possibly abstract) class"""

    __implements__ = ITypeService


class StaticBinding(object):
    pass














class StructuralFeature(DynamicBinding, Base):

    # XXX lowerBound = Eval("isRequired and 1 or 0")
    # XXX lowerBound.copyIntoSubclasses = 1

    isRequired    = 0  # XXX SubclassDefault(0)

    upperBound    = None    # None means unbounded upper end

    isOrdered     = 0
    isChangeable  = 1       # default is to be changeable

    referencedEnd = None    # and without an 'other end'
    referencedType = None

    def getElement(self):
        return self.getSEFparent()
        
    def getService(self,name=None):
        return self.getSEFparent().getService(name)

    def getReferencedType(self):
        return self.getService(self.referencedType)

    def _getData(self,default=()):
        return self.getSEFparent()._fData.get(self._componentName,default)

    def _setData(self,value):
        self.getSEFparent()._fData[self._componentName]=value

    def _delData(self):
        del self.getSEFparent()._fData[self._componentName]

    def _hasData(self):
        return self.getSEFparent()._fData.has_key(self._componentName)






class Field(StructuralFeature):

    __implements__ = IValue
    
    upperBound = 1

    def __call__(self):
        """Return the value of the feature"""
        return self._getData(None)

    def values(self):
        """Return the value(s) of the feature as a sequence, even if it's a single value"""
        v=self._getData(NOT_FOUND)
        if v is NOT_FOUND: return ()
        return v,

    def clear(self):
        """Unset the value of the feature (like __delattr__)"""
        if self._hasData():
            self._delData()

    def set(self,value):
        """Set the value of the feature to value"""
        if self.isChangeable:
            self._set(value)
        else:
            raise TypeError,("Read-only field %s" % self._componentName)

    def _set(self,value):
        self.clear()
        self._setData(value)










class Collection(StructuralFeature):

    __implements__ = ICollection


    def set(self,value):
        """Set the value of the feature to value"""
        self._set(value)


    def addItem(self,item):
        """Add the item to the collection/relationship, reject if multiplicity exceeded"""
        
        ub = self.upperBound
        
        if not ub or len(self)<ub:
            self._notifyLink(item)
            self._link(item)
        else:
            raise ValueError


    def removeItem(self,item):
        """Remove the item from the collection/relationship, if present"""
        self._unlink(item)
        self._notifyUnlink(item)


    def replaceItem(self,oldItem,newItem):
        d = self._getData([])
        p = d.index(oldItem)
        if p!=-1:
            d[p]=newItem
            self._setData(d)
            self._notifyUnlink(oldItem)
            self._notifyLink(newItem)
        else:
            raise ValueError    # XXX



    def __call__(self):
        """Return the value of the feature"""
        return self._getData()


    def values(self):
        """Return the value(s) of the feature as a sequence, even if it's a single value"""
        return self._getData()


    def clear(self):
        """Unset the value of the feature (like __delattr__)"""

        referencedEnd = self.referencedEnd

        d = self._getData()

        if referencedEnd:
            element = self.getElement()
            for item in d:
                otherEnd = getattr(item,referencedEnd)
                otherEnd._unlink(element)

        if d:
            self._delData()


    def __len__(self):
        return len(self._getData())

    def isEmpty(self):
        return len(self._getData())==0

    def isReferenced(self,item):
        return item in self._getData()






    def _notifyLink(self,item):
        referencedEnd = self.referencedEnd
        if referencedEnd:
            otherEnd = getattr(item,referencedEnd)
            otherEnd._link(self.getElement())

    def _notifyUnlink(self,item):
        referencedEnd = self.referencedEnd
        if referencedEnd:
            otherEnd = getattr(item,referencedEnd)
            otherEnd._unlink(self.getElement())


    def _set(self,value):
        self.clear()
        self._setData(value)


    def _link(self,element):
        d=self._getData([])
        d.append(element)
        self._setData(d)

    def _unlink(self,element):
        d=self._getData([])
        d.remove(element)
        self._setData(d)














class Reference(Collection):

    __implements__ = IReference

    upperBound = 1

    def __call__(self):
        """Return the value of the feature"""
        return self._getData(None)

    def _set(self,value):
        self.clear()
        self._setData([value])


class Sequence(Collection):

    __implements__ = ISequence

    isOrdered = 1

    def insertBefore(self,oldItem,newItem):

        d = self._getData([])
        
        ub = self.upperBound
        if ub and len(d)>=ub:
            raise ValueError    # XXX

        i = -1
        if d: i = d.index(element)

        if i!=-1:
            d.insert(i,newItem)
            self._setData(d)
            self._notifyLink(newItem)
        else:
            raise ValueError    # XXX
    


class Classifier(StaticBinding, Base):
    """Basis for all flavors"""
            
class PrimitiveType(Classifier):
    """A primitive type (e.g. Boolean, String, etc.)"""

class Enumeration(DynamicBinding, Classifier):
    """An enumerated type"""

class DataType(Classifier):
    """A complex datatype"""

class Element(DataType):
    """An element in its own right"""
    __implements__ = IElement


setupModule()
























cvs-admin@eby-sarna.com

Powered by ViewCVS 1.0-dev

ViewCVS and CVS Help