[Zope3-checkins] CVS: Zope3/src/zope/interface - __init__.py:1.7 declarations.py:1.14
Jim Fulton
jim@zope.com
Wed, 4 Jun 2003 18:25:30 -0400
Update of /cvs-repository/Zope3/src/zope/interface
In directory cvs.zope.org:/tmp/cvs-serv26183/src/zope/interface
Modified Files:
__init__.py declarations.py
Log Message:
Made interface specifications picklable. This is necessary to deal
with interface assertions on instances and will be needed for
interface assertions on persistent classes.
=== Zope3/src/zope/interface/__init__.py 1.6 => 1.7 ===
--- Zope3/src/zope/interface/__init__.py:1.6 Mon Jun 2 07:07:19 2003
+++ Zope3/src/zope/interface/__init__.py Wed Jun 4 18:24:59 2003
@@ -88,7 +88,11 @@
from zope.interface.declarations import directlyProvidedBy, directlyProvides
from zope.interface.declarations import implements, implementsOnly
from zope.interface.declarations import classProvides, moduleProvides
-from zope.interface.declarations import InterfaceSpecification
+from zope.interface.declarations import InterfaceSpecification, Spec
+
+# The following are to make spec pickles cleaner
+from zope.interface.declarations import Implements, Only, Provides
+
from zope.interface.interfaces import IInterfaceDeclaration
moduleProvides(IInterfaceDeclaration)
=== Zope3/src/zope/interface/declarations.py 1.13 => 1.14 ===
--- Zope3/src/zope/interface/declarations.py:1.13 Tue Jun 3 15:52:39 2003
+++ Zope3/src/zope/interface/declarations.py Wed Jun 4 18:24:59 2003
@@ -142,7 +142,7 @@
# This function is needed by _zope_interface_ospec and, so, must be
# defined before _zope_interface_ospec is imported.
def oldSpecSig(cls, implements):
- implements = OnlyImplementsSpecification(implements)
+ implements = ImplementsOnlySpecification(implements)
_setImplements(cls, implements)
return implements.__signature__
@@ -421,7 +421,7 @@
from _zope_interface_ospec import getObjectSpecification, providedBy
from _zope_interface_ospec import ObjectSpecificationDescriptor
-class InterfaceSpecification(InterfaceSpecificationBase):
+def InterfaceSpecification(*interfaces):
"""Create an interface specification
The arguments are one or more interfaces or interface
@@ -430,19 +430,33 @@
A new interface specification (IInterfaceSpecification) with
the given interfaces is returned.
"""
+ return Spec(*_flattenSpecs(interfaces, []))
+
+
+_spec_cache = {}
+
+class Spec(InterfaceSpecificationBase):
only = False
+ # We don't want to pickle these
+ def __reduce__(self):
+ raise TypeError, "can't pickle InterfaceSpecification objects"
+
def __init__(self, *interfaces):
- self.interfaces = tuple(_flattenSpecs(interfaces, []))
- set = {}
- iro = mergeOrderings(
- [iface.__iro__ for iface in self.interfaces],
- set)
- self.__iro__ = iro
- self.set = set
+ self.interfaces = interfaces
+
+ cached = _spec_cache.get(interfaces)
+ if not cached:
+ set = {}
+ iro = mergeOrderings(
+ [iface.__iro__ for iface in self.interfaces],
+ set)
+ sig = '\t'.join([iface.__identifier__ for iface in iro])
+ cached = iro, set, sig
+ _spec_cache[interfaces] = cached
- self._computeSignature(iro)
+ self.__iro__, self.set, self.__signature__ = cached
def __nonzero__(self):
"""Test whether there are any interfaces in a specification.
@@ -459,26 +473,6 @@
"""
return bool(self.interfaces)
- def _computeSignature(self, iro):
- """Compute a specification signature
-
- For example::
-
- >>> from zope.interface import Interface
- >>> class I1(Interface): pass
- ...
- >>> class I2(I1): pass
- ...
- >>> spec = InterfaceSpecification(I2)
- >>> int(spec.__signature__ == "%s\\t%s\\t%s" % (
- ... I2.__identifier__, I1.__identifier__,
- ... Interface.__identifier__))
- 1
-
- """
- self.__signature__ = '\t'.join([iface.__identifier__ for iface in iro])
-
-
def __contains__(self, interface):
"""Test whether an interface is in the specification
@@ -643,7 +637,7 @@
"""
if other is None:
other = _empty
- return self.__class__(self, other)
+ return self.__class__(*_flattenSpecs((self, other), []))
__radd__ = __add__
@@ -683,9 +677,9 @@
"""
if other is None:
- other = _empty
+ other = ()
else:
- other = InterfaceSpecification(other)
+ other = _flattenSpecs((other,), [])
ifaces = []
@@ -694,12 +688,27 @@
for oface in other:
if oface in iface.__iro__:
break
- else:
- ifaces.append(iface)
+ else:
+ ifaces.append(iface)
return self.__class__(*ifaces)
+class PicklableSpec(Spec):
+ """Mix-in that adds picklability
+
+ This is done using a mix-in to prevent regular interface specs
+ from being pickled.
+
+ """
+
+ __safe_for_unpickling__ = True
+
+ def __reduce__(self):
+ return self.__class__, self.interfaces
+
+
+
def _flattenSpecs(specs, result):
"""Flatten a sequence of interfaces and interface specs to interfaces
@@ -734,11 +743,16 @@
_empty = InterfaceSpecification()
-class ImplementsSpecification(InterfaceSpecification):
+def ImplementsSpecification(*interfaces):
+ return Implements(*_flattenSpecs(interfaces, []))
+
+class Implements(PicklableSpec):
+
+ __module__ = 'zope.interface'
_cspec = None
def setClass(self, cls):
- self._cspec = ImplementsSpecification(_gatherSpecs(cls, []))
+ self._cspec = Spec(*_flattenSpecs(_gatherSpecs(cls, []), []))
self.__signature__ = self._cspec.__signature__
def __get__(self, inst, cls):
@@ -774,16 +788,26 @@
return InterfaceSpecification(_gatherSpecs(cls, []))
-class OnlyImplementsSpecification(ImplementsSpecification):
+def ImplementsOnlySpecification(*interfaces):
+ return Only(*_flattenSpecs(interfaces, []))
+
+class Only(Implements):
+
+ __module__ = 'zope.interface'
only = True
def __init__(self, *interfaces):
- ImplementsSpecification.__init__(self, *interfaces)
+ Spec.__init__(self, *interfaces)
self.__signature__ = "only(%s)" % self.__signature__
-class ProvidesSpecification(InterfaceSpecification):
+def ProvidesSpecification(*interfaces):
+ return Provides(*_flattenSpecs(interfaces, []))
+
+class Provides(PicklableSpec):
+
+ __module__ = 'zope.interface'
def __get__(self, inst, cls):
"""Make sure that a class __provides__ doesn't leak to an instance
@@ -849,9 +873,9 @@
whatever interfaces instances of ``A`` and ``B`` implement.
"""
- spec = OnlyImplementsSpecification(*interfaces)
+ spec = ImplementsOnlySpecification(*interfaces)
spec.only = True
- _setImplements(cls, OnlyImplementsSpecification(*interfaces))
+ _setImplements(cls, ImplementsOnlySpecification(*interfaces))
def directlyProvides(object, *interfaces):
"""Declare interfaces declared directly for an object
@@ -1117,7 +1141,7 @@
instances of ``A`` and ``B`` implement.
"""
- spec = ImplementsSpecification(interfaces)
+ spec = ImplementsOnlySpecification(interfaces)
spec.only = True
_implements("implements", spec)
@@ -1263,7 +1287,7 @@
implements = getattr(cls, '__implements__', None)
if implements is not None:
- implements = OnlyImplementsSpecification(implements)
+ implements = ImplementsOnlySpecification(implements)
return implements
@@ -1347,7 +1371,7 @@
stop = implements.only
except AttributeError:
# Must be an old-style interface spec
- implements = OnlyImplementsSpecification(
+ implements = ImplementsOnlySpecification(
_flattenSpecs([implements], []))
stop = 1
_setImplements(cls, implements)
@@ -1369,7 +1393,7 @@
stop = implements.only
except AttributeError:
# Must be an old-style interface spec
- implements = OnlyImplementsSpecification(
+ implements = ImplementsOnlySpecification(
_flattenSpecs([implements], []))
stop = 1
_setImplements(cls, implements)
@@ -1385,7 +1409,8 @@
result.append(cspec)
return result
- # No cached cspec. Compute one if we're being called recursively:
+ # No cached cspec. Compute one if we're being called recursively.
+ # We know we're being called recursively is result is not empty!
if result:
implements.setClass(cls)
cspec = implements._cspec
@@ -1399,7 +1424,6 @@
_gatherSpecs(b, result)
return result
-
# DocTest:
if __name__ == "__main__":