[Checkins] SVN: zope.component/branches/tseaver-queryAdapterFactory/src/zope/component/ Add 'queryAdapterFactory' and 'queryMultiAdapterFactory' APIs.

Tres Seaver tseaver at palladion.com
Mon Mar 21 15:10:37 EDT 2011


Log message for revision 121062:
  Add 'queryAdapterFactory' and 'queryMultiAdapterFactory' APIs.
  
  These functions allow looking up the uncalled factory for an adapter.
  

Changed:
  U   zope.component/branches/tseaver-queryAdapterFactory/src/zope/component/README.txt
  U   zope.component/branches/tseaver-queryAdapterFactory/src/zope/component/__init__.py
  U   zope.component/branches/tseaver-queryAdapterFactory/src/zope/component/_api.py
  U   zope.component/branches/tseaver-queryAdapterFactory/src/zope/component/interfaces.py
  U   zope.component/branches/tseaver-queryAdapterFactory/src/zope/component/registry.py
  U   zope.component/branches/tseaver-queryAdapterFactory/src/zope/component/tests.py

-=-
Modified: zope.component/branches/tseaver-queryAdapterFactory/src/zope/component/README.txt
===================================================================
--- zope.component/branches/tseaver-queryAdapterFactory/src/zope/component/README.txt	2011-03-21 19:10:36 UTC (rev 121061)
+++ zope.component/branches/tseaver-queryAdapterFactory/src/zope/component/README.txt	2011-03-21 19:10:36 UTC (rev 121062)
@@ -166,6 +166,21 @@
     ...
     ComponentLookupError: (...Person...>, <...IGreeter>, 'frank')
 
+We can also query for the *factory* for the adapter (e.g., if we want to
+call it later ourselves, or supply an unregistered default):
+
+    >>> component.queryAdapterFactory(Person("Sally"), IGreeter
+    ...                              ) is PersonGreeter
+    True
+    >>> component.queryAdapterFactory(Person("Sally"), IGreeter, 'bob'
+    ...                                     ) is BobPersonGreeter
+    True
+    >>> def _greeterDefault(*args):
+    ...     assert 0, "Don't call the factory!"
+    >>> component.queryAdapterFactory(Person("Sally"), IGreeter,
+    ...          'not_registered', default=_greeterDefault) is _greeterDefault
+    True
+
 Adapters can adapt multiple objects:
 
     >>> class TwoPersonGreeter:
@@ -197,6 +212,19 @@
     Hello Sally
     my name is Bob
 
+We can also query for the *factory* for the multi-adapter (e.g., if we want to
+call it later ourselves, or supply an unregistered default):
+
+    >>> component.queryMultiAdapterFactory((Person("Sally"), Person("Bob")),
+    ...                                  IGreeter) is TwoPersonGreeter
+    True
+    >>> def _multiGreeterDefault(*args):
+    ...     assert 0, "Don't call the factory!"
+    >>> component.queryMultiAdapterFactory((Person("Sally"), Person("Bob")),
+    ...           IGreeter, 'not_registered', default=_greeterDefault
+    ...           ) is _greeterDefault
+    True
+
 Adapters need not be classes.  Any callable will do.  We use the
 adapter decorator (in the Python 2.4 decorator sense) to declare that
 a callable object adapts some interfaces (or classes):

Modified: zope.component/branches/tseaver-queryAdapterFactory/src/zope/component/__init__.py
===================================================================
--- zope.component/branches/tseaver-queryAdapterFactory/src/zope/component/__init__.py	2011-03-21 19:10:36 UTC (rev 121061)
+++ zope.component/branches/tseaver-queryAdapterFactory/src/zope/component/__init__.py	2011-03-21 19:10:36 UTC (rev 121062)
@@ -46,8 +46,10 @@
 from zope.component._api import getNextUtility
 from zope.component._api import handle
 from zope.component._api import queryAdapter
+from zope.component._api import queryAdapterFactory
 from zope.component._api import queryAdapterInContext
 from zope.component._api import queryMultiAdapter
+from zope.component._api import queryMultiAdapterFactory
 from zope.component._api import queryUtility
 from zope.component._api import queryNextUtility
 from zope.component._api import subscribers

Modified: zope.component/branches/tseaver-queryAdapterFactory/src/zope/component/_api.py
===================================================================
--- zope.component/branches/tseaver-queryAdapterFactory/src/zope/component/_api.py	2011-03-21 19:10:36 UTC (rev 121061)
+++ zope.component/branches/tseaver-queryAdapterFactory/src/zope/component/_api.py	2011-03-21 19:10:36 UTC (rev 121062)
@@ -95,6 +95,18 @@
     return getSiteManager(context).queryAdapter(object, interface, name,
                                                 default)
 
+def queryAdapterFactory(object, interface=Interface, name=u'', default=None,
+                 context=None):
+    if context is None: # inlined from adapter_hook
+        try:
+            sitemanager = getSiteManager()
+        except ComponentLookupError:
+            # Oh blast, no site manager. This should *never* happen!
+            return None
+    else:
+        sitemanager = getSiteManager(context)
+    return sitemanager.queryAdapterFactory(object, interface, name, default)
+
 def getMultiAdapter(objects, interface=Interface, name=u'', context=None):
     adapter = queryMultiAdapter(objects, interface, name, context=context)
     if adapter is None:
@@ -111,6 +123,17 @@
 
     return sitemanager.queryMultiAdapter(objects, interface, name, default)
 
+def queryMultiAdapterFactory(objects, interface=Interface, name=u'',
+                             default=None, context=None):
+    try:
+        sitemanager = getSiteManager(context)
+    except ComponentLookupError:
+        # Oh blast, no site manager. This should *never* happen!
+        return default
+
+    return sitemanager.queryMultiAdapterFactory(objects, interface, name,
+                                                default)
+
 def getAdapters(objects, provided, context=None):
     try:
         sitemanager = getSiteManager(context)

Modified: zope.component/branches/tseaver-queryAdapterFactory/src/zope/component/interfaces.py
===================================================================
--- zope.component/branches/tseaver-queryAdapterFactory/src/zope/component/interfaces.py	2011-03-21 19:10:36 UTC (rev 121061)
+++ zope.component/branches/tseaver-queryAdapterFactory/src/zope/component/interfaces.py	2011-03-21 19:10:36 UTC (rev 121062)
@@ -188,6 +188,21 @@
         and this adapter's 'Adapters' service is used.
         """
 
+    def queryAdapterFactory(object, interface=Interface, name=u'',
+                     default=None, context=None):
+        """Look for a factory named adapter to an interface for an object
+
+        Returns a callable which, if called with 'object', returns an adapter
+        that can adapt object to interface.  If a matching
+        factory cannot be found, returns 'default'.
+
+        If context is None, an application-defined policy is used to choose
+        an appropriate service manager from which to get an 'Adapters' service.
+
+        If 'context' is not None, context is adapted to IServiceService,
+        and this adapter's 'Adapters' service is used.
+        """
+
     def queryAdapterInContext(object, interface, context, default=None):
         """Look for a special adapter to an interface for an object
 
@@ -230,6 +245,27 @@
         named adapter methods with an empty string for a name.
         """
 
+    def queryMultiAdapterFactory(objects,
+                                 interface=Interface, name=u'',
+                                 default=None,
+                                 context=None):
+        """Look for a multi-adapter to an interface for objects
+
+        Returns a factory, which if called with 'objects' returns a 
+        multi-adapter that can adapt objects to interface.  If a
+        matching factory cannot be found, returns 'default'.
+
+        If context is None, an application-defined policy is used to choose
+        an appropriate service manager from which to get an 'Adapters' service.
+
+        If 'context' is not None, context is adapted to IServiceService,
+        and this adapter's 'Adapters' service is used.
+
+        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 getAdapters(objects, provided, context=None):
         """Look for all matching adapters to a provided interface for objects
 
@@ -324,6 +360,12 @@
         If a matching adapter cannot be found, returns the default.
         """
 
+    def queryAdapterFactory(object, interface, name=u'', default=None):
+        """Look for a factory named adapter to an interface for an object
+
+        If a matching factory cannot be found, returns 'default'.
+        """
+
     def getAdapter(object, interface, name=u''):
         """Look for a named adapter to an interface for an object
 
@@ -337,6 +379,12 @@
         If a matching adapter cannot be found, returns the default.
         """
 
+    def queryMultiAdapterFactory(objects, interface, name=u'', default=None):
+        """Look for a factory for multi-adapter to an interface.
+
+        If a matching adapter cannot be found, returns 'default'.
+        """
+
     def getMultiAdapter(objects, interface, name=u''):
         """Look for a multi-adapter to an interface for multiple objects
 

Modified: zope.component/branches/tseaver-queryAdapterFactory/src/zope/component/registry.py
===================================================================
--- zope.component/branches/tseaver-queryAdapterFactory/src/zope/component/registry.py	2011-03-21 19:10:36 UTC (rev 121061)
+++ zope.component/branches/tseaver-queryAdapterFactory/src/zope/component/registry.py	2011-03-21 19:10:36 UTC (rev 121062)
@@ -227,6 +227,10 @@
     def queryAdapter(self, object, interface, name=u'', default=None):
         return self.adapters.queryAdapter(object, interface, name, default)
 
+    def queryAdapterFactory(self, object, interface, name=u'', default=None):
+        required = providedBy(object)
+        return self.adapters.lookup1(required, interface, name, default)
+
     def getAdapter(self, object, interface, name=u''):
         adapter = self.adapters.queryAdapter(object, interface, name)
         if adapter is None:
@@ -237,6 +241,11 @@
         return self.adapters.queryMultiAdapter(
             objects, interface, name, default)
 
+    def queryMultiAdapterFactory(self, objects, interface, name=u'',
+                                 default=None):
+        required = map(providedBy, objects)
+        return self.adapters.lookup(required, interface,  name, default)
+
     def getMultiAdapter(self, objects, interface, name=u''):
         adapter = self.adapters.queryMultiAdapter(objects, interface, name)
         if adapter is None:

Modified: zope.component/branches/tseaver-queryAdapterFactory/src/zope/component/tests.py
===================================================================
--- zope.component/branches/tseaver-queryAdapterFactory/src/zope/component/tests.py	2011-03-21 19:10:36 UTC (rev 121061)
+++ zope.component/branches/tseaver-queryAdapterFactory/src/zope/component/tests.py	2011-03-21 19:10:36 UTC (rev 121062)
@@ -1272,6 +1272,49 @@
    </configure>"""
 
 
+
+class ComponentsTests(unittest.TestCase):
+
+    def _getTargetClass(self):
+        from zope.component.registry import Components
+        return Components
+
+    def _makeOne(self, name='', bases=()):
+        return self._getTargetClass()(name, bases)
+
+    def test_queryAdapterFactory(self):
+        from zope.interface import Interface
+        class IAdapted(Interface):
+            pass
+        class Context(object):
+            pass
+        context = Context()
+        def _factory(*args):
+            assert 0, "Don't call the factory, we'll call later!"
+        registry = self._makeOne()
+        factory  = registry.queryAdapterFactory(context, IAdapted,
+                                                default=_factory)
+        self.assert_(factory is _factory)
+
+    def test_queryMultiAdapterFactory(self):
+        from zope.interface import Interface
+        class IAdapted(Interface):
+            pass
+        class Context1(object):
+            pass
+        context1 = Context1()
+        class Context2(object):
+            pass
+        context2 = Context2()
+        def _factory(*args):
+            assert 0, "Don't call the factory, we'll call later!"
+        registry = self._makeOne()
+        factory  = registry.queryMultiAdapterFactory(
+                                (context1, context2), IAdapted,
+                                default=_factory)
+        self.assert_(factory is _factory)
+
+
 class ResourceViewTests(PlacelessSetup, unittest.TestCase):
 
     def setUp(self):
@@ -1738,6 +1781,7 @@
         zcml_conditional,
         hooks_conditional,
         unittest.makeSuite(StandaloneTests),
+        unittest.makeSuite(ComponentsTests),
         unittest.makeSuite(ResourceViewTests),
         ))
 



More information about the checkins mailing list