[Zope-Checkins] SVN: Zope/branches/dc-bobo_traverse-branch/lib/python/ZPublisher/ Change ZPublisher behavior to catch AttributeError and KeyError on

Sidnei da Silva sidnei at awkly.org
Mon Oct 4 16:55:50 EDT 2004


Log message for revision 27745:
  Change ZPublisher behavior to catch AttributeError and KeyError on
  __bobo_traverse__ and then fallback to attribute and item access if
  such an exception is caught. Added some tests to verify the behavior.
  
  


Changed:
  U   Zope/branches/dc-bobo_traverse-branch/lib/python/ZPublisher/BaseRequest.py
  U   Zope/branches/dc-bobo_traverse-branch/lib/python/ZPublisher/tests/testBaseRequest.py


-=-
Modified: Zope/branches/dc-bobo_traverse-branch/lib/python/ZPublisher/BaseRequest.py
===================================================================
--- Zope/branches/dc-bobo_traverse-branch/lib/python/ZPublisher/BaseRequest.py	2004-10-04 20:44:01 UTC (rev 27744)
+++ Zope/branches/dc-bobo_traverse-branch/lib/python/ZPublisher/BaseRequest.py	2004-10-04 20:55:50 UTC (rev 27745)
@@ -308,15 +308,20 @@
                           "Object name begins with an underscore at: %s" % URL)
                     else: return response.forbiddenError(entry_name)
 
-                if hasattr(object,'__bobo_traverse__'):
-                    subobject=object.__bobo_traverse__(request,entry_name)
-                    if type(subobject) is type(()) and len(subobject) > 1:
-                        # Add additional parents into the path
-                        parents[-1:] = list(subobject[:-1])
-                        object, subobject = subobject[-2:]
-                else:
+                bobo_got = 0
+                try:
+                    if hasattr(object,'__bobo_traverse__'):
+                        subobject=object.__bobo_traverse__(request,entry_name)
+                        bobo_got = 1
+                        if type(subobject) is type(()) and len(subobject) > 1:
+                            # Add additional parents into the path
+                            parents[-1:] = list(subobject[:-1])
+                            object, subobject = subobject[-2:]
+                except (AttributeError, KeyError):
+                    pass
+
+                if not bobo_got:
                     try:
-
                         # Note - no_acquire_flag is necessary to support
                         # things like DAV.  We have to make sure
                         # that the target object is not acquired
@@ -362,7 +367,7 @@
                 # certain mutable types (dicts, lists) to become publishable
                 # when they shouldn't be. The following check makes sure that
                 # the right thing happens in both 2.2.2+ and earlier versions.
-                
+
                 if not typeCheck(subobject):
                     return response.debugError(
                         "The object at %s is not publishable." % URL

Modified: Zope/branches/dc-bobo_traverse-branch/lib/python/ZPublisher/tests/testBaseRequest.py
===================================================================
--- Zope/branches/dc-bobo_traverse-branch/lib/python/ZPublisher/tests/testBaseRequest.py	2004-10-04 20:44:01 UTC (rev 27744)
+++ Zope/branches/dc-bobo_traverse-branch/lib/python/ZPublisher/tests/testBaseRequest.py	2004-10-04 20:55:50 UTC (rev 27745)
@@ -43,6 +43,24 @@
         REQUEST._hacked_path=1
 
 
+class DummyObjectWithBBT(DummyObjectBasic):
+    """ Dummy class with docstring.
+    """
+
+    def __bobo_traverse__(self, REQUEST, name):
+        raise AttributeError, name
+
+    def dummyMethod(self):
+        """Dummy method with docstring."""
+        return 'Dummy Value'
+
+    def __getitem__(self, name):
+        if name.startswith('no_key_'):
+            raise KeyError, name
+        name = name.replace('key_', '')
+        return getattr(self, name)
+
+
 class DummyObjectWithBD(DummyObjectBasic):
     """Dummy class with docstring."""
 
@@ -53,7 +71,14 @@
             raise RuntimeError('Infinite loop detected.')
         return self, self._default_path
 
+class DummyObjectWithBDBBT(DummyObjectWithBD):
+    """Dummy class with docstring."""
 
+    def __bobo_traverse__(self, REQUEST, name):
+        if name == self.default_path[0]:
+            return getattr(self, name)
+        raise AttributeError, name
+
 class TestBaseRequest(TestCase):
 
     def setUp(self):
@@ -64,6 +89,8 @@
         self.f1._setObject('objWithDefaultNone', DummyObjectWithDefaultNone() )
         self.f1._setObject('objWithBPTH', DummyObjectWithBPTH() )
         self.f1._setObject('objWithBD', DummyObjectWithBD() )
+        self.f1._setObject('objWithBBT', DummyObjectWithBBT() )
+        self.f1._setObject('objWithBDBBT', DummyObjectWithBDBBT() )
 
     def makeBaseRequest(self):
         response = HTTPResponse()
@@ -131,6 +158,58 @@
         self.f1.objWithBD._default_path = ['']
         self.failUnlessRaises(NotFound, r.traverse, 'folder/objWithBD')
 
+    def test_traverse_withBBT_handles_AttributeError(self):
+        # Test that if __bobo_traverse__ raises AttributeError
+        # that we get a NotFound
+        from ZPublisher import NotFound
+        r = self.makeBaseRequest()
+        self.failUnlessRaises(NotFound, r.traverse, 'folder/objWithBBT/bbt_foo')
+
+    def test_traverse_withBBT_fallback_getattr(self):
+        # Test that if __bobo_traverse__ raises AttributeError
+        # that we fallback to getattr()
+        r = self.makeBaseRequest()
+        r.traverse('folder/objWithBBT/dummyMethod')
+        self.assertEqual(r.URL, '/folder/objWithBBT/dummyMethod')
+
+    def test_traverse_withBBT_fallback_getitem(self):
+        # Test that if __bobo_traverse__ raises AttributeError
+        # and getattr raises AttributeError
+        # that we fallback to __getitem__
+        r = self.makeBaseRequest()
+        r.traverse('folder/objWithBBT/key_dummyMethod')
+        self.assertEqual(r.URL, '/folder/objWithBBT/key_dummyMethod')
+
+    def test_traverse_withBBT_fallback_getitem_NotFound(self):
+        # Test that if all else fails, we get a NotFound
+        from ZPublisher import NotFound
+        r = self.makeBaseRequest()
+        self.failUnlessRaises(NotFound, r.traverse,
+                              'folder/objWithBBT/no_key_dummyMethod')
+
+    def test_traverse_withBDBBT(self):
+        # Test for an object which has a __browser_default__
+        # and __bobo_traverse__
+        # __bobo_traverse__ should return the object
+        # pointed by __browser_default__
+        r = self.makeBaseRequest()
+        self.f1.objWithBDBBT._default_path = ['view']
+        r.traverse('folder/objWithBDBBT')
+        self.assertEqual(r.URL, '/folder/objWithBDBBT/view')
+        self.assertEqual(r.response.base, '/folder/objWithBDBBT/')
+
+    def test_traverse_withBDBBT_NotFound(self):
+        # Test for an object which has a __browser_default__
+        # and __bobo_traverse__
+        # __bobo_traverse__ should raise an AttributeError, which will
+        # end up falling back to getattr, then __getitem__ to finally
+        # raise a NotFound
+        from ZPublisher import NotFound
+        r = self.makeBaseRequest()
+        self.f1.objWithBDBBT._default_path = ['xxx']
+        r = self.makeBaseRequest()
+        self.failUnlessRaises(NotFound, r.traverse, 'folder/objWithBDBBT')
+
     def test_traverse_slash(self):
         r = self.makeBaseRequest()
         r['PARENTS'] = [self.f1.objWithDefault]



More information about the Zope-Checkins mailing list