[Zope3-checkins] SVN: Zope3/trunk/ zope.tales.expressions.simpleTraverse would raise NameError if the

Stefan H. Holek stefan at epy.co.at
Sun Nov 20 08:23:13 EST 2005


Log message for revision 40270:
  zope.tales.expressions.simpleTraverse would raise NameError if the
  object at hand did not implement __getitem__. Changed to raise
  AttributeError instead. AttributeError is included in Undefs whereas
  NameError is not.
  

Changed:
  U   Zope3/trunk/doc/CHANGES.txt
  U   Zope3/trunk/src/zope/tales/expressions.py
  U   Zope3/trunk/src/zope/tales/tests/test_expressions.py
  A   Zope3/trunk/src/zope/tales/tests/test_traverser.py

-=-
Modified: Zope3/trunk/doc/CHANGES.txt
===================================================================
--- Zope3/trunk/doc/CHANGES.txt	2005-11-20 12:46:15 UTC (rev 40269)
+++ Zope3/trunk/doc/CHANGES.txt	2005-11-20 13:23:13 UTC (rev 40270)
@@ -154,6 +154,11 @@
 
     Bug Fixes
 
+      - zope.tales.expressions.simpleTraverse would raise NameError if the
+        object at hand did not implement __getitem__. Changed to raise
+        AttributeError instead. AttributeError is included in Undefs whereas
+        NameError is not.
+
       - Fixed bug 405, http://www.zope.org/Collectors/Zope3-dev/405
         Needed check for common bug when calling apply on field indexes.
 
@@ -206,7 +211,7 @@
       Stephan Richter, Roger Ineichen, Marius Gedminas, Julien Anguenot, Benji
       York, Gary Poster, Jim Fulton, Michael Kerrin, Torsten Kurbad,
       Philipp von Weitershausen, Tarek Ziadé, Andreas Jung, Dmitry Vasiliev,
-      Juergen Kartnaller
+      Juergen Kartnaller, Stefan Holek
 
     Note: If you are not listed and contributed, please add yourself. This
           note will be deleted before the release.

Modified: Zope3/trunk/src/zope/tales/expressions.py
===================================================================
--- Zope3/trunk/src/zope/tales/expressions.py	2005-11-20 12:46:15 UTC (rev 40269)
+++ Zope3/trunk/src/zope/tales/expressions.py	2005-11-20 13:23:13 UTC (rev 40270)
@@ -37,7 +37,8 @@
         elif hasattr(object, '__getitem__'):
             object = object[name]
         else:
-            raise NameError(name)
+            # Allow AttributError to propagate
+            object = getattr(object, name)
     return object
 
 

Modified: Zope3/trunk/src/zope/tales/tests/test_expressions.py
===================================================================
--- Zope3/trunk/src/zope/tales/tests/test_expressions.py	2005-11-20 12:46:15 UTC (rev 40269)
+++ Zope3/trunk/src/zope/tales/tests/test_expressions.py	2005-11-20 13:23:13 UTC (rev 40270)
@@ -260,7 +260,7 @@
         try:
             expr = self.engine.compile('adapterTest/namespace:title')
             expr(self.context)
-        except (NameError,KeyError),e: 
+        except KeyError,e: 
             self.assertEquals(e.args[0],'title')
         else:
             self.fail('Engine accepted unknown function')

Added: Zope3/trunk/src/zope/tales/tests/test_traverser.py
===================================================================
--- Zope3/trunk/src/zope/tales/tests/test_traverser.py	2005-11-20 12:46:15 UTC (rev 40269)
+++ Zope3/trunk/src/zope/tales/tests/test_traverser.py	2005-11-20 13:23:13 UTC (rev 40270)
@@ -0,0 +1,120 @@
+"""
+Tests for zope.tales.expressions.simpleTraverse
+
+$Id:$
+"""
+
+from unittest import TestCase, TestSuite, makeSuite, main
+from zope.tales.expressions import simpleTraverse
+
+
+class AttrTraversable(object):
+    """Traversable by attribute access"""
+    attr = 'foo'
+
+class ItemTraversable(object):
+    """Traversable by item access"""
+    def __getitem__(self, name):
+        if name == 'attr':
+            return 'foo'
+        raise KeyError, name
+
+class AllTraversable(AttrTraversable, ItemTraversable):
+    """Traversable by attribute and item access"""
+    pass
+
+
+_marker = object()
+
+def getitem(ob, name, default=_marker):
+    """Helper a la getattr(ob, name, default)."""
+    try:
+        item = ob[name]
+    except KeyError:
+        if default is not _marker:
+            return default
+        raise KeyError, name
+    else:
+        return item
+
+
+class TraverserTests(TestCase):
+
+    def testGetItem(self):
+        # getitem helper should behave like __getitem__
+        ob = {'attr': 'foo'}
+        self.assertEqual(getitem(ob, 'attr', None), 'foo')
+        self.assertEqual(getitem(ob, 'attr'), 'foo')
+        self.assertEqual(getitem(ob, 'missing_attr', None), None)
+        self.assertRaises(KeyError, getitem, ob, 'missing_attr')
+        self.assertRaises(TypeError, getitem, object(), 'attr')
+
+    def testAttrTraversable(self):
+        # An object without __getitem__ should raise AttributeError
+        # for missing attribute.
+        ob = AttrTraversable()
+        self.assertEqual(getattr(ob, 'attr', None), 'foo')
+        self.assertRaises(AttributeError, getattr, ob, 'missing_attr')
+
+    def testItemTraversable(self):
+        # An object with __getitem__ (but without attr) should raise
+        # KeyError for missing attribute.
+        ob = ItemTraversable()
+        self.assertEqual(getitem(ob, 'attr', None), 'foo')
+        self.assertRaises(KeyError, getitem, ob, 'missing_attr')
+
+    def testAllTraversable(self):
+        # An object with attr and __getitem__ should raise either
+        # exception, depending on method of access.
+        ob = AllTraversable()
+        self.assertEqual(getattr(ob, 'attr', None), 'foo')
+        self.assertRaises(AttributeError, getattr, ob, 'missing_attr')
+        self.assertEqual(getitem(ob, 'attr', None), 'foo')
+        self.assertRaises(KeyError, getitem, ob, 'missing_attr')
+
+    def testTraverseEmptyPath(self):
+        # simpleTraverse should return the original object if the path is emtpy
+        ob = object()
+        self.assertEqual(simpleTraverse(ob, [], None), ob)
+
+    def testTraverseByAttr(self):
+        # simpleTraverse should find attr through attribute access
+        ob = AttrTraversable()
+        self.assertEqual(simpleTraverse(ob, ['attr'], None), 'foo')
+
+    def testTraverseByMissingAttr(self):
+        # simpleTraverse should raise AttributeError
+        ob = AttrTraversable()
+        # Here lurks the bug (unexpected NamError raised)
+        self.assertRaises(AttributeError, simpleTraverse, ob, ['missing_attr'], None)
+
+    def testTraverseByItem(self):
+        # simpleTraverse should find attr through item access
+        ob = ItemTraversable()
+        self.assertEqual(simpleTraverse(ob, ['attr'], None), 'foo')
+
+    def testTraverseByMissingItem(self):
+        # simpleTraverse should raise KeyError
+        ob = ItemTraversable()
+        self.assertRaises(KeyError, simpleTraverse, ob, ['missing_attr'], None)
+
+    def testTraverseByAll(self):
+        # simpleTraverse should find attr through attribute access
+        ob = AllTraversable()
+        self.assertEqual(simpleTraverse(ob, ['attr'], None), 'foo')
+
+    def testTraverseByMissingAll(self):
+        # simpleTraverse should raise KeyError (because ob implements __getitem__)
+        ob = AllTraversable()
+        self.assertRaises(KeyError, simpleTraverse, ob, ['missing_attr'], None)
+
+
+def test_suite():
+    return TestSuite((
+        makeSuite(TraverserTests),
+    ))
+
+
+if __name__ == '__main__':
+    main(defaultTest='test_suite')
+


Property changes on: Zope3/trunk/src/zope/tales/tests/test_traverser.py
___________________________________________________________________
Name: svn:keywords
   + Id
Name: svn:eol-style
   + native



More information about the Zope3-Checkins mailing list