[Zope3-checkins] CVS: Zope3/src/zope/interface - declarations.py:1.6
Jim Fulton
jim@zope.com
Tue, 13 May 2003 15:48:54 -0400
Update of /cvs-repository/Zope3/src/zope/interface
In directory cvs.zope.org:/tmp/cvs-serv2076/src/zope/interface
Modified Files:
declarations.py
Log Message:
Improved interface performance using Steve and Guido's metaclass
trick. This sped up Zope substantially (roughly 80% to render / with
a new database).
=== Zope3/src/zope/interface/declarations.py 1.5 => 1.6 ===
--- Zope3/src/zope/interface/declarations.py:1.5 Wed May 7 11:48:57 2003
+++ Zope3/src/zope/interface/declarations.py Tue May 13 15:48:23 2003
@@ -89,6 +89,7 @@
"""
self.__signature__ = '\t'.join([iface.__identifier__ for iface in iro])
+
def __contains__(self, interface):
"""Test whether an interface is in the specification
@@ -312,6 +313,11 @@
class ImplementsSpecification(InterfaceSpecification):
+ _cspec = None
+ def setClass(self, cls):
+ self._cspec = ImplementsSpecification(_gatherSpecs(cls, []))
+ self.__signature__ = self._cspec.__signature__
+
def __get__(self, inst, cls):
"""Get an implementation specification for an object.
@@ -485,79 +491,144 @@
def __init__(self, ob):
self.ob = ob
+ def _gathersig(self, c, result):
+ flags = getattr(c, '__flags__', heap)
+
+ if flags & heap:
+ try:
+ dict = c.__dict__
+ except AttributeError:
+
+ # XXX If we got here, we must have a
+ # security-proxied class. This introduces an
+ # indirect dependency on security proxies,
+ # which we don't want. This is necessary to
+ # support old-style __implements__ interface
+ # declarations.
+
+ # If we got here, we must have an old-style
+ # declaration, so we'll just look for an
+ # __implements__. We can't fix it because the class
+ # is probably security proxied.
+
+ implements = getattr(c, '__implements__', None)
+ if implements is not None:
+ assert ((implements.__class__ == tuple)
+ or
+ (InterfaceClass in
+ implements.__class__.__mro__)
+ )
+ result.append(`implements`)
+
+ else:
+ # Normal case
+ implements = dict.get('__implements__')
+ if implements is None:
+ # No implements spec, lets add one:
+ classImplements(c)
+ implements = dict['__implements__']
+
+ try:
+ sig = implements.__signature__
+ except AttributeError:
+ # Old-style implements! Fix it up.
+ implements = OnlyImplementsSpecification(
+ implements)
+ _setImplements(c, implements)
+ sig = implements.__signature__
+
+ if sig:
+ result.append(sig)
+
+ else:
+ # Look in reg
+ implements = _implements_reg.get(c)
+ if implements is None:
+ # No implements spec, lets add one:
+ classImplements(c)
+ implements = _implements_reg[c]
+ sig = implements.__signature__
+ if sig:
+ result.append(sig)
+
+
def __signature__(self):
ob = self.ob
provides = getattr(ob, '__provides__', None)
if provides is not None:
- result = [provides.__signature__]
+ provides = provides.__signature__
else:
- result = []
+ provides = ''
+ sig = ''
try:
cls = ob.__class__
except AttributeError:
+ # If there's no class, we'll just use the instance spec
pass
else:
- try:
- mro = cls.__mro__
- except AttributeError:
- mro = _getmro(cls, [])
+ flags = getattr(cls, '__flags__', heap)
- for c in mro:
- try: flags = c.__flags__
- except AttributeError: flags = heap
+ if flags & heap:
+ try:
+ dict = cls.__dict__
+ except AttributeError:
+
+ # XXX If we got here, we must have a
+ # security-proxied class. This introduces an
+ # indirect dependency on security proxies,
+ # which we don't want. This is necessary to
+ # support old-style __implements__ interface
+ # declarations.
+
+ # If we got here, we must have an old-style
+ # declaration, so we'll just look for an
+ # __implements__. We can't fix it because the class
+ # is probably security proxied.
- if flags & heap:
- try:
- dict = c.__dict__
- except AttributeError:
-
- # XXX If we got here, we must have a
- # security-proxied class. This introduces an
- # indirect dependency on security proxies,
- # which we don't want. This is necessary to
- # support old-style __implements__ interface
- # declarations.
-
- # If we got here, we must have an old-style
- # declaration, so we'll just look for an
- # __implements__.
-
- implements = getattr(c, '__implements__', None)
- if implements is not None:
- assert ((implements.__class__ == tuple)
- or
- (InterfaceClass in
- implements.__class__.__mro__)
- )
- result.append(`implements`)
-
- else:
-
- # Normal case
-
- implements = dict.get('__implements__')
-
- if implements is not None:
- try:
- sig = implements.__signature__
- except AttributeError:
- # Old-style implements! Fix it up.
- implements = OnlyImplementsSpecification(
- implements)
- _setImplements(c, implements)
- sig = implements.__signature__
+ implements = getattr(cls, '__implements__', None)
+ if implements is not None:
+ assert ((implements.__class__ == tuple)
+ or
+ (InterfaceClass in
+ implements.__class__.__mro__)
+ )
+ sig = `implements`
- result.append(sig)
else:
- # Look in reg
- implements = _implements_reg.get(c)
- if implements is not None:
- result.append(implements.__signature__)
+ # Normal case
+ implements = dict.get('__implements__')
+ if implements is None:
+ # No implements spec, lets add one:
+ classImplements(cls)
+ implements = dict['__implements__']
- return tuple(result)
+ try:
+ sig = implements.__signature__
+ except AttributeError:
+ # Old-style implements! Fix it up.
+ implements = OnlyImplementsSpecification(
+ implements)
+ _setImplements(cls, implements)
+ sig = implements.__signature__
+
+ else:
+ # Look in reg
+ implements = _implements_reg.get(cls)
+ if implements is None:
+ # No implements spec, lets add one:
+ classImplements(cls)
+ implements = _implements_reg[cls]
+ sig = implements.__signature__
+
+ if sig:
+ if provides:
+ return provides, sig
+ return sig
+ else:
+ return provides
__signature__ = property(__signature__)
@@ -574,7 +645,6 @@
except AttributeError:
pass
else:
-
_gatherSpecs(cls, result)
self.__dict__['_v_spec'] = spec = InterfaceSpecification(*result)
@@ -836,6 +906,24 @@
return getattr(object, "__provides__", _empty)
+class metaclasshooker:
+
+ def __init__(self, metaclass):
+ self.metaclass = metaclass
+
+ def __call__(self, name, bases, dict):
+ metaclass = self.metaclass
+ if metaclass is None:
+ if bases:
+ metaclass = type(bases[0])
+ else:
+ metaclass = ClassType
+
+ cls = metaclass(name, bases, dict)
+ _setImplements(cls, dict['__implements__'])
+
+ return cls
+
def _implements(name, spec):
frame = sys._getframe(2)
locals = frame.f_locals
@@ -848,7 +936,11 @@
raise TypeError(name+" can be used only once in a class definition.")
locals["__implements__"] = spec
- locals["__providedBy__"] = _objectSpecificationDescriptor
+
+ metaclass = locals.get('__metaclass__')
+ if metaclass is None:
+ metaclass = frame.f_globals.get('__metaclass__')
+ locals["__metaclass__"] = metaclasshooker(metaclass)
def implements(*interfaces):
"""Declare interfaces implemented by instances of a class
@@ -1090,9 +1182,7 @@
def _getImplements(cls):
-
- try: flags = cls.__flags__
- except AttributeError: flags = heap
+ flags = getattr(cls, '__flags__', heap)
if flags & heap:
try:
@@ -1125,11 +1215,7 @@
return d.get(k)
def _setImplements(cls, v):
-
- try:
- flags = cls.__flags__
- except AttributeError:
- flags = heap
+ flags = getattr(cls, '__flags__', heap)
if flags & heap:
cls.__implements__ = v
@@ -1137,6 +1223,8 @@
else:
_implements_reg[cls] = v
+ v.setClass(cls)
+
def _flattenSpecs(specs, result):
"""Flatten a sequence of interfaces and interface specs to interfaces
@@ -1194,6 +1282,44 @@
if not stop:
for b in cls.__bases__:
_gatherSpecs(b, result)
+
+ return result
+
+def _gatherSpecs(cls, result):
+ implements = _getImplements(cls)
+ if implements is not None:
+ try:
+ stop = implements.only
+ except AttributeError:
+ # Must be an old-style interface spec
+ implements = OnlyImplementsSpecification(
+ _flattenSpecs([implements], []))
+ stop = 1
+ _setImplements(cls, implements)
+
+ if stop:
+ result.append(implements)
+ return result
+
+ cspec = implements._cspec
+ if cspec is not None:
+ # We have a cached spec.
+ # This makes out job much easier
+ result.append(cspec)
+ return result
+
+ # No cached cspec. Compute one if we're being called recursively:
+ if result:
+ implements.setClass(cls)
+ cspec = implements._cspec
+ # Now we have one
+ result.append(cspec)
+ return result
+
+ result.append(implements)
+
+ for b in cls.__bases__:
+ _gatherSpecs(b, result)
return result