[Zope3-checkins] SVN: Zope3/trunk/ Added new `getNextUtility()`, `queryNextUtility()`, and

Stephan Richter srichter at cosmos.phy.tufts.edu
Mon Dec 20 22:29:21 EST 2004


Log message for revision 28662:
  Added new `getNextUtility()`, `queryNextUtility()`, and
  `testingNextUtility()` functions to make it easier to find and test
  for utilities in higher-up sites. These mimic their service-based
  equivalents.
  
  

Changed:
  U   Zope3/trunk/doc/CHANGES.txt
  U   Zope3/trunk/src/zope/app/utility/tests.py
  U   Zope3/trunk/src/zope/app/utility/utility.py

-=-
Modified: Zope3/trunk/doc/CHANGES.txt
===================================================================
--- Zope3/trunk/doc/CHANGES.txt	2004-12-21 03:03:45 UTC (rev 28661)
+++ Zope3/trunk/doc/CHANGES.txt	2004-12-21 03:29:21 UTC (rev 28662)
@@ -10,6 +10,11 @@
 
     New features
 
+      - Added new `getNextUtility()`, `queryNextUtility()`, and
+        `testingNextUtility()` functions to make it easier to find and test
+        for utilities in higher-up sites. These mimic their service-based
+        equivalents.
+
       - Added `getInfo(generation)` method to `zope.app.generations`'s
         `ISchemaManager`. It will return some information about the evolver
         that brings the database to the specified generation. This way we can

Modified: Zope3/trunk/src/zope/app/utility/tests.py
===================================================================
--- Zope3/trunk/src/zope/app/utility/tests.py	2004-12-21 03:03:45 UTC (rev 28661)
+++ Zope3/trunk/src/zope/app/utility/tests.py	2004-12-21 03:29:21 UTC (rev 28662)
@@ -260,6 +260,9 @@
         unittest.makeSuite(TestUtilityService),
         unittest.makeSuite(TestLocalUtilityDirective),
         DocTestSuite('zope.app.utility.metaconfigure'),
+        DocTestSuite('zope.app.utility.utility',
+                     setUp=setup.placelessSetUp,
+                     tearDown=setup.placelessTearDown),
         DocTestSuite('zope.app.utility.vocabulary',
                      setUp=setup.placelessSetUp,
                      tearDown=setup.placelessTearDown)

Modified: Zope3/trunk/src/zope/app/utility/utility.py
===================================================================
--- Zope3/trunk/src/zope/app/utility/utility.py	2004-12-21 03:03:45 UTC (rev 28661)
+++ Zope3/trunk/src/zope/app/utility/utility.py	2004-12-21 03:29:21 UTC (rev 28662)
@@ -17,16 +17,18 @@
 $Id$
 """
 from persistent.interfaces import IPersistent
+import zope.interface
+import zope.interface.adapter
+from zope.component.utility import UtilityService, GlobalUtilityService
+from zope.security.proxy import removeSecurityProxy
+
+import zope.app.site.interfaces
+from zope.app import zapi
 from zope.app.adapter.adapter import LocalAdapterService
-from zope.app import zapi
+from zope.app.component.localservice import queryNextService
 from zope.app.registration.registration import ComponentRegistration
 from zope.app.utility.interfaces import ILocalUtilityService
 from zope.app.utility.interfaces import IUtilityRegistration
-from zope.component.utility import UtilityService
-from zope.security.proxy import removeSecurityProxy
-import zope.app.site.interfaces
-import zope.interface
-import zope.interface.adapter
 
 class LocalUtilityService(UtilityService, LocalAdapterService):
     """Local Utility Service
@@ -122,3 +124,140 @@
         # permission; it needs the interface to create a security
         # proxy for the interface with the given permission.
         return self.interface
+
+
+
+_marker = object()
+
+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 ComponentLookupError, \
+              "No more utilities for %s, '%s' have been found." %(interface,
+                                                                  name)
+    return util
+
+
+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.
+
+    It is very important that this method really finds the next utility and
+    does not abort, if the utility was not found in the next utility service.
+
+    Let's start out by declaring a utility interface and an implementation:
+
+      >>> from zope.interface import Interface, implements
+      >>> class IAnyUtility(Interface):
+      ...     pass
+      
+      >>> class AnyUtility(object):
+      ...     implements(IAnyUtility)
+      ...     def __init__(self, id):
+      ...         self.id = id
+      
+      >>> any1 = AnyUtility(1)
+      >>> any1next = AnyUtility(2)
+
+    Now that we have the utilities, let's register them:
+
+      >>> testingNextUtility(any1, any1next, IAnyUtility)
+
+    The next utility of `any1` ahould be `any1next`:
+
+      >>> queryNextUtility(any1, IAnyUtility) is any1next
+      True
+
+    But `any1next` does not have a next utility, so the default is returned:
+
+      >>> queryNextUtility(any1next, IAnyUtility) is None
+      True
+
+    """    
+    util = _marker
+    while util is _marker:
+        utilservice = queryNextService(context, zapi.servicenames.Utilities)
+        if utilservice is None:
+            return default
+        util = utilservice.queryUtility(interface, name, _marker)
+        context = utilservice
+        
+    return util
+
+
+def testingNextUtility(utility, nextutility, interface, name='',
+                       service=None, nextservice=None):
+    """Provide a next utility for testing.
+
+    Since utilities must be registered in services, we really provide a next
+    utility service in which we place the next utility. If you do not pass in
+    any services, they will be created for you.
+
+    For a simple usage of this function, see the doc test of
+    `queryNextUtility()`. Here is a demonstration that passes in the services
+    directly and ensures that the `__parent__` attributes are set correctly.
+
+    First, we need to create a utility interface and implementation:
+
+      >>> from zope.interface import Interface, implements
+      >>> class IAnyUtility(Interface):
+      ...     pass
+      
+      >>> class AnyUtility(object):
+      ...     implements(IAnyUtility)
+      ...     def __init__(self, id):
+      ...         self.id = id
+      
+      >>> any1 = AnyUtility(1)
+      >>> any1next = AnyUtility(2)
+
+    Now we create a special utility service that can have a location:
+
+      >>> UtilityService = type('UtilityService', (GlobalUtilityService,),
+      ...                       {'__parent__': None})
+
+    Let's now create one utility service
+
+      >>> utils = UtilityService()
+
+    and pass it in as the original utility service to the function:
+
+      >>> testingNextUtility(any1, any1next, IAnyUtility, service=utils)
+      >>> any1.__parent__ is utils
+      True
+      >>> utilsnext = any1next.__parent__
+      >>> utils.__parent__.next.data['Utilities'] is utilsnext
+      True
+
+    or if we pass the current and the next utility service:
+
+      >>> utils = UtilityService()
+      >>> utilsnext = UtilityService()
+      >>> testingNextUtility(any1, any1next, IAnyUtility,
+      ...                    service=utils, nextservice=utilsnext)
+      >>> any1.__parent__ is utils
+      True
+      >>> any1next.__parent__ is utilsnext
+      True
+    
+    """
+    UtilityService = type('UtilityService', (GlobalUtilityService,),
+                          {'__parent__': None})
+    if service is None:
+        service = UtilityService()
+    if nextservice is None:
+        nextservice = UtilityService()
+    from zope.app.component.localservice import testingNextService
+    testingNextService(service, nextservice, zapi.servicenames.Utilities)
+
+    service.provideUtility(interface, utility, name)
+    utility.__parent__ = service
+    nextservice.provideUtility(interface, nextutility, name)
+    nextutility.__parent__ = nextservice



More information about the Zope3-Checkins mailing list