[Jython-checkins] jython: Merged PR #49 github.com/jythontools/jython/pull/49, which fixes issue #2523

stefan.richthofer jython-checkins at python.org
Thu Jan 12 08:49:42 EST 2017


https://hg.python.org/jython/rev/509d0ba0a3e4
changeset:   8006:509d0ba0a3e4
user:        Stefan Richthofer <stefan.richthofer at gmx.de>
date:        Thu Jan 12 14:49:34 2017 +0100
summary:
  Merged PR #49 github.com/jythontools/jython/pull/49, which fixes issue #2523 defaultdict.__getitem__() does not propagate exceptions raised by calling default_factory

files:
  Lib/test/test_defaultdict_jy.py                        |  35 +++++++++-
  NEWS                                                   |   2 +
  src/org/python/modules/_collections/PyDefaultDict.java |  18 ++++-
  3 files changed, 51 insertions(+), 4 deletions(-)


diff --git a/Lib/test/test_defaultdict_jy.py b/Lib/test/test_defaultdict_jy.py
--- a/Lib/test/test_defaultdict_jy.py
+++ b/Lib/test/test_defaultdict_jy.py
@@ -101,6 +101,7 @@
 
 
 class UnhashableKeyRaiseTypeErrorTestCase(unittest.TestCase):
+    # http://bugs.jython.org/issue2522
 
     def test_setitem_raises_typeerror(self):
         self.assertRaises(TypeError, defaultdict(int).__setitem__, {}, 1)
@@ -110,8 +111,7 @@
 
 
 class GetVariantsTestCase(unittest.TestCase):
-
-    #http://bugs.jython.org/issue2133
+    # http://bugs.jython.org/issue2133
 
     def test_get_does_not_vivify(self):
         d = defaultdict(list)
@@ -129,6 +129,34 @@
         self.assertEquals(d.items(), [("vivify", [])]) 
 
 
+class GetItemPropagateWhateverMissingRaisedTestCase(unittest.TestCase):
+    # http://bugs.jython.org/issue2523
+
+    def test_getitem_propagate_default_factory_raises(self):
+
+        class FooError(Exception):
+            pass
+
+        def defaultfactory():
+            raise FooError()
+
+        d = defaultdict(defaultfactory)
+        self.assertRaises(FooError, d.__getitem__, 'bar')
+
+    def test_getitem_propagate_overridden_missing_raises(self):
+
+        class FooError(Exception):
+            pass
+
+        class DefaultDict(defaultdict):
+
+            def __missing__(self, key):
+                raise FooError()
+
+        d = DefaultDict(int)
+        self.assertRaises(FooError, d.__getitem__, 'bar')
+
+
 class OverrideMissingTestCase(unittest.TestCase):
     class KeyDefaultDict(defaultdict):
         """defaultdict to pass the requested key to factory function."""
@@ -163,7 +191,8 @@
 def test_main():
     test_support.run_unittest(PickleTestCase, ThreadSafetyTestCase,
             UnhashableKeyRaiseTypeErrorTestCase,
-            GetVariantsTestCase, OverrideMissingTestCase)
+            GetVariantsTestCase, OverrideMissingTestCase,
+            GetItemPropagateWhateverMissingRaisedTestCase)
 
 
 if __name__ == '__main__':
diff --git a/NEWS b/NEWS
--- a/NEWS
+++ b/NEWS
@@ -4,6 +4,8 @@
 
 Jython 2.7.1rc1
   Bugs fixed
+    - [ 2523 ] defaultdict.__getitem__() does not propagate exceptions raised by calling
+               default_factory
     - [ 2522 ] defaultdict.__getitem__(unhashable) raises KeyError instead of TypeError
     - [ 2515 ] typing module doesn't import
     - [ 2538 ] Test failures in test_unittest
diff --git a/src/org/python/modules/_collections/PyDefaultDict.java b/src/org/python/modules/_collections/PyDefaultDict.java
--- a/src/org/python/modules/_collections/PyDefaultDict.java
+++ b/src/org/python/modules/_collections/PyDefaultDict.java
@@ -57,7 +57,11 @@
         backingMap = CacheBuilder.newBuilder().build(
                 new CacheLoader<PyObject, PyObject>() {
                     public PyObject load(PyObject key) {
-                        return __missing__(key);
+                        try {
+                            return __missing__(key);
+                        } catch (RuntimeException ex) {
+                            throw new MissingThrownException(ex);
+                        }
                     }
                 });
     }
@@ -170,6 +174,10 @@
              * caller as it is. */
             throw pe;
         } catch (Exception ex) {
+            Throwable cause = ex.getCause();
+            if (cause != null && cause instanceof MissingThrownException) {
+                throw ((MissingThrownException) cause).thrownByMissing;
+            }
             throw Py.KeyError(key);
         }
     }
@@ -224,4 +232,12 @@
         }
         return backingMap.asMap().containsKey(ob) || backingMap.asMap().containsValue(ob);
     }
+
+    private static class MissingThrownException extends RuntimeException {
+        final RuntimeException thrownByMissing;
+        MissingThrownException(RuntimeException thrownByMissing) {
+            super(thrownByMissing);
+            this.thrownByMissing = thrownByMissing;
+        }
+    }
 }

-- 
Repository URL: https://hg.python.org/jython


More information about the Jython-checkins mailing list