[Subversion] / ObjectRoles / peak / util / roles.py  

View of /ObjectRoles/peak/util/roles.py

Parent Directory | Revision Log
Revision: 2344 - (download) (as text)
Thu Jul 12 17:17:30 2007 UTC (16 years, 9 months ago) by pje
File size: 3918 byte(s)
Custom role keys, class roles, weakref support, and docs.
from peak.util.decorators import decorate, decorate_class
from weakref import ref
import sys

__all__ = ['Role', 'ClassRole', 'roledict_for']

_roledicts = {}

def roledict_for(ob):
    """Get the dictionary that should contain roles for `ob`"""
    try:
        d = ob.__dict__
        sd = d.setdefault
        return d
    except (AttributeError, TypeError):
        r = ref(ob)
        try:
            return _roledicts[r]
        except KeyError:
            return _roledicts.setdefault(ref(ob, _roledicts.__delitem__), {})


def additional_tests():
    import doctest
    return doctest.DocFileSuite(
        'README.txt', package='__main__',
        optionflags=doctest.ELLIPSIS|doctest.NORMALIZE_WHITESPACE,
    )













class Role(object):
    """Attach extra state to (almost) any object"""

    __slots__ = ()

    class __metaclass__(type):
        def __call__(cls, ob, *data):
            a = roledict_for(ob)
            role_key = cls.role_key(*data)
            try:
                return a[role_key]
            except KeyError:
                # Use setdefault() to prevent race conditions
                ob = a.setdefault(role_key, type.__call__(cls, ob, *data))
                return ob

    decorate(classmethod)
    def role_key(cls, *args):
        if args: return (cls,)+args
        return cls

    decorate(classmethod)
    def exists_for(cls, ob, *key):
        """Does an aspect of this type for the given key exist?"""
        return cls.role_key(*key) in roledict_for(ob)

    decorate(classmethod)
    def delete_from(cls, ob, *key):
        """Ensure an aspect of this type for the given key does not exist"""
        a = roledict_for(ob)
        try:
            del a[cls.role_key(*key)]
        except KeyError:
            pass

    def __init__(self, subject):
        pass




class ClassRole(Role):
    """Attachment/annotation for classes and types"""

    class __metaclass__(Role.__class__):
        def __call__(cls, ob, *data):
            role_key = cls.role_key(*data)
            d = ob.__dict__
            if role_key in d:
                return d[role_key]
            d2 = roledict_for(ob)
            try:
                return d2[role_key]
            except KeyError:
                # Use setdefault() to prevent race conditions
                ob = d2.setdefault(role_key, type.__call__(cls, ob, *data))
                return ob

    decorate(classmethod)
    def for_enclosing_class(cls, *args, **kw):
        if 'frame' in kw:
            frame = kw.pop('frame')
        else:
            if 'level' in kw:
                level = kw.pop('level')
            else:
                level = 2
            frame = sys._getframe(level)
        if kw:
            raise TypeError("Unexpected keyword arguments", kw)

        a = frame.f_locals
        role_key = cls.role_key(*args)
        try:
            return a[role_key]
        except KeyError:
            # Use setdefault() to prevent race conditions
            ob = a.setdefault(role_key, type.__call__(cls, None, *args))
            decorate_class(ob.__decorate, frame=frame)
            return ob


    decorate(classmethod)
    def exists_for(cls, ob, *key):
        """Does an aspect of this type for the given key exist?"""
        role_key = cls.role_key(*key)
        return role_key in ob.__dict__ or role_key in roledict_for(ob)

    decorate(classmethod)
    def delete_from(cls, ob, *key):
        """Class Roles are not deletable!"""
        raise TypeError("ClassRoles cannot be deleted")

    def __decorate(self, cls):
        self.created_for(cls)
        return cls

    def created_for(self, cls):
        """Override to access the decorated class, as soon as it's known"""

    def __init__(self, subject):
        """Ensure ``created_for()`` is called, if class already exists"""
        if subject is not None:
            self.created_for(subject)




















cvs-admin@eby-sarna.com

Powered by ViewCVS 1.0-dev

ViewCVS and CVS Help