[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