Source

Extends / extends / __init__.py

__all__ = ['Base', 'Extend']

def get_extends(cls):
    # __subclasses__ is sorted in loading order and the mro
    # executes the bases left-to-right. We want the resolution
    # order of the extended type to be last-loaded first (the
    # latest-loaded extender sees its methods executed first,
    # execution goes up the extension sequence and ends on the
    # base class), therefore we must revert ``extenders``
    return [
        sub for sub in cls.__subclasses__()
        if issubclass(sub, Extend)
        if sub is not Extend
        if cls._accepts(sub)][::-1]

class Extend(object):
    pass

class Base(object):
    def __new__(cls):
        base_extenders = get_extends(cls)
        ancestor_extenders = sum(
            [get_extends(ancestor) for ancestor in cls.mro()[1:]
             if issubclass(ancestor, Base)
             if ancestor is not Base], [])
        if not (base_extenders or ancestor_extenders):
            return object.__new__(cls)

        extenders = (base_extenders or [cls]) + ancestor_extenders
        return object.__new__(
            type(cls.__name__, tuple(extenders), {}))
    @classmethod
    def extension_filter(cls, callable):
        if not hasattr(cls, '_extension_filters'):
            cls._extension_filters = [callable]
        else:
            cls._extension_filters.append(callable)
    @classmethod
    def _accepts(cls, candidate):
        if not hasattr(cls, '_extension_filters'): return True
        for callable in cls._extension_filters:
            if callable(cls, candidate) is False:
                return False
        return super(cls)._accepts(candidate)