[Zope3-checkins] SVN: Zope3/branches/Zope-3.1/src/zope/interface/
Make sure that the implementedBy(interface,
obj) call always succeeds.
Stephan Richter
srichter at cosmos.phy.tufts.edu
Wed Nov 16 17:48:55 EST 2005
Log message for revision 40185:
Make sure that the implementedBy(interface, obj) call always succeeds.
An attribute error was raised, if obj did not have an attribute called
__name__.
?\194?\160
This fix addresses issue 470, but using a different solution than
suggested.
Changed:
U Zope3/branches/Zope-3.1/src/zope/interface/declarations.py
U Zope3/branches/Zope-3.1/src/zope/interface/interface.py
-=-
Modified: Zope3/branches/Zope-3.1/src/zope/interface/declarations.py
===================================================================
--- Zope3/branches/Zope-3.1/src/zope/interface/declarations.py 2005-11-16 22:42:26 UTC (rev 40184)
+++ Zope3/branches/Zope-3.1/src/zope/interface/declarations.py 2005-11-16 22:48:54 UTC (rev 40185)
@@ -22,12 +22,13 @@
- ProvidesDeclarations are used to express interfaces directly
provided by objects.
-
+
$Id$
"""
__docformat__ = 'restructuredtext'
import sys
+import types
import weakref
from zope.interface.interface import InterfaceClass, Specification
from ro import mergeOrderings, ro
@@ -35,7 +36,7 @@
from types import ClassType
from zope.interface.advice import addClassAdvisor
-# Registry of class-implementation specifications
+# Registry of class-implementation specifications
BuiltinImplementationSpecifications = {}
class Declaration(Specification):
@@ -183,7 +184,7 @@
if i.extends(j, 0)]
]
)
-
+
def __add__(self, other):
"""Add two specifications or a specification and an interface
@@ -266,9 +267,9 @@
def __repr__(self):
return '<implementedBy %s>' % (self.__name__)
-
-
+
+
def implementedByFallback(cls):
"""Return the interfaces implemented for a class' instances
@@ -291,14 +292,26 @@
... implements(I3)
>>> [i.getName() for i in implementedBy(C2)]
['I3', 'I2']
+
+ Really, any object should be able to receive a successful answer, even
+ an instance:
+
+ >>> class Callable(object):
+ ... def __call__(self):
+ ... return self
+
+ >>> implementedBy(Callable())
+ <implementedBy zope.interface.declarations.?>
+
+ Note that the name of the spec ends with a '?', because the `Callable`
+ instance does not have a `__name__` attribute.
"""
-
# This also manages storage of implementation specifications
try:
spec = cls.__dict__.get('__implemented__')
except AttributeError:
-
+
# we can't get the class dict. This is probably due to a
# security proxy. If this is the case, then probably no
# descriptor was installed for the class.
@@ -316,7 +329,7 @@
if spec is not None:
return spec
return _empty
-
+
if spec.__class__ == Implements:
# we defaulted to _empty or there was a spec. Good enough.
# Return it.
@@ -326,7 +339,7 @@
# Hm, there's an __implemented__, but it's not a spec. Must be
# an old-style declaration. Just compute a spec for it
return Declaration(*_normalizeargs((spec, )))
-
+
if isinstance(spec, Implements):
return spec
@@ -354,7 +367,7 @@
spec.inherit = cls
spec.__name__ = (getattr(cls, '__module__', '?') or '?') + \
- '.' + cls.__name__
+ '.' + (getattr(cls, '__name__', '?') or '?')
try:
cls.__implemented__ = spec
@@ -369,7 +382,7 @@
cls,
getattr(cls, '__class__', type(cls)),
)
-
+
except TypeError:
if not isinstance(cls, type):
raise TypeError("ImplementedBy called for non-type", cls)
@@ -479,7 +492,7 @@
if b not in seen:
seen[b] = 1
bases.append(b)
-
+
spec.__bases__ = tuple(bases)
def _implements_advice(cls):
@@ -671,7 +684,7 @@
>>> from zope.interface import Interface
>>> class IFooFactory(Interface): pass
...
-
+
>>> class C(object):
... pass
@@ -717,7 +730,7 @@
... gc.collect()
)
-
+
>>> collect()
>>> before = len(InstanceDeclarations)
@@ -727,7 +740,7 @@
>>> from zope.interface import Interface
>>> class I(Interface):
... pass
-
+
>>> c1 = C()
>>> c2 = C()
@@ -751,9 +764,9 @@
>>> collect()
>>> len(InstanceDeclarations) == before
1
-
+
"""
-
+
spec = InstanceDeclarations.get(interfaces)
if spec is None:
spec = ProvidesClass(*interfaces)
@@ -868,8 +881,8 @@
object.__provides__ = ClassProvides(object, cls, *interfaces)
else:
object.__provides__ = Provides(cls, *interfaces)
-
-
+
+
def alsoProvides(object, *interfaces):
"""Declare interfaces declared directly for an object
@@ -879,7 +892,7 @@
The interfaces given (including the interfaces in the
specifications) are added to the interfaces previously
declared for the object.
-
+
Consider the following example::
>>> from zope.interface import Interface
@@ -917,7 +930,7 @@
1
>>> int(IC in providedBy(ob))
1
-
+
>>> alsoProvides(ob, I2)
>>> int(I1 in providedBy(ob))
1
@@ -931,7 +944,7 @@
1
>>> int(IC in providedBy(ob))
1
-
+
The object, ``ob`` provides ``I1``, ``I2``, and whatever interfaces
instances have been declared for instances of ``C``. Notice that the
alsoProvides just extends the provided interfaces.
@@ -943,7 +956,7 @@
def __get__(self, inst, cls):
if cls is self._cls:
# We only work if called on the class we were defined for
-
+
if inst is None:
# We were accessed through a class, so we are the class'
# provides spec. Just return this object as is:
@@ -987,7 +1000,7 @@
>>> [i.getName() for i in C().__provides__]
['IFoo']
-
+
"""
def __init__(self, cls, metacls, *interfaces):
@@ -1250,7 +1263,7 @@
provides = getattr(ob, '__provides__', None)
if provides is not None:
return provides
-
+
try:
cls = ob.__class__
except AttributeError:
@@ -1270,8 +1283,8 @@
except AttributeError:
# Not set yet. Fall back to lower-level thing that computes it
return getObjectSpecification(ob)
-
+
try:
# We might have gotten a descriptor from an instance of a
# class (like an ExtensionClass) that doesn't support
@@ -1339,7 +1352,7 @@
# Get an ObjectSpecification bound to either an instance or a class,
# depending on how we were accessed.
-
+
if inst is None:
return getObjectSpecification(cls)
@@ -1370,7 +1383,7 @@
else:
for v in sequence:
_normalizeargs(v, output)
-
+
return output
_empty = Declaration()
@@ -1385,4 +1398,4 @@
from _zope_interface_coptimizations import ObjectSpecificationDescriptor
objectSpecificationDescriptor = ObjectSpecificationDescriptor()
-
+
Modified: Zope3/branches/Zope-3.1/src/zope/interface/interface.py
===================================================================
--- Zope3/branches/Zope-3.1/src/zope/interface/interface.py 2005-11-16 22:42:26 UTC (rev 40184)
+++ Zope3/branches/Zope-3.1/src/zope/interface/interface.py 2005-11-16 22:48:54 UTC (rev 40185)
@@ -110,7 +110,7 @@
>>> directlyProvides(C, I1)
>>> I1.providedBy(C)
True
-
+
"""
spec = providedBy(ob)
return self in spec._implied
@@ -199,7 +199,7 @@
>>> I3.extends(I1)
0
-
+
"""
# Copy some base class methods for speed
@@ -241,16 +241,16 @@
# Register ourselves as a dependent of our old bases
for b in self.__bases__:
b.unsubscribe(self)
-
+
# Register ourselves as a dependent of our bases
self.__dict__['__bases__'] = bases
for b in bases:
b.subscribe(self)
-
+
self.changed()
__bases__ = property(
-
+
lambda self: self.__dict__.get('__bases__', ()),
__setBases,
)
@@ -309,8 +309,8 @@
if interface not in seen:
seen[interface] = 1
yield interface
-
+
def extends(self, interface, strict=True):
"""Does the specification extend the given interface?
@@ -377,7 +377,7 @@
if attr is not None:
attrs[name] = attr
break
-
+
if attr is None:
return default
else:
@@ -469,7 +469,7 @@
>>> from zope.interface import Interface
>>> class I1(Interface): pass
...
- >>>
+ >>>
>>> i = I1.interfaces()
>>> i.next().getName()
'I1'
@@ -611,7 +611,7 @@
# provide some consistencey with the PEP 246 adapt method.
marker = object()
-
+
def __call__(self, obj, alternate=marker):
"""Adapt an object to the interface
@@ -714,7 +714,7 @@
This method is normally not called directly. It is called by
the PEP 246 adapt framework and by the interface __call__
- operator.
+ operator.
The adapt method is responsible for adapting an object to
the reciever.
More information about the Zope3-Checkins
mailing list