[Checkins] SVN: zope.traversing/trunk/ Fix behavior: now __parent__ is checked first before an ILocation

Martijn Faassen faassen at startifact.com
Fri Jul 9 06:59:59 EDT 2010


Log message for revision 114362:
  Fix behavior: now __parent__ is checked first before an ILocation
  adapter lookup is performed.
  

Changed:
  U   zope.traversing/trunk/CHANGES.txt
  U   zope.traversing/trunk/src/zope/traversing/browser/absoluteurl.py
  U   zope.traversing/trunk/src/zope/traversing/browser/tests.py

-=-
Modified: zope.traversing/trunk/CHANGES.txt
===================================================================
--- zope.traversing/trunk/CHANGES.txt	2010-07-09 06:50:23 UTC (rev 114361)
+++ zope.traversing/trunk/CHANGES.txt	2010-07-09 10:59:58 UTC (rev 114362)
@@ -2,9 +2,18 @@
 Changes
 =======
 
-3.12.2 (unreleased)
--------------------
+3.13 (unreleased)
+-----------------
 
+- When a ``__parent__`` attribute is available on an object, it is
+  always used for absolute URL construction, and no ILocation adapter
+  lookup is performed for it. This was the previous behavior but was
+  broken (around 3.5?) due to dependency refactoring. 
+ 
+  If the object provides no ``__parent__`` then an ILocation adapter
+  lookup will be performed. This will always succeed as zope.location
+  provides a default LocationProxy for everything, but more specific
+  ILocation adapters can also be provided.
 
 3.12.1 (2010-04-30)
 -------------------

Modified: zope.traversing/trunk/src/zope/traversing/browser/absoluteurl.py
===================================================================
--- zope.traversing/trunk/src/zope/traversing/browser/absoluteurl.py	2010-07-09 06:50:23 UTC (rev 114361)
+++ zope.traversing/trunk/src/zope/traversing/browser/absoluteurl.py	2010-07-09 10:59:58 UTC (rev 114362)
@@ -49,8 +49,20 @@
             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)
 

Modified: zope.traversing/trunk/src/zope/traversing/browser/tests.py
===================================================================
--- zope.traversing/trunk/src/zope/traversing/browser/tests.py	2010-07-09 06:50:23 UTC (rev 114361)
+++ zope.traversing/trunk/src/zope/traversing/browser/tests.py	2010-07-09 10:59:58 UTC (rev 114362)
@@ -27,6 +27,7 @@
 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 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 @@
         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 @@
                           {'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 @@
                           {'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 @@
         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')



More information about the checkins mailing list