Log message for revision 41744: for alecm: Changed Traversable to call the original __bobo_traverse__ method before attempting to use attribute access to find the desired object. This ensures that the monkeypatched object retains the same behavior as the original object during traversal. Also, added checks to see if the request is a WebDAV request in which case attribute lookup is performed without acquisition (see BaseRequest.traverse for why this is important).
Changed: U Zope/branches/2.9/lib/python/Products/Five/browser/tests/test_traversable.py U Zope/branches/2.9/lib/python/Products/Five/traversable.py -=- Modified: Zope/branches/2.9/lib/python/Products/Five/browser/tests/test_traversable.py =================================================================== --- Zope/branches/2.9/lib/python/Products/Five/browser/tests/test_traversable.py 2006-02-21 21:37:05 UTC (rev 41743) +++ Zope/branches/2.9/lib/python/Products/Five/browser/tests/test_traversable.py 2006-02-22 01:20:07 UTC (rev 41744) @@ -64,6 +64,9 @@ ... <five:traversable ... class="Products.Five.browser.tests.test_traversable.SimpleClass" ... /> + ... <five:traversable + ... class="Products.Five.tests.testing.FiveTraversableFolder" + ... /> ... ... <browser:page ... for="Products.Five.tests.testing.fancycontent.IFancyContent" @@ -99,7 +102,64 @@ ... Fancy, fancy + Without five traversable, if there had been an attrubute something-else, + the __bobo_traverse__ method would have still been used instead of the + atribute, let's make sure we preserve that behavior. + >>> self.folder.fancy.an_attribute = 'This is an attribute' + >>> print http(r''' + ... GET /test_folder_1_/fancy/an_attribute HTTP/1.1 + ... ''') + HTTP/1.1 200 OK + ... + an_attribute + + If we use WebDAV to get an object no acquisition should be performed, + otherwise content creation will break: + + >>> from Products.Five.tests.testing import manage_addFiveTraversableFolder + >>> manage_addFiveTraversableFolder(self.folder, 'traversable_folder', 'Traversable') + + Let's verify that we can get our object properties via WebDAV: + >>> print http(r''' + ... PROPFIND /test_folder_1_/fancy HTTP/1.1 + ... Content-Type: text/xml; charset="utf-8" + ... Depth: 0 + ... + ... <?xml version="1.0" encoding="utf-8"?> + ... <DAV:propfind xmlns:DAV="DAV:" + ... xmlns:zope="http://www.zope.org/propsets/default"> + ... <DAV:prop><zope:title/></DAV:prop> + ... </DAV:propfind> + ... ''') + HTTP/1.1 200 OK + ... + PROPFIND + + And that a normal http request will acquire the object: + >>> print http(r''' + ... GET /test_folder_1_/traversable_folder/fancy HTTP/1.1 + ... ''') + HTTP/1.1 200 OK + ... + <FancyContent at > + + But that a WebDAV request will not: + >>> print http(r''' + ... PROPFIND /test_folder_1_/traversable_folder/fancy HTTP/1.1 + ... Content-Type: text/xml; charset="utf-8" + ... Depth: 0 + ... + ... <?xml version="1.0" encoding="utf-8"?> + ... <DAV:propfind xmlns:DAV="DAV:" + ... xmlns:zope="http://www.zope.org/propsets/default"> + ... <DAV:prop><zope:title/></DAV:prop> + ... </DAV:propfind> + ... ''') + HTTP/1.1 404 Not Found + ... + + Clean up: >>> from zope.app.testing.placelesssetup import tearDown Modified: Zope/branches/2.9/lib/python/Products/Five/traversable.py =================================================================== --- Zope/branches/2.9/lib/python/Products/Five/traversable.py 2006-02-21 21:37:05 UTC (rev 41743) +++ Zope/branches/2.9/lib/python/Products/Five/traversable.py 2006-02-22 01:20:07 UTC (rev 41744) @@ -16,6 +16,7 @@ $Id: traversable.py 19283 2005-10-31 17:43:51Z philikon $ """ from zExceptions import NotFound +from ZPublisher import xmlrpc from zope.component import getMultiAdapter, ComponentLookupError from zope.interface import implements, Interface @@ -29,8 +30,11 @@ from zope.app.interface import queryType from AccessControl import getSecurityManager +from Acquisition import aq_base from Products.Five.security import newInteraction +from webdav.NullResource import NullResource + _marker = object class FakeRequest(dict): @@ -56,7 +60,7 @@ Just raise a AttributeError to indicate traversal has failed and let Zope do it's job. """ - raise AttributeError, name + raise NotImplementedError __fallback_traverse__.__five_method__ = True def __bobo_traverse__(self, REQUEST, name): @@ -86,14 +90,36 @@ AttributeError, KeyError, NotFound): pass try: - return getattr(self, name) - except AttributeError: + return self.__fallback_traverse__(REQUEST, name) + except NotImplementedError: pass - try: - return self[name] - except (AttributeError, KeyError): - pass - return self.__fallback_traverse__(REQUEST, name) + # This should at least make a half hearted attempt to care for + # potential WebDAV issues, in particular we should not perform + # acquisition for webdav requests, and should return a NullResource + # when appropriate. + method = REQUEST.get('REQUEST_METHOD', 'GET').upper() + if (len(REQUEST.get('TraversalRequestNameStack', ())) == 0 and + not (method in ('GET', 'HEAD', 'POST') and not + isinstance(REQUEST.RESPONSE, xmlrpc.Response))): + if getattr(aq_base(self), name, None) is not None: + return getattr(self, name) + else: + # XXX: This may be unnecessary as Zope itself doesn't do it, + # but it shouldn't be harmful + if (method in ('PUT', 'MKCOL') and not + isinstance(RESPONSE, xmlrpc.Response)): + return NullResource(self, name, REQUEST).__of__(self) + else: + try: + return getattr(self, name) + except AttributeError: + pass + try: + return self[name] + except (AttributeError, KeyError): + pass + raise AttributeError, name + __bobo_traverse__.__five_method__ = True @@ -112,3 +138,5 @@ return getMultiAdapter((context, REQUEST), Interface, name) except ComponentLookupError: pass + + _______________________________________________ Zope-Checkins maillist - Zope-Checkins@zope.org http://mail.zope.org/mailman/listinfo/zope-checkins