[Checkins] SVN: zope.interface/branches/gary-crazy-experiments/src/zope/interface/ Switch to using new-style metaclass hook.

Gary Poster gary.poster at canonical.com
Mon Aug 3 09:08:39 EDT 2009


Log message for revision 102455:
  Switch to using new-style metaclass hook.
  
  Have not yet run tests, but basics (defining an interface, simple
  introspection, declaring a class implements an interface, testing for class
  implementing and object providing) worked in the interpreter.  Good enough
  for a first check in.
  
  

Changed:
  U   zope.interface/branches/gary-crazy-experiments/src/zope/interface/declarations.py
  U   zope.interface/branches/gary-crazy-experiments/src/zope/interface/interface.py

-=-
Modified: zope.interface/branches/gary-crazy-experiments/src/zope/interface/declarations.py
===================================================================
--- zope.interface/branches/gary-crazy-experiments/src/zope/interface/declarations.py	2009-08-03 13:05:52 UTC (rev 102454)
+++ zope.interface/branches/gary-crazy-experiments/src/zope/interface/declarations.py	2009-08-03 13:08:38 UTC (rev 102455)
@@ -30,7 +30,7 @@
 
 import sys
 import weakref
-from zope.interface.interface import InterfaceClass, Specification
+from zope.interface.interface import InterfaceMetaclass, Specification
 from ro import mergeOrderings, ro
 import exceptions
 from types import ClassType, ModuleType
@@ -1363,7 +1363,7 @@
         output = []
 
     cls = sequence.__class__
-    if InterfaceClass in cls.__mro__ or Implements in cls.__mro__:
+    if InterfaceMetaclass in cls.__mro__ or Implements in cls.__mro__:
         output.append(sequence)
     else:
         for v in sequence:

Modified: zope.interface/branches/gary-crazy-experiments/src/zope/interface/interface.py
===================================================================
--- zope.interface/branches/gary-crazy-experiments/src/zope/interface/interface.py	2009-08-03 13:05:52 UTC (rev 102454)
+++ zope.interface/branches/gary-crazy-experiments/src/zope/interface/interface.py	2009-08-03 13:08:38 UTC (rev 102455)
@@ -272,22 +272,20 @@
         else:
             raise KeyError(dependent)
 
-    def __setBases(self, bases):
+    _bases = ()
+    def _setBases(self, bases):
         # Register ourselves as a dependent of our old bases
-        for b in self.__bases__:
+        for b in self._bases:
             b.unsubscribe(self)
-
         # Register ourselves as a dependent of our bases
-        self.__dict__['__bases__'] = bases
+        self._bases = bases
         for b in bases:
             b.subscribe(self)
-
         self.changed(self)
 
     __bases__ = property(
-
-        lambda self: self.__dict__.get('__bases__', ()),
-        __setBases,
+        lambda self: self._bases,
+        _setBases,
         )
 
     def changed(self, originally_changed):
@@ -307,7 +305,7 @@
 
         self.__sro__ = tuple(ancestors)
         self.__iro__ = tuple([ancestor for ancestor in ancestors
-                              if isinstance(ancestor, InterfaceClass)
+                              if isinstance(ancestor, InterfaceMetaclass)
                               ])
 
         for ancestor in ancestors:
@@ -421,7 +419,7 @@
         else:
             return attr
 
-class InterfaceClass(Element, InterfaceBase, Specification):
+class InterfaceMetaclass(type, Element, InterfaceBase, Specification):
     """Prototype (scarecrow) Interfaces Implementation."""
 
     # We can't say this yet because we don't have enough
@@ -429,12 +427,31 @@
     #
     #implements(IInterface)
 
+    # we will consume all of the bits other than the name in the __init__.
+    def __new__(cls, name, bases=(), attrs=None, __doc__=None,
+                __module__=None):
+        return super(InterfaceMetaclass, cls).__new__(cls, name, (), {})
+
+    # We don't want to instantiate a class on a call, but get an object of this
+    # interface.
+    __call__ = InterfaceBase.__call__
+
+    # We need to make sure that the Specification's implementation of __bases__
+    # is used, not type's
+    __bases__ = property(
+        lambda self: self._bases,
+        lambda self, value: self._setBases(value),
+        )
+
     def __init__(self, name, bases=(), attrs=None, __doc__=None,
                  __module__=None):
 
         if attrs is None:
             attrs = {}
 
+        if not bases: # (I.e., this is the root "interface.")
+            del attrs['__metaclass__'] # Interfaces don't want "real" attrs.
+
         if __module__ is None:
             __module__ = attrs.get('__module__')
             if isinstance(__module__, str):
@@ -468,7 +485,7 @@
                 self.setTaggedValue(key, val)
 
         for base in bases:
-            if not isinstance(base, InterfaceClass):
+            if not isinstance(base, InterfaceMetaclass):
                 raise TypeError('Expected base interfaces')
 
         Specification.__init__(self, bases)
@@ -690,8 +707,10 @@
         return c > 0
 
 
-Interface = InterfaceClass("Interface", __module__ = 'zope.interface')
+class Interface:
+    __metaclass__ = InterfaceMetaclass
 
+
 class Attribute(Element):
     """Attribute descriptions
     """
@@ -802,7 +821,7 @@
     classImplements(Method, IMethod)
 
     from zope.interface.interfaces import IInterface, ISpecification
-    classImplements(InterfaceClass, IInterface)
+    classImplements(InterfaceMetaclass, IInterface)
     classImplements(Specification, ISpecification)
 
 # We import this here to deal with module dependencies.



More information about the Checkins mailing list