From c2088ddc969e4600b8fd92165f9ef7f6ac216aa7 Mon Sep 17 00:00:00 2001 From: Martijn Faassen Date: Fri, 9 Jul 2010 10:59:58 +0000 Subject: Fix behavior: now __parent__ is checked first before an ILocation adapter lookup is performed. --- src/zope/traversing/browser/absoluteurl.py | 16 ++++++++-- src/zope/traversing/browser/tests.py | 50 +++++++++++++++++++++++++++++- 2 files changed, 63 insertions(+), 3 deletions(-) (limited to 'src/zope/traversing') diff --git a/src/zope/traversing/browser/absoluteurl.py b/src/zope/traversing/browser/absoluteurl.py index efef9c5..54602e2 100644 --- a/src/zope/traversing/browser/absoluteurl.py +++ b/src/zope/traversing/browser/absoluteurl.py @@ -49,8 +49,20 @@ class AbsoluteURL(BrowserView): or sameProxiedObjects(context, request.getVirtualHostRoot())): return request.getApplicationURL() - context = ILocation(context) - container = getattr(context, '__parent__', None) + # first try to get the __parent__ of the object, no matter whether + # it provides ILocation or not. If this fails, look up an ILocation + # adapter. This will always work, as a general ILocation adapter + # is registered for interface in zope.location (a LocationProxy) + # This proxy will return a parent of None, causing this to fail + # More specific ILocation adapters can be provided however. + try: + container = context.__parent__ + except AttributeError: + # we need to assign to context here so we can get + # __name__ from it below + context = ILocation(context) + container = context.__parent__ + if container is None: raise TypeError(_insufficientContext) diff --git a/src/zope/traversing/browser/tests.py b/src/zope/traversing/browser/tests.py index bc4a095..a52baf5 100644 --- a/src/zope/traversing/browser/tests.py +++ b/src/zope/traversing/browser/tests.py @@ -27,6 +27,7 @@ from zope.interface.verify import verifyObject from zope.publisher.browser import TestRequest from zope.publisher.http import IHTTPRequest, HTTPCharsets from zope.location.interfaces import ILocation +from zope.location.location import LocationProxy from zope.container.contained import contained @@ -39,6 +40,9 @@ class Root(object): class TrivialContent(object): """Trivial content object, used because instances of object are rocks.""" +class AdaptedContent(object): + """A simple content object that has an ILocation adapter for it.""" + class FooContent(object): """Class whose location will be provided by an adapter.""" @@ -70,7 +74,12 @@ class TestAbsoluteURL(PlacelessSetup, TestCase): zope.component.provideAdapter(FooLocation) zope.component.provideAdapter(HTTPCharsets, (IHTTPRequest,), IUserPreferredCharsets) - + # LocationProxy as set by zope.location + # this makes a default LocationProxy for all objects that + # don't define a more specific adapter + zope.component.provideAdapter(LocationProxy, (Interface,), + ILocation) + def tearDown(self): PlacelessSetup.tearDown(self) @@ -112,6 +121,27 @@ class TestAbsoluteURL(PlacelessSetup, TestCase): {'name': 'c', 'url': 'http://127.0.0.1/a/b/c'}, )) + + def testParentButNoLocation(self): + request = TestRequest() + + content1 = TrivialContent() + content1.__parent__ = Root() + content1.__name__ = 'a' + + content2 = TrivialContent() + content2.__parent__ = content1 + content2.__name__ = 'b' + + content3 = TrivialContent() + content3.__parent__ = content2 + content3.__name__ = 'c' + + view = getMultiAdapter((content3, request), name='absolute_url') + self.assertEqual(str(view), 'http://127.0.0.1/a/b/c') + self.assertEqual(absoluteURL(content3, request), + 'http://127.0.0.1/a/b/c') + def testAdaptedContext(self): request = TestRequest() @@ -128,6 +158,23 @@ class TestAbsoluteURL(PlacelessSetup, TestCase): {'name': 'foo', 'url': 'http://127.0.0.1/bar/foo'}, )) + def testParentTrumpsAdapter(self): + # if we have a location adapter for a content object but + # the object also has its own __parent__, this will trump the + # adapter + request = TestRequest() + + + content = FooContent() + content.__parent__ = Root() + content.__name__ = 'foo' + + view = getMultiAdapter((content, request), name='absolute_url') + self.assertEqual(str(view), 'http://127.0.0.1/foo') + self.assertEqual(absoluteURL(content, request), + 'http://127.0.0.1/foo') + + def testBasicContext_unicode(self): #Tests so that AbsoluteURL handle unicode names as well request = TestRequest() @@ -242,6 +289,7 @@ class TestAbsoluteURL(PlacelessSetup, TestCase): self.assertEqual(str(view), 'http://127.0.0.1') self.assertEqual(absoluteURL(None, request), 'http://127.0.0.1') + def testVirtualHostingWithoutContextInformation(self): request = TestRequest() request._vh_root = contained(TrivialContent(), Root(), name='a') -- cgit v1.2.1