[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