]> granicus.if.org Git - python/commitdiff
Issue 7244: fix exception handling in itertools.izip_longest().
authorRaymond Hettinger <python@rcn.com>
Sun, 1 Nov 2009 08:53:21 +0000 (08:53 +0000)
committerRaymond Hettinger <python@rcn.com>
Sun, 1 Nov 2009 08:53:21 +0000 (08:53 +0000)
Lib/test/test_itertools.py
Misc/NEWS
Modules/itertoolsmodule.c

index d297848774812d285e1ca3d493e7bd8e74870334..ee5af4b601d797f5fc47a1e738f35d99285070c1 100644 (file)
@@ -398,6 +398,42 @@ class TestBasicOps(unittest.TestCase):
         ids = map(id, list(izip_longest('abc', 'def')))
         self.assertEqual(len(dict.fromkeys(ids)), len(ids))
 
+    def test_bug_7244(self):
+
+        class Repeater(object):
+            # this class is similar to itertools.repeat
+            def __init__(self, o, t, e):
+                self.o = o
+                self.t = int(t)
+                self.e = e
+            def __iter__(self): # its iterator is itself
+                return self
+            def next(self):
+                if self.t > 0:
+                    self.t -= 1
+                    return self.o
+                else:
+                    raise self.e
+
+        # Formerly this code in would fail in debug mode
+        # with Undetected Error and Stop Iteration
+        r1 = Repeater(1, 3, StopIteration)
+        r2 = Repeater(2, 4, StopIteration)
+        def run(r1, r2):
+            result = []
+            for i, j in izip_longest(r1, r2, fillvalue=0):
+                print(i, j)
+                result.append((i, j))
+            return result
+        self.assertEqual(run(r1, r2), [(1,2), (1,2), (1,2), (0,2)])
+
+        # Formerly, the RuntimeError would be lost
+        # and StopIteration would stop as expected
+        r1 = Repeater(1, 3, RuntimeError)
+        r2 = Repeater(2, 4, StopIteration)
+        mylist = lambda it: [v for v in it]
+        self.assertRaises(RuntimeError, mylist, izip_longest(r1, r2, fillvalue=0))
+
     def test_product(self):
         for args, result in [
             ([], [()]),                     # zero iterables
@@ -687,6 +723,7 @@ class TestBasicOps(unittest.TestCase):
             self.assertRaises(StopIteration, f(lambda x:x, []).next)
             self.assertRaises(StopIteration, f(lambda x:x, StopNow()).next)
 
+
 class TestExamples(unittest.TestCase):
 
     def test_chain(self):
index 4ad6ca7f096ad3468060687e8c6430ba06bd1458..a8918dbdfadf005e8faa2b15f7270bc0b1458540 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -24,6 +24,9 @@ Core and Builtins
 Library
 -------
 
+- Issue #7244: itertools.izip_longest() no longer ignores exceptions
+  raised during the formation of an output tuple.
+
 - Issue #7233: Fix a number of two-argument Decimal methods to make
   sure that they accept an int or long as the second argument.  Also
   fix buggy handling of large arguments (those with coefficient longer
index 5875d1045800602a245cedde662f7a2ae6dc52b6..ecd5e173da1885424b7f75b6ea6675a4ed42b7d4 100644 (file)
@@ -3412,10 +3412,11 @@ izip_longest_next(iziplongestobject *lz)
                                 item = lz->fillvalue;
                         } else {
                                 assert(PyIter_Check(it));
-                                item = (*Py_TYPE(it)->tp_iternext)(it);
+                                item = PyIter_Next(it);
                                 if (item == NULL) {
-                                        lz->numactive -= 1;      
-                                        if (lz->numactive == 0) {
+                                        lz->numactive -= 1;
+                                        if (lz->numactive == 0 || PyErr_Occurred()) {
+                                                                                               lz->numactive = 0;
                                                 Py_DECREF(result);
                                                 return NULL;
                                         } else {
@@ -3441,10 +3442,11 @@ izip_longest_next(iziplongestobject *lz)
                                 item = lz->fillvalue;
                         } else {
                                 assert(PyIter_Check(it));
-                                item = (*Py_TYPE(it)->tp_iternext)(it);
+                                item = PyIter_Next(it);
                                 if (item == NULL) {
                                         lz->numactive -= 1;      
-                                        if (lz->numactive == 0) {
+                                        if (lz->numactive == 0 || PyErr_Occurred()) {
+                                                                                               lz->numactive = 0;
                                                 Py_DECREF(result);
                                                 return NULL;
                                         } else {