Metaclass resolution for InterfaceClass

Laurence Rowe <[email protected]>
Newsgroups gmane.comp.web.zope.devel
Message-ID <[email protected]>
While experimenting with my InterfaceClass subclass I noticed that it
was only being used when it was specified as the first of the bases. I
believe this is because InterfaceClass is not a subclass of ``type``,
so the normal metaclass derivation logic is not applied. The attached
patch implements that logic in InterfaceClass.__new__, picking from
the base metaclasses that metaclass which subclasses all other base
metaclasses.

Laurence

_______________________________________________
Zope-Dev maillist  -  [email protected]
https://mail.zope.org/mailman/listinfo/zope-dev
**  No cross posts or HTML encoding!  **
(Related lists - 
 https://mail.zope.org/mailman/listinfo/zope-announce
 https://mail.zope.org/mailman/listinfo/zope )
metaclass_resolution.diff (application/octet-stream, 2.2 KB)
Index: src/zope/interface/interface.py
===================================================================
--- src/zope/interface/interface.py	(revision 121495)
+++ src/zope/interface/interface.py	(working copy)
@@ -433,6 +433,22 @@
     #
     #implements(IInterface)
 
+    def __new__(cls, name, bases=(), attrs=None, __doc__=None,
+                 __module__=None):
+        # Resolve metaclass in the same way as ``type``
+        for base in bases:
+            meta = type(base)
+            if issubclass(cls, meta):
+                continue
+            if issubclass(meta, cls):
+                cls = meta
+                continue
+            raise TypeError(
+                "Error when calling the metaclass bases\n    "
+                "metaclass conflict: the metaclass of a derived class must be "
+                "a (non-strict) subclass of the metaclasses of all its bases")
+        return object.__new__(cls)
+
     def __init__(self, name, bases=(), attrs=None, __doc__=None,
                  __module__=None):
 
Index: src/zope/interface/tests/test_interface.py
===================================================================
--- src/zope/interface/tests/test_interface.py	(revision 121495)
+++ src/zope/interface/tests/test_interface.py	(working copy)
@@ -413,7 +413,33 @@
     True
     """
 
+def test_subclassing_interfaceclass():
+    """
+As ``InterfaceClass`` does not derive from ``type`` the normal python rules
+for determining the metaclass of a class from it's bases are not applied and
+the. In order to support specialisation, ``InterfaceClass`` resolves the
+metclass itself in ``__new__``.
 
+    >>> from zope.interface import Interface
+    >>> from zope.interface.interface import InterfaceClass
+    >>> class SpecialClass(InterfaceClass): pass
+    ... 
+    >>> Special = SpecialClass('Special')
+    >>> class I(Interface):
+    ...     pass
+
+    >>> class S(Special):
+    ...     pass
+
+    >>> class Combined(I, S):
+    ...     pass
+
+    >>> isinstance(Combined, SpecialClass)
+    True
+    """
+
+
+
 def test_suite():
     suite = unittest.makeSuite(InterfaceTests)
     suite.addTest(doctest.DocTestSuite("zope.interface.interface"))
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.