[z3-checkins] r18543 - in z3/Five/trunk: . browser doc form/tests testing tests

regebro at codespeak.net regebro at codespeak.net
Fri Oct 14 15:37:33 CEST 2005


Author: regebro
Date: Fri Oct 14 15:37:26 2005
New Revision: 18543

Added:
   z3/Five/trunk/localsite.py
      - copied unchanged from r18537, z3/Five/branch/regebro-sitemanager/localsite.py
   z3/Five/trunk/localsite.zcml
      - copied unchanged from r18537, z3/Five/branch/regebro-sitemanager/localsite.zcml
   z3/Five/trunk/testing/interfaces.py
      - copied unchanged from r18537, z3/Five/branch/regebro-sitemanager/testing/interfaces.py
   z3/Five/trunk/testing/localsite.py
      - copied unchanged from r18537, z3/Five/branch/regebro-sitemanager/testing/localsite.py
   z3/Five/trunk/tests/test_localservice.py
      - copied unchanged from r18537, z3/Five/branch/regebro-sitemanager/tests/test_localservice.py
Modified:
   z3/Five/trunk/CHANGES.txt
   z3/Five/trunk/browser/TrustedExpression.py
   z3/Five/trunk/configure.zcml
   z3/Five/trunk/doc/features.txt
   z3/Five/trunk/fiveconfigure.py
   z3/Five/trunk/fivedirectives.py
   z3/Five/trunk/form/tests/forms.txt
   z3/Five/trunk/interfaces.py
   z3/Five/trunk/meta.zcml
   z3/Five/trunk/monkey.py
Log:
Merging local site support into trunk!


Modified: z3/Five/trunk/CHANGES.txt
==============================================================================
--- z3/Five/trunk/CHANGES.txt	(original)
+++ z3/Five/trunk/CHANGES.txt	Fri Oct 14 15:37:26 2005
@@ -5,6 +5,14 @@
 Trunk only
 ==========
 
+Features
+--------
+* Local site support: Five has now support for creating local sites and 
+  thereby local utilities. This is mostly needed for allowing CMF to convert
+  it's portal tools into local utilities.
+  See doc/local_sites.txt for more information 
+  (that is, when I have finished that piece of documentation /Regebro).
+
 Restructuring
 -------------
 

Modified: z3/Five/trunk/browser/TrustedExpression.py
==============================================================================
--- z3/Five/trunk/browser/TrustedExpression.py	(original)
+++ z3/Five/trunk/browser/TrustedExpression.py	Fri Oct 14 15:37:26 2005
@@ -70,7 +70,7 @@
       o = get(object, name, M)
       if o is M:
         try: o = object[name]
-        except AttributeError: # better exception
+        except (AttributeError, TypeError): # better exception
           raise AttributeError(name)
     object = o
 

Modified: z3/Five/trunk/configure.zcml
==============================================================================
--- z3/Five/trunk/configure.zcml	(original)
+++ z3/Five/trunk/configure.zcml	Fri Oct 14 15:37:26 2005
@@ -6,6 +6,7 @@
   <include file="interfaces.zcml" />
   <include file="permissions.zcml" />
   <include file="i18n.zcml" />
+  <include file="localsite.zcml" />
   <include package=".browser" />
   <include package=".form" />
   <include package=".skin" />

Modified: z3/Five/trunk/doc/features.txt
==============================================================================
--- z3/Five/trunk/doc/features.txt	(original)
+++ z3/Five/trunk/doc/features.txt	Fri Oct 14 15:37:26 2005
@@ -84,3 +84,23 @@
 ignored by views anyway, as they are trusted -- it only serves to
 protect directly exposed methods on content classes (the python
 scripts and the ZPublisher).
+
+Local Site Manager
+==================
+
+Five can support the concept of a Local Site Manager. The steps for
+creating one are:
+
+  - Register your Zope 2 class with the 'local site hook' using the
+    <five:localsitehook> directive. Doing that will mixin the FiveSite
+    class into your class by means of 'structured monkey patching'.
+
+  - Implement an ``IFiveSite`` adapter for your Zope 2 class. For the full
+    interface definition refer to
+    ``Products.Five.interfaces.IFiveSite``.
+
+  - To enable the Local Site Hook for an instance of your class, use::
+
+    from Products.Five.localsite import enableLocalSiteHook
+    enableLocalSiteHook(obj)
+

Modified: z3/Five/trunk/fiveconfigure.py
==============================================================================
--- z3/Five/trunk/fiveconfigure.py	(original)
+++ z3/Five/trunk/fiveconfigure.py	Fri Oct 14 15:37:26 2005
@@ -25,14 +25,20 @@
 import App
 from zLOG import LOG, ERROR
 
-from zope.interface import classImplements
+from zope.interface import classImplements, classImplementsOnly, implementedBy
+from zope.interface.interface import InterfaceClass
 from zope.configuration import xmlconfig
+from zope.configuration.exceptions import ConfigurationError
 from zope.app.component.interface import provideInterface
+from zope.app.component.metaconfigure import adapter
+from zope.app.utility.interfaces import ILocalUtilityService
+from zope.app.site.interfaces import IPossibleSite, ISite
 
 from viewable import Viewable
 from traversable import Traversable
 from bridge import fromZ2Interface
 from browser.metaconfigure import page
+from localsite import FiveSite, SimpleLocalUtilityService
 
 debug_mode = App.config.getConfiguration().debug_mode
 
@@ -55,7 +61,7 @@
     # in the control panel. However, all attempts to do so has failed from my 
     # side. //regebro
     exc = sys.exc_info()
-    LOG('Five', ERROR, 'Could not import Product %s' % product, error=exc)
+    LOG('Five', ERROR, 'Could not import Product %s' % product.__name__, error=exc)
 
 def loadProducts(_context):
     products = findProducts()
@@ -233,6 +239,60 @@
         page(_context, name=name, permission=permission,
              layer=layer, for_=for_, template=fname)
 
+def classSiteHook(class_, site_class):
+    setattr(class_, 'getSiteManager',
+            site_class.getSiteManager.im_func)
+    setattr(class_, 'setSiteManager',
+            site_class.setSiteManager.im_func)
+ 
+count = 0
+def next():
+    global count
+    count += 1
+    return count
+
+_localsite_monkies = []
+def installSiteHook(_context, class_, site_class=None, utility_service=None):
+    if site_class is None:
+        if not IPossibleSite.implementedBy(class_):
+            # This is not a possible site, we need to monkey-patch it so that
+            # it is.
+            site_class = FiveSite
+    else:
+        if not IPossibleSite.implementedBy(site_class):
+            raise ConfigurationError('Site class does not implement '
+                                     'IPossibleClass: %s' % site_class)
+    if site_class is not None:
+        _context.action(
+            discriminator = (class_,),
+            callable = classSiteHook,
+            args=(class_, site_class)
+            )
+        _context.action(
+            discriminator = (class_, ISite),
+            callable = classImplements,
+            args=(class_, ISite)
+            )
+    if utility_service is None:
+        utility_service = SimpleLocalUtilityService
+    else:
+        if not ILocalUtilityService.implementedBy(utility_service):
+            raise ConfigurationError('utility_service does not implement '
+                                     'ILocalUtilityService: %s' % utility_service)
+        
+    # Generate a marker interface that should be unique, so that
+    # we can register the utility service only for this class.
+    iface = InterfaceClass('IFiveSite%s' % next())
+    adapter(_context, factory=(utility_service,),
+            provides=ILocalUtilityService,
+            for_=(iface,))
+    _context.action(
+        discriminator = (class_, 'UtilityMarker'),
+        callable = classImplements,
+        args=(class_, iface)
+        )
+    _localsite_monkies.append(class_)
+
 # clean up code
 
 def killMonkey(class_, name, fallback, attr=None):
@@ -265,12 +325,21 @@
     killMonkey(class_, '__browser_default__', '__fallback_default__',
                '__five_viewable__')
 
+def uinstallSiteHook(class_):
+    delattr(class_, 'getSiteManager')
+    delattr(class_, 'setSiteManager')
+    classImplementsOnly(class_, implementedBy(class_)-ISite)
+    _localsite_monkies.remove(class_)
+
 def cleanUp():
     for class_ in _traversable_monkies:
         untraversable(class_)
     for class_ in _defaultviewable_monkies:
         undefaultViewable(class_)
-
+    for class_ in _localsite_monkies:
+        uinstallSiteHook(class_)
+    
 from zope.testing.cleanup import addCleanUp
 addCleanUp(cleanUp)
 del addCleanUp
+

Modified: z3/Five/trunk/fivedirectives.py
==============================================================================
--- z3/Five/trunk/fivedirectives.py	(original)
+++ z3/Five/trunk/fivedirectives.py	Fri Oct 14 15:37:26 2005
@@ -104,3 +104,19 @@
         description=u"The directory containing the resource data.",
         required=True
         )
+
+class ISiteDirective(Interface):
+    """Make instances of class hookable for Site.
+
+    site_class is an implementation of ISite, which will have it's methods
+    monkey_patched into the the class. If not given a default implementation
+    will be used.
+    """
+    class_ = GlobalObject(
+        title=u"Class",
+        required=True
+        )
+    site_class = GlobalObject(
+        title=u"Site Class",
+        required=False
+        )

Modified: z3/Five/trunk/form/tests/forms.txt
==============================================================================
--- z3/Five/trunk/form/tests/forms.txt	(original)
+++ z3/Five/trunk/form/tests/forms.txt	Fri Oct 14 15:37:26 2005
@@ -48,9 +48,8 @@
   >>> print http(r"""
   ... GET /test_folder_1_/ftf/+/protectedaddform.html HTTP/1.1
   ... """, handle_errors=False)
-  Traceback (most recent call last):
+  HTTP/1.1 401 Unauthorized
   ...
-  Unauthorized: ...
 
 Now let's add a piece of our sample content object to test more things
 on it:

Modified: z3/Five/trunk/interfaces.py
==============================================================================
--- z3/Five/trunk/interfaces.py	(original)
+++ z3/Five/trunk/interfaces.py	Fri Oct 14 15:37:26 2005
@@ -17,6 +17,7 @@
 """
 from zope.interface import Interface
 from zope.interface.interfaces import IInterface
+from zope.app.site.interfaces import ISite
 
 class IBrowserDefault(Interface):
     """Provide a hook for deciding about the default view for an object"""
@@ -34,6 +35,9 @@
     menu items.
     """
 
+class IFiveSite(ISite):
+    """Five specialization of ISite
+    """
 
 #
 # BBB: Zope core interfaces

Modified: z3/Five/trunk/meta.zcml
==============================================================================
--- z3/Five/trunk/meta.zcml	(original)
+++ z3/Five/trunk/meta.zcml	Fri Oct 14 15:37:26 2005
@@ -162,6 +162,12 @@
        handler=".fiveconfigure.bridge"
        />
 
+    <meta:directive
+       name="localsite"
+       schema=".fivedirectives.ISiteDirective"
+       handler=".fiveconfigure.installSiteHook"
+       />
+       
   </meta:directives>
 
   <meta:directive

Modified: z3/Five/trunk/monkey.py
==============================================================================
--- z3/Five/trunk/monkey.py	(original)
+++ z3/Five/trunk/monkey.py	Fri Oct 14 15:37:26 2005
@@ -55,3 +55,36 @@
         import sys
         from Products.Five.bbb import transaction
         sys.modules['transaction'] = transaction
+ 
+    from Acquisition import aq_inner, aq_parent
+    from zope.app.site.interfaces import ISiteManager
+    from zope.component.exceptions import ComponentLookupError
+
+    def getLocalServices(context):
+        """Returns the service manager that contains `context`.
+
+        If `context` is a local service, returns the service manager
+        that contains that service. If `context` is a service manager,
+        returns `context`.
+
+        Otherwise, raises ``ComponentLookupError('Services')``
+
+        XXX Basically, this overrides the one in Zope3 X3.0 so that it
+        uses acquisition instead of looking up __parent__.
+        """
+
+        # IMPORTANT
+        #
+        # This is not allowed to use any services to get its job done!
+
+        while not (context is None or
+                   ISiteManager.providedBy(context)):
+            context = aq_parent(aq_inner(context))
+        if context is None:
+            raise ComponentLookupError('Services')
+        else:
+            return context
+
+    from zope.app.component import localservice
+    localservice.getLocalServices = getLocalServices
+


More information about the z3-checkins mailing list