diff options
| author | Dan Korostelev <nadako@gmail.com> | 2009-03-11 23:38:56 +0000 |
|---|---|---|
| committer | Dan Korostelev <nadako@gmail.com> | 2009-03-11 23:38:56 +0000 |
| commit | 5afc3ad4e288895feb57cbcf42663dcebecd7c80 (patch) | |
| tree | a92f08925bf9504aa8d73c4c90361ab478f018e4 /src/zope | |
| parent | 79df7e65fca5515edab2316f89ce1a10f0e3647d (diff) | |
| download | zope-component-5afc3ad4e288895feb57cbcf42663dcebecd7c80.tar.gz | |
Add getNextUtility/queryNextUtility functions that used to be in zope.site earlier (and in zope.app.component even more earlier).
Diffstat (limited to 'src/zope')
| -rw-r--r-- | src/zope/component/__init__.py | 2 | ||||
| -rw-r--r-- | src/zope/component/_api.py | 31 | ||||
| -rw-r--r-- | src/zope/component/interfaces.py | 14 | ||||
| -rw-r--r-- | src/zope/component/tests.py | 92 |
4 files changed, 139 insertions, 0 deletions
diff --git a/src/zope/component/__init__.py b/src/zope/component/__init__.py index 3f88ebd..95be229 100644 --- a/src/zope/component/__init__.py +++ b/src/zope/component/__init__.py @@ -45,11 +45,13 @@ from zope.component._api import getMultiAdapter 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 diff --git a/src/zope/component/_api.py b/src/zope/component/_api.py index 4a38a01..1ddc6d8 100644 --- a/src/zope/component/_api.py +++ b/src/zope/component/_api.py @@ -181,6 +181,37 @@ def getAllUtilitiesRegisteredFor(interface, context=None): 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): diff --git a/src/zope/component/interfaces.py b/src/zope/component/interfaces.py index a34b0d6..7823037 100644 --- a/src/zope/component/interfaces.py +++ b/src/zope/component/interfaces.py @@ -89,6 +89,20 @@ class IComponentArchitecture(Interface): 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 diff --git a/src/zope/component/tests.py b/src/zope/component/tests.py index e9adf44..e8627fe 100644 --- a/src/zope/component/tests.py +++ b/src/zope/component/tests.py @@ -945,6 +945,98 @@ def test_multi_handler_unregistration(): | 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 |
