[Zope3-checkins] CVS: Zope3/src/zope/component - __init__.py:1.9 adapter.py:1.3 interfaces.py:1.4

Jim Fulton jim@zope.com
Wed, 21 May 2003 16:30:37 -0400


Update of /cvs-repository/Zope3/src/zope/component
In directory cvs.zope.org:/tmp/cvs-serv22750/src/zope/component

Modified Files:
	__init__.py adapter.py interfaces.py 
Log Message:
Changed the API for handling named adapters.  There is
now a separate cleaner api for getting named adapters.

Also added support for the PEP 246 __conform__ method.



=== Zope3/src/zope/component/__init__.py 1.8 => 1.9 ===
--- Zope3/src/zope/component/__init__.py:1.8	Sun May 18 14:06:44 2003
+++ Zope3/src/zope/component/__init__.py	Wed May 21 16:30:05 2003
@@ -16,6 +16,8 @@
 $Id$
 """
 
+import sys
+import warnings
 from zope.interface import moduleProvides
 from zope.component.interfaces import IComponentArchitecture
 from zope.component.exceptions import ComponentLookupError
@@ -66,12 +68,58 @@
 # Adapter service
 
 def getAdapter(object, interface, name='', context=None):
+    adapter = queryAdapter(object, interface, name=name, context=context)
+    if adapter is None:
+        raise ComponentLookupError(object, interface)
+    return adapter
+
+def queryAdapter(object, interface, default=None, name='', context=None):
+    if name:
+        warnings.warn("The name argument to queryAdapter is deprecated",
+                      DeprecationWarning, 2)
+        return queryNamedAdapter(object, interface, name, default, context)
+    
+    conform = getattr(object, '__conform__', None)
+    if conform is not None:
+        try:
+            adapter = conform(interface)
+        except TypeError:
+            # We got a TypeError. It might be an error raised by
+            # the __conform__ implementation, or *we* may have
+            # made the TypeError by calling an unbound method
+            # (object is a class).  In the later case, we behave
+            # as though there is no __conform__ method. We can
+            # detect this case by checking whether there is more
+            # than one traceback object in the traceback chain:
+            if sys.exc_info()[2].tb_next is not None:
+                # There is more than one entry in the chain, so
+                # reraise the error:
+                raise
+            # This clever trick is from Phillip Eby
+        else:
+            if adapter is not None:
+                return adapter
+
+    if interface.isImplementedBy(object):
+        return object
+
     if context is None:
         context = object
-    return getService(context, Adapters).getAdapter(
-        object, interface, name)
+    try:
+        adapters = getService(context, Adapters)
+    except ComponentLookupError:
+        # Oh blast, no adapter service. We're probably just running from a test
+        return default
 
-def queryAdapter(object, interface, default=None, name='', context=None):
+    return adapters.queryNamedAdapter(object, interface, name, default)
+
+def getNamedAdapter(object, interface, name, context=None):
+    adapter = queryNamedAdapter(object, interface, name, context=context)
+    if adapter is None:
+        raise ComponentLookupError(object, interface)
+    return adapter
+
+def queryNamedAdapter(object, interface, name, default=None, context=None):
     if context is None:
         context = object
     try:
@@ -80,8 +128,7 @@
         # Oh blast, no adapter service. We're probably just running from a test
         return default
 
-    return adapters.queryAdapter(
-        object, interface, default, name)
+    return adapters.queryNamedAdapter(object, interface, name, default)
 
 # Factory service
 
@@ -144,9 +191,3 @@
                       Resources).queryResource(
         wrapped_object, name, request, default)
 
-
-#def _clear():
-#    from Service import _clear;     _clear()
-#    from ViewService import _clear; _clear()
-#    from Resources import _clear; _clear()
-#    from SkinService import _clear; _clear()


=== Zope3/src/zope/component/adapter.py 1.2 => 1.3 ===
--- Zope3/src/zope/component/adapter.py:1.2	Wed Dec 25 09:13:31 2002
+++ Zope3/src/zope/component/adapter.py	Wed May 21 16:30:05 2003
@@ -14,45 +14,16 @@
 """adapter service
 """
 
+import sys
+from zope.interface import implements
 from zope.interface.adapter import AdapterRegistry
 from zope.component.exceptions import ComponentLookupError
-from zope.component.interfaces import IAdapterService
+from zope.component.interfaces import IGlobalAdapterService
+import warnings
 
-class IGlobalAdapterService(IAdapterService):
+class GlobalAdapterService(object):
 
-    def provideAdapter(forInterface, providedInterface, maker, name=''):
-        """Provide an adapter
-
-        An adapter provides an interface for objects that have another
-        interface.
-
-        Arguments:
-
-        forInterface -- The interface the adapter provides an interface for.
-
-        providedInterface -- The provided interface
-
-        maker -- a callable object that gets an adapter component for
-        a context component.
-        """
-    def getRegisteredMatching(for_interface=None, provide_interface=None,
-                              name=None):
-        """Return information about registered data
-
-        A four-tuple is returned containing:
-
-          - registered name,
-
-          - registered for interface
-
-          - registered provided interface, and
-
-          - registered data
-        """
-
-class GlobalAdapterService:
-
-    __implements__ = IGlobalAdapterService
+    implements(IGlobalAdapterService)
 
     def __init__(self):
         self.__adapters = {}
@@ -78,7 +49,15 @@
 
     def getAdapter(self, object, interface, name=''):
         """see IAdapterService interface"""
-        result = self.queryAdapter(object, interface, None, name)
+        result = self.queryAdapter(object, interface, name=name)
+        if result is None:
+            raise ComponentLookupError(object, interface)
+
+        return result
+
+    def getNamedAdapter(self, object, interface, name):
+        """see IAdapterService interface"""
+        result = self.queryNamedAdapter(object, interface, name)
         if result is None:
             raise ComponentLookupError(object, interface)
 
@@ -87,9 +66,39 @@
 
     def queryAdapter(self, object, interface, default=None, name=''):
         """see IAdapterService interface"""
-        if (not name) and interface.isImplementedBy(object):
+        if name:
+            warnings.warn("The name argument to queryAdapter is deprecated",
+                          DeprecationWarning, 2)
+            return self.queryNamedAdapter(object, interface, name, default)
+    
+        conform = getattr(object, '__conform__', None)
+        if conform is not None:
+            try:
+                adapter = conform(interface)
+            except TypeError:
+                # We got a TypeError. It might be an error raised by
+                # the __conform__ implementation, or *we* may have
+                # made the TypeError by calling an unbound method
+                # (object is a class).  In the later case, we behave
+                # as though there is no __conform__ method. We can
+                # detect this case by checking whether there is more
+                # than one traceback object in the traceback chain:
+                if sys.exc_info()[2].tb_next is not None:
+                    # There is more than one entry in the chain, so
+                    # reraise the error:
+                    raise
+                # This clever trick is from Phillip Eby
+            else:
+                if adapter is not None:
+                    return adapter
+
+        if interface.isImplementedBy(object):
             return object
 
+        return self.queryNamedAdapter(object, interface, name, default)
+
+    def queryNamedAdapter(self, object, interface, name, default=None):
+        """see IAdapterService interface"""
         registry = self.__adapters.get(name)
         if registry is None:
             return default
@@ -135,11 +144,13 @@
 adapterService = GlobalAdapterService()
 provideAdapter = adapterService.provideAdapter
 
-
-
 _clear = adapterService._clear
 
 # Register our cleanup with Testing.CleanUp to make writing unit tests simpler.
-from zope.testing.cleanup import addCleanUp
-addCleanUp(_clear)
-del addCleanUp
+try:
+    from zope.testing.cleanup import addCleanUp
+except ImportError:
+    pass
+else:
+    addCleanUp(_clear)
+    del addCleanUp


=== Zope3/src/zope/component/interfaces.py 1.3 => 1.4 ===
--- Zope3/src/zope/component/interfaces.py:1.3	Fri Jan 10 13:44:23 2003
+++ Zope3/src/zope/component/interfaces.py	Wed May 21 16:30:05 2003
@@ -60,23 +60,65 @@
 
     # Adapter service
 
-    def getAdapter(object, interface, name='', context=None):
-        """Get adapter to interface for object
+    def getAdapter(object, interface, context=None):
+        """Get an adapter to an interface for an object
 
         Returns the nearest adapter to the context that can adapt
         object to interface.  If context is not specified, attempts to
         use wrapping around object to specify a context.  If a
         matching adapter cannot be found, raises ComponentLookupError.
 
+        If the object has a __conform__ method, this method will be
+        called with the requested interface.  If the method returns a
+        non-None value, that value will be returned. Otherwise, if the
+        object already implements the interface, the object will be
+        returned. 
+
         """
 
-    def queryAdapter(object, interface, default=None, name='', context=None):
-        """Look for adapter to interface for object
+    def getNamedAdapter(object, interface, name, context=None):
+        """Get a named adapter to an interface for an object
+
+        Returns the nearest named adapter to the context that can adapt
+        object to interface.  If context is not specified, attempts to
+        use wrapping around object to specify a context.  If a
+        matching adapter cannot be found, raises ComponentLookupError.
+
+        The name consisting of an empty string is reserved for unnamed
+        adapters. The unnamed adapter methods will often call the
+        named adapter methods with an empty string for a name.
+
+        """
+
+    def queryAdapter(object, interface, default=None, context=None):
+        """Look for an adapter to an interface for an object
 
         Returns the nearest adapter to the context that can adapt
         object to interface.  If context is not specified, attempts to
         use wrapping around object to specify a context.  If a matching
-        adapter cannot be found, returns default."""
+        adapter cannot be found, returns the default.
+
+        If the object has a __conform__ method, this method will be
+        called with the requested interface.  If the method returns a
+        non-None value, that value will be returned. Otherwise, if the
+        object already implements the interface, the object will be
+        returned. 
+
+        """
+
+    def queryNamedAdapter(object, interface, name, default=None, context=None):
+        """Look for a named adapter to an interface for an object
+
+        Returns the nearest named adapter to the context that can adapt
+        object to interface.  If context is not specified, attempts to
+        use wrapping around object to specify a context.  If a matching
+        adapter cannot be found, returns the default.
+
+        The name consisting of an empty string is reserved for unnamed
+        adapters. The unnamed adapter methods will often call the
+        named adapter methods with an empty string for a name.
+
+        """
 
     # Factory service
 
@@ -268,23 +310,54 @@
 
 class IAdapterService(Interface):
 
-    def getAdapter(object, interface, name=''):
-        """Look up an adapter that provides an interface for an object
+    def getAdapter(object, interface):
+        """Get an adapter to an interface for an object
 
-        If name is empty and the object already implements the
-        interface, then the object will be returned.
+        If the object has a __conform__ method, this method will be
+        called with the requested interface.  If the method returns a
+        non-None value, that value will be returned. Otherwise, if the
+        object already implements the interface, the object will be
+        returned. 
+
+        If a matching adapter cannot be found, raises
+        ComponentLookupError.
 
-        A ComponentLookupError will be
-        raised if the component can't be found.
         """
 
-    def queryAdapter(object, interface, default=None, name=''):
-        """Look up an adapter that provides an interface for an object
+    def getNamedAdapter(object, interface, name):
+        """Get a named adapter to an interface for an object
 
-        If name is empty and the object already implements the
-        interface, then the object will be returned.
+        If a matching adapter cannot be found, raises
+        ComponentLookupError.
+
+        The name consisting of an empty string is reserved for unnamed
+        adapters. The unnamed adapter methods will often call the
+        named adapter methods with an empty string for a name.
+
+        """
+
+    def queryAdapter(object, interface, default=None):
+        """Look for an adapter to an interface for an object
+
+        If the object has a __conform__ method, this method will be
+        called with the requested interface.  If the method returns a
+        non-None value, that value will be returned. Otherwise, if the
+        object already implements the interface, the object will be
+        returned. 
+
+        If a matching adapter cannot be found, returns the default.
+
+        """
+
+    def queryNamedAdapter(object, interface, name, default=None):
+        """Look for a named adapter to an interface for an object
+
+        If a matching adapter cannot be found, returns the default.
+
+        The name consisting of an empty string is reserved for unnamed
+        adapters. The unnamed adapter methods will often call the
+        named adapter methods with an empty string for a name.
 
-        The default will be returned if the component can't be found.
         """
 
     # XXX need to add name support
@@ -306,6 +379,38 @@
         - the object registered specifically for the required and
           provided interfaces.
 
+        """
+
+class IGlobalAdapterService(IAdapterService):
+
+    def provideAdapter(forInterface, providedInterface, maker, name=''):
+        """Provide an adapter
+
+        An adapter provides an interface for objects that have another
+        interface.
+
+        Arguments:
+
+        forInterface -- The interface the adapter provides an interface for.
+
+        providedInterface -- The provided interface
+
+        maker -- a callable object that gets an adapter component for
+        a context component.
+        """
+    def getRegisteredMatching(for_interface=None, provide_interface=None,
+                              name=None):
+        """Return information about registered data
+
+        A four-tuple is returned containing:
+
+          - registered name,
+
+          - registered for interface
+
+          - registered provided interface, and
+
+          - registered data
         """
 
 class IPresentation(Interface):