[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