[Checkins] SVN: zope.component/trunk/ Add getNextUtility/queryNextUtility functions that used to be in zope.site earlier (and in zope.app.component even more earlier).
Dan Korostelev
nadako at gmail.com
Wed Mar 11 19:38:56 EDT 2009
Log message for revision 97938:
Add getNextUtility/queryNextUtility functions that used to be in zope.site earlier (and in zope.app.component even more earlier).
Changed:
U zope.component/trunk/CHANGES.txt
U zope.component/trunk/src/zope/component/__init__.py
U zope.component/trunk/src/zope/component/_api.py
U zope.component/trunk/src/zope/component/interfaces.py
U zope.component/trunk/src/zope/component/tests.py
-=-
Modified: zope.component/trunk/CHANGES.txt
===================================================================
--- zope.component/trunk/CHANGES.txt 2009-03-11 22:44:45 UTC (rev 97937)
+++ zope.component/trunk/CHANGES.txt 2009-03-11 23:38:56 UTC (rev 97938)
@@ -21,6 +21,9 @@
If you used IViewFactory in context of zope.app.form, there's now
IWidgetFactory in the zope.app.form.interfaces instead.
+- Add getNextUtility/queryNextUtility functions that used to be in zope.site
+ earlier (and in zope.app.component even more earlier).
+
- Added a pure-Python 'hookable' implementation, for use when
'zope.hookable' is not present.
Modified: zope.component/trunk/src/zope/component/__init__.py
===================================================================
--- zope.component/trunk/src/zope/component/__init__.py 2009-03-11 22:44:45 UTC (rev 97937)
+++ zope.component/trunk/src/zope/component/__init__.py 2009-03-11 23:38:56 UTC (rev 97938)
@@ -45,11 +45,13 @@
from zope.component._api import getSiteManager
from zope.component._api import getUtilitiesFor
from zope.component._api import getUtility
+from zope.component._api import getNextUtility
from zope.component._api import handle
from zope.component._api import queryAdapter
from zope.component._api import queryAdapterInContext
from zope.component._api import queryMultiAdapter
from zope.component._api import queryUtility
+from zope.component._api import queryNextUtility
from zope.component._api import subscribers
from zope.component._declaration import adaptedBy
Modified: zope.component/trunk/src/zope/component/_api.py
===================================================================
--- zope.component/trunk/src/zope/component/_api.py 2009-03-11 22:44:45 UTC (rev 97937)
+++ zope.component/trunk/src/zope/component/_api.py 2009-03-11 23:38:56 UTC (rev 97938)
@@ -181,6 +181,37 @@
return getSiteManager(context).getAllUtilitiesRegisteredFor(interface)
+_marker = object()
+
+def queryNextUtility(context, interface, name='', default=None):
+ """Query for the next available utility.
+
+ Find the next available utility providing `interface` and having the
+ specified name. If no utility was found, return the specified `default`
+ value.
+ """
+ sm = getSiteManager(context)
+ bases = sm.__bases__
+ for base in bases:
+ util = base.queryUtility(interface, name, _marker)
+ if util is not _marker:
+ return util
+ return default
+
+
+def getNextUtility(context, interface, name=''):
+ """Get the next available utility.
+
+ If no utility was found, a `ComponentLookupError` is raised.
+ """
+ util = queryNextUtility(context, interface, name, _marker)
+ if util is _marker:
+ raise zope.component.interfaces.ComponentLookupError(
+ "No more utilities for %s, '%s' have been found." % (
+ interface, name))
+ return util
+
+
# Factories
def createObject(__factory_name, *args, **kwargs):
Modified: zope.component/trunk/src/zope/component/interfaces.py
===================================================================
--- zope.component/trunk/src/zope/component/interfaces.py 2009-03-11 22:44:45 UTC (rev 97937)
+++ zope.component/trunk/src/zope/component/interfaces.py 2009-03-11 23:38:56 UTC (rev 97938)
@@ -89,6 +89,20 @@
the specified interface. If one is not found, returns default.
"""
+ def queryNextUtility(context, interface, name='', default=None):
+ """Query for the next available utility.
+
+ Find the next available utility providing `interface` and having the
+ specified name. If no utility was found, return the specified `default`
+ value.
+ """
+
+ def getNextUtility(context, interface, name=''):
+ """Get the next available utility.
+
+ If no utility was found, a `ComponentLookupError` is raised.
+ """
+
def getUtilitiesFor(interface, context=None):
"""Return the utilities that provide an interface
Modified: zope.component/trunk/src/zope/component/tests.py
===================================================================
--- zope.component/trunk/src/zope/component/tests.py 2009-03-11 22:44:45 UTC (rev 97937)
+++ zope.component/trunk/src/zope/component/tests.py 2009-03-11 23:38:56 UTC (rev 97938)
@@ -945,6 +945,98 @@
| Factory 2 is here
"""
+def test_next_utilities():
+ """
+ It is common for a utility to delegate its answer to a utility
+ providing the same interface in one of the component registry's
+ bases. Let's first create a global utility::
+
+ >>> import zope.interface
+ >>> class IMyUtility(zope.interface.Interface):
+ ... pass
+
+ >>> class MyUtility(ConformsToIComponentLookup):
+ ... zope.interface.implements(IMyUtility)
+ ... def __init__(self, id, sm):
+ ... self.id = id
+ ... self.sitemanager = sm
+ ... def __repr__(self):
+ ... return "%s('%s')" % (self.__class__.__name__, self.id)
+
+ >>> from zope.component import getGlobalSiteManager
+ >>> gsm = getGlobalSiteManager()
+
+ >>> gutil = MyUtility('global', gsm)
+ >>> gsm.registerUtility(gutil, IMyUtility, 'myutil')
+
+ Now, let's create two registries and set up the bases hierarchy::
+
+ >>> from zope.component.registry import Components
+ >>> sm1 = Components('sm1', bases=(gsm, ))
+ >>> sm1_1 = Components('sm1_1', bases=(sm1, ))
+
+ Now we create two utilities and insert them in our folder hierarchy:
+
+ >>> util1 = MyUtility('one', sm1)
+ >>> sm1.registerUtility(util1, IMyUtility, 'myutil')
+ >>> IComponentLookup(util1) is sm1
+ True
+
+ >>> util1_1 = MyUtility('one-one', sm1_1)
+ >>> sm1_1.registerUtility(util1_1, IMyUtility, 'myutil')
+ >>> IComponentLookup(util1_1) is sm1_1
+ True
+
+ Now, if we ask `util1_1` for its next available utility we get the
+ ``one`` utility::
+
+ >>> from zope.component import getNextUtility
+ >>> getNextUtility(util1_1, IMyUtility, 'myutil')
+ MyUtility('one')
+
+ Next we ask `util1` for its next utility and we should get the global version:
+
+ >>> getNextUtility(util1, IMyUtility, 'myutil')
+ MyUtility('global')
+
+ However, if we ask the global utility for the next one, an error is raised
+
+ >>> getNextUtility(gutil, IMyUtility,
+ ... 'myutil') #doctest: +NORMALIZE_WHITESPACE
+ Traceback (most recent call last):
+ ...
+ ComponentLookupError:
+ No more utilities for <InterfaceClass zope.component.tests.IMyUtility>,
+ 'myutil' have been found.
+
+ You can also use `queryNextUtility` and specify a default:
+
+ >>> from zope.component import queryNextUtility
+ >>> queryNextUtility(gutil, IMyUtility, 'myutil', 'default')
+ 'default'
+
+ Let's now ensure that the function also works with multiple registries. First
+ we create another base registry:
+
+ >>> myregistry = Components()
+
+ We now set up another utility into that registry:
+
+ >>> custom_util = MyUtility('my_custom_util', myregistry)
+ >>> myregistry.registerUtility(custom_util, IMyUtility, 'my_custom_util')
+
+ We add it as a base to the local site manager:
+
+ >>> sm1.__bases__ = (myregistry,) + sm1.__bases__
+
+ Both the ``myregistry`` and global utilities should be available:
+
+ >>> queryNextUtility(sm1, IMyUtility, 'my_custom_util')
+ MyUtility('my_custom_util')
+ >>> queryNextUtility(sm1, IMyUtility, 'myutil')
+ MyUtility('global')
+ """
+
class StandaloneTests(unittest.TestCase):
def testStandalone(self):
import subprocess
More information about the Checkins
mailing list