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(): _______________________________________________ Zope-Checkins maillist - Zope-Checkins@zope.org https://mail.zope.org/mailman/listinfo/zope-checkins