[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