[Zope3-checkins]
SVN: Zope3/branches/srichter-blow-services/src/zope/app/component/
Finished lcoal component API and the final README.txt. Yipee!
Stephan Richter
srichter at cosmos.phy.tufts.edu
Fri Jan 7 09:06:45 EST 2005
Log message for revision 28759:
Finished lcoal component API and the final README.txt. Yipee!
Changed:
U Zope3/branches/srichter-blow-services/src/zope/app/component/README.txt
U Zope3/branches/srichter-blow-services/src/zope/app/component/__init__.py
A Zope3/branches/srichter-blow-services/src/zope/app/component/tests/test_api.py
-=-
Modified: Zope3/branches/srichter-blow-services/src/zope/app/component/README.txt
===================================================================
--- Zope3/branches/srichter-blow-services/src/zope/app/component/README.txt 2005-01-07 14:03:24 UTC (rev 28758)
+++ Zope3/branches/srichter-blow-services/src/zope/app/component/README.txt 2005-01-07 14:06:45 UTC (rev 28759)
@@ -2,31 +2,128 @@
Zope 3's Local Component Architecture
=====================================
+The local component architecture provides several packages that can be used
+independent of the entire component architecture framework. Thus, I decided to
+document these frameworks in different files.
-Registration Framework
-----------------------
+ o Registration Framework (`registration.txt`)
+ Provides an API for creating custom registries. The entries of the
+ registries are managed via registration components. A specific
+ implementation for component-based registrations is also
+ provided. Finally, there are some generic container classes that allow the
+ developer to manage the components and their registrations.
-Local Adapter Registry
-----------------------
+ o Local Adapter Registry (`adapterregistry.txt`)
+ Provides a persistent adapter registry that uses the registration
+ framework. Local registries can be assembled to a registry tree where
+ nodes further down in the tree overrride registrations of higher-up nodes.
-Local Site Manager
-------------------
+ o Sites and Local Site Managers (`site.txt`)
+ Provides a local and persistent site manager implementation, so that one
+ can register local utilities and adapters. It uses local adapter
+ registries for its adapter and utility registry. The module also provides
+ some facilities to organize the local software and ensures the correct
+ behavior inside the ZODB.
-Persistent Module Registry
---------------------------
-resolve
-findModule
-__import__
+Local Component Architecture API
+--------------------------------
+While the component architecture API provided by `zope.component` is
+sufficient most of the time, there are a couple of functions that are useful
+in the context of multiple sites.
-Local API
----------
+A very common use case is to get the nearest site manager in a given
+context. Sometimes, however, one wants the next higher-up site manager. First,
+let's create a folder tree and create some sites from it:
-getNextSiteManager
-queryNextSiteManager
-getNextUtility
-queryNextUtility
\ No newline at end of file
+ >>> from zope.app.testing import setup
+ >>> root = setup.buildSampleFolderTree()
+ >>> root_sm = setup.createSiteManager(root)
+ >>> folder1_sm = setup.createSiteManager(root['folder1'])
+
+If we ask `folder1` for its nearest site manager, we get
+
+ >>> from zope.app import zapi
+ >>> zapi.getSiteManager(root['folder1']) is folder1_sm
+ True
+
+but its next site manager is
+
+ >>> from zope.app import component
+ >>> component.getNextSiteManager(root['folder1']) is root_sm
+ True
+
+The next site manager of the local root is the global site manager:
+
+ >>> gsm = zapi.getGlobalSiteManager()
+ >>> component.getNextSiteManager(root) is gsm
+ True
+
+If a non-location is passed into the function, a component lookup error is
+raised, since there is no site manager beyond the global site manager:
+
+ >>> component.getNextSiteManager(object())
+ Traceback (most recent call last):
+ ...
+ ComponentLookupError: 'No more site managers have been found.'
+
+If you use the `queryNextSiteManager()` function, you can specify a `default`
+return value:
+
+ >>> component.queryNextSiteManager(object(), 'default')
+ 'default'
+
+A related use case to the above is to find the next available utility
+providing a certain interface and name. This is often used when a utility
+delegates a query to the next one. Let's start by creating a utility and
+inserting it in our folder hiearchy:
+
+ >>> import zope.interface
+ >>> class IMyUtility(zope.interface.Interface):
+ ... pass
+
+ >>> class MyUtility(object):
+ ... zope.interface.implements(IMyUtility)
+ ... def __init__(self, id):
+ ... self.id = id
+ ... def __repr__(self):
+ ... return "%s('%s')" %(self.__class__.__name__, self.id)
+
+ >>> gutil = MyUtility('global')
+ >>> gsm.provideUtility(IMyUtility, gutil, 'myutil')
+
+ >>> util1 = setup.addUtility(folder1_sm, 'myutil', IMyUtility,
+ ... MyUtility('one'))
+
+ >>> folder1_1_sm = setup.createSiteManager(root['folder1']['folder1_1'])
+ >>> util1_1 = setup.addUtility(folder1_1_sm, 'myutil', IMyUtility,
+ ... MyUtility('one-one'))
+
+Now, if we ask `util1_1` for its next available utility and we get
+
+ >>> component.getNextUtility(util1_1, IMyUtility, 'myutil')
+ MyUtility('one')
+
+Next we ask `util1` for its next utility and we should get the global version:
+
+ >>> component.getNextUtility(util1, IMyUtility, 'myutil')
+ MyUtility('global')
+
+However, if we ask the global utility for the next one, an error is raised
+
+ >>> component.getNextUtility(gutil, IMyUtility,
+ ... 'myutil') #doctest: +NORMALIZE_WHITESPACE
+ Traceback (most recent call last):
+ ...
+ ComponentLookupError:
+ "No more utilities for <InterfaceClass __builtin__.IMyUtility>,
+ 'myutil' have been found."
+
+or you can simply use the `queryNextUtility` and specify a default:
+
+ >>> component.queryNextUtility(gutil, IMyUtility, 'myutil', 'default')
+ 'default'
\ No newline at end of file
Modified: Zope3/branches/srichter-blow-services/src/zope/app/component/__init__.py
===================================================================
--- Zope3/branches/srichter-blow-services/src/zope/app/component/__init__.py 2005-01-07 14:03:24 UTC (rev 28758)
+++ Zope3/branches/srichter-blow-services/src/zope/app/component/__init__.py 2005-01-07 14:06:45 UTC (rev 28759)
@@ -16,6 +16,8 @@
$Id$
"""
__docformat__ = "reStructuredText"
+import zope.component
+from zope.app import zapi
##############################################################################
# BBB: Backward Compatiblity 12/23/2004
@@ -39,10 +41,31 @@
##############################################################################
+_marker = object()
+def getNextSiteManager(context):
+ """Get the next site manager."""
+ sm = queryNextSiteManager(context, _marker)
+ if sm is _marker:
+ raise zope.component.interfaces.ComponentLookupError, \
+ "No more site managers have been found."
+ return sm
-_marker = object()
+def queryNextSiteManager(context, default=None):
+ """Get the next site manager.
+
+ If the site manager of the given context is the global site manager, then
+ `default` is returned.
+ """
+ sm = zapi.getSiteManager(context)
+ if zope.component.site.IGlobalSiteManager.providedBy(sm):
+ return default
+ if sm.next is None:
+ return zapi.getGlobalSiteManager()
+ return sm.next
+
+
def getNextUtility(context, interface, name=''):
"""Get the next available utility.
@@ -50,7 +73,7 @@
"""
util = queryNextUtility(context, interface, name, _marker)
if util is _marker:
- raise ComponentLookupError, \
+ raise zope.component.interfaces.ComponentLookupError, \
"No more utilities for %s, '%s' have been found." %(interface,
name)
return util
@@ -61,46 +84,8 @@
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
+ value."""
+ sm = queryNextSiteManager(context)
+ if sm is None:
+ return default
+ return sm.queryUtility(interface, name, default)
Added: Zope3/branches/srichter-blow-services/src/zope/app/component/tests/test_api.py
===================================================================
--- Zope3/branches/srichter-blow-services/src/zope/app/component/tests/test_api.py 2005-01-07 14:03:24 UTC (rev 28758)
+++ Zope3/branches/srichter-blow-services/src/zope/app/component/tests/test_api.py 2005-01-07 14:06:45 UTC (rev 28759)
@@ -0,0 +1,38 @@
+##############################################################################
+#
+# Copyright (c) 2004 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Registration Tests
+
+$Id$
+"""
+__docformat__ = "reStructuredText"
+import unittest
+
+from zope.testing import doctest
+from zope.app.testing import setup
+
+def setUp(test):
+ setup.placefulSetUp()
+
+def tearDown(test):
+ setup.placefulTearDown()
+
+def test_suite():
+ return unittest.TestSuite((
+ doctest.DocFileSuite('../README.txt',
+ setUp=setUp, tearDown=tearDown),
+ ))
+
+if __name__ == "__main__":
+ unittest.main(defaultTest='test_suite')
+
More information about the Zope3-Checkins
mailing list