Commits

masklinn committed 97d8f1e

Fix handling of filter stacks across the mro

Comments (0)

Files changed (2)

     >>> RejectUnCap().accepted_extensions()
     [<class 'QAccepted'>]
 
+And of course, the filters stacks have no issue with multiple inheritance::
+
+    >>> class RejectUnCap(extends.Base):
+    ...     pass
+    >>> RejectUnCap.extension_filter(
+    ...     lambda cls, candidate: \
+    ...         re.match(r'^[A-Z]', candidate.__name__) is not None)
+    >>> class RejectQ(extends.Base):
+    ...     pass
+    >>> RejectQ.extension_filter(
+    ...     lambda cls, candidate: \
+    ...         not candidate.__name__.lower().startswith('q'))
+    >>> class RejectionMachine(RejectUnCap, RejectQ):
+    ...    def accepted_extensions(self):
+    ...        return []
+    >>> class rejectedCaps(extends.Extend, RejectionMachine):
+    ...     def accepted_extensions(self):
+    ...         return [rejectedCaps] \
+    ...                + super(rejectedCaps, self).accepted_extensions()
+    >>> class QRejected(extends.Extend, RejectionMachine):
+    ...     def accepted_extensions(self):
+    ...         return [QRejected] \
+    ...                + super(QRejected, self).accepted_extensions()
+    >>> class ActuallyAccepted(extends.Extend, RejectionMachine):
+    ...     def accepted_extensions(self):
+    ...         return [ActuallyAccepted] \
+    ...                + super(ActuallyAccepted, self).accepted_extensions()
+    >>> RejectionMachine().accepted_extensions()
+    [<class 'ActuallyAccepted'>]
+
+
 Limitations of Extends
 ======================
 

extends/__init__.py

         if sub is not Extend
         if cls._accepts(sub)][::-1]
 
+class MetaBase(type):
+    def __new__(typ, name, bases, attributes):
+        return type.__new__(
+            typ, name, bases,
+            dict(attributes, _extension_filters=[]))
+
 class Extend(object):
     pass
 
 class Base(object):
+    __metaclass__ = MetaBase
     def __new__(cls):
         base_extenders = get_extends(cls)
         ancestor_extenders = sum(
 
         extenders = (base_extenders or [cls]) + ancestor_extenders
         return object.__new__(
-            type(cls.__name__, tuple(extenders), {}))
+            MetaBase(cls.__name__, tuple(extenders), {}))
     @classmethod
     def extension_filter(cls, callable):
-        cls._extension_filters = \
-            [callable] + getattr(cls, '_extension_filters', [])
+        cls._extension_filters.append(callable)
     @classmethod
     def _accepts(cls, candidate):
-        for callable in getattr(cls, '_extension_filters', []):
-            if callable(cls, candidate) is False:
-                return False
+        for class_ in cls.mro():
+            for callable in getattr(class_, '_extension_filters', []):
+                if callable(cls, candidate) is False:
+                    return False
         return True