[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