[Zope-Checkins] SVN: Zope/branches/wichert=request-modifier/ If a traversal step returns the same object do not call before-publish hooks again

Wichert Akkerman wichert at wiggy.net
Sun Feb 21 16:12:32 EST 2010


Log message for revision 109226:
  If a traversal step returns the same object do not call before-publish hooks again
  

Changed:
  U   Zope/branches/wichert=request-modifier/doc/CHANGES.rst
  U   Zope/branches/wichert=request-modifier/src/ZPublisher/BaseRequest.py
  U   Zope/branches/wichert=request-modifier/src/ZPublisher/tests/testBeforeTraverse.py

-=-
Modified: Zope/branches/wichert=request-modifier/doc/CHANGES.rst
===================================================================
--- Zope/branches/wichert=request-modifier/doc/CHANGES.rst	2010-02-21 20:44:15 UTC (rev 109225)
+++ Zope/branches/wichert=request-modifier/doc/CHANGES.rst	2010-02-21 21:12:32 UTC (rev 109226)
@@ -20,6 +20,9 @@
 Bugs Fixed
 ++++++++++
 
+- If a traversal step returns the same object do not call before-publish hooks
+  again.
+
 - Protect ZCTextIndex's clear method against storing Acquisition wrappers.
 
 - LP #195761: fixed ZMI XML export / import and restored it to the UI.

Modified: Zope/branches/wichert=request-modifier/src/ZPublisher/BaseRequest.py
===================================================================
--- Zope/branches/wichert=request-modifier/src/ZPublisher/BaseRequest.py	2010-02-21 20:44:15 UTC (rev 109225)
+++ Zope/branches/wichert=request-modifier/src/ZPublisher/BaseRequest.py	2010-02-21 21:12:32 UTC (rev 109226)
@@ -36,6 +36,12 @@
     # quote url path segments, but leave + and @ intact
     return urllib_quote(text, '/+@')
 
+def _base(obj):
+    if IAcquirer.providedBy(obj):
+        return aq_base(obj)
+    return obj
+
+
 try:
     from ExtensionClass import Base
     from ZPublisher.Converters import type_converters
@@ -428,10 +434,12 @@
         try:
             # We build parents in the wrong order, so we
             # need to make sure we reverse it when we're done.
+            same_object = False
             while 1:
-                bpth = getattr(object, '__before_publishing_traverse__', None)
-                if bpth is not None:
-                    bpth(object, self)
+                if not same_object:
+                    bpth = getattr(object, '__before_publishing_traverse__', None)
+                    if bpth is not None:
+                        bpth(object, self)
 
                 path = request.path = request['TraversalRequestNameStack']
                 # Check for method:
@@ -505,6 +513,7 @@
                     self.roles = getRoles(
                         object, check_name, subobject,
                         self.roles)
+                    same_object =  _base(object) is _base(subobject)
                     object = subobject
                 except (KeyError, AttributeError):
                     if response.debug_mode:

Modified: Zope/branches/wichert=request-modifier/src/ZPublisher/tests/testBeforeTraverse.py
===================================================================
--- Zope/branches/wichert=request-modifier/src/ZPublisher/tests/testBeforeTraverse.py	2010-02-21 20:44:15 UTC (rev 109225)
+++ Zope/branches/wichert=request-modifier/src/ZPublisher/tests/testBeforeTraverse.py	2010-02-21 21:12:32 UTC (rev 109226)
@@ -1,10 +1,12 @@
 import sys
 import logging
 
+from zope.interface import implements
 from Acquisition import Implicit
 from ZPublisher import BeforeTraverse
 from ZPublisher.BaseRequest import BaseRequest
 from ZPublisher.HTTPResponse import HTTPResponse
+from zope.publisher.interfaces import IPublishTraverse
 
 def makeBaseRequest(root):
     response = HTTPResponse()
@@ -133,6 +135,39 @@
     """
     pass
 
+class CountHook:
+    counter = 0
+    def __call__(self, obj, request):
+        self.counter += 1
+        
+
+class TraverseToSelfObject(Implicit):
+    implements(IPublishTraverse)
+    def publishTraverse(self, request, name):
+        return self
+
+def testNoMulitpleCalls(self):
+    """
+    Sometimes a traversal adapter is used which only modifies the
+    request, but does not do any real traversing. Skin traversal
+    adapters are a common example of this type of adapter. In this
+    case we do not want to call the before publish hooks for the
+    same object multiple times.
+
+    >>> root = DummyObjectBasic()
+    >>> request = makeBaseRequest(root)
+
+    >>> container = TraverseToSelfObject()
+    >>> root.container = container
+
+    >>> counter = CountHook()
+    >>> BeforeTraverse.registerBeforeTraverse(container, counter, 'count_hook')
+
+    >>> _ = request.traverse('container/traverser/obj')
+    >>> counter.counter
+    1
+    """
+
 from zope.testing import doctest
 
 def test_suite():



More information about the Zope-Checkins mailing list