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

index d917262fd444c3256340256ca3a16ed3c9076425..2f449da0bbb6ed7b3e1f8d419d63e53c889e2e3b 100644 (file)
@@ -581,6 +581,46 @@ class TestBasicOps(unittest.TestCase):
         ids = list(map(id, list(zip_longest('abc', 'def'))))
         self.assertEqual(len(dict.fromkeys(ids)), len(ids))
 
+    def test_bug_7244(self):
+
+        class Repeater:
+            # 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 zip_longest(r1, r2, fillvalue=0):
+                with support.captured_output('stdout'):
+                    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)
+        it = zip_longest(r1, r2, fillvalue=0)
+        self.assertEqual(next(it), (1, 2))
+        self.assertEqual(next(it), (1, 2))
+        self.assertEqual(next(it), (1, 2))
+        self.assertRaises(RuntimeError, next, it)
+
     def test_product(self):
         for args, result in [
             ([], [()]),                     # zero iterables
index e979137f942d9624da2928b903610a0ceeba8c98..eda10c8aa78fd3ebf056e3f95758bfad4d638819 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -12,6 +12,9 @@ What's New in Python 3.2 Alpha 1?
 Core and Builtins
 -----------------
 
+- Issue #7244: itertools.izip_longest() no longer ignores exceptions
+  raised during the formation of an output tuple.
+
 - Issue #3297: On wide unicode builds, do not split unicode characters into
   surrogates.
 
index 12144d0c35c6189e840613941b55c3054d119b4e..1df978282ceccd5135e9dc6c4fc2cd543767e9fa 100644 (file)
@@ -3344,71 +3344,73 @@ zip_longest_traverse(ziplongestobject *lz, visitproc visit, void *arg)
 static PyObject *
 zip_longest_next(ziplongestobject *lz)
 {
-       Py_ssize_t i;
-       Py_ssize_t tuplesize = lz->tuplesize;
-       PyObject *result = lz->result;
-       PyObject *it;
-       PyObject *item;
-       PyObject *olditem;
-
-       if (tuplesize == 0)
-               return NULL;
+        Py_ssize_t i;
+        Py_ssize_t tuplesize = lz->tuplesize;
+        PyObject *result = lz->result;
+        PyObject *it;
+        PyObject *item;
+        PyObject *olditem;
+
+        if (tuplesize == 0)
+                return NULL;
         if (lz->numactive == 0)
                 return NULL;
-       if (Py_REFCNT(result) == 1) {
-               Py_INCREF(result);
-               for (i=0 ; i < tuplesize ; i++) {
-                       it = PyTuple_GET_ITEM(lz->ittuple, i);
+        if (Py_REFCNT(result) == 1) {
+                Py_INCREF(result);
+                for (i=0 ; i < tuplesize ; i++) {
+                        it = PyTuple_GET_ITEM(lz->ittuple, i);
                         if (it == NULL) {
                                 Py_INCREF(lz->fillvalue);
                                 item = lz->fillvalue;
                         } else {
-                                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 {
                                                 Py_INCREF(lz->fillvalue);
-                                                item = lz->fillvalue;                                        
+                                                item = lz->fillvalue;
                                                 PyTuple_SET_ITEM(lz->ittuple, i, NULL);
                                                 Py_DECREF(it);
                                         }
                                 }
                         }
-                       olditem = PyTuple_GET_ITEM(result, i);
-                       PyTuple_SET_ITEM(result, i, item);
-                       Py_DECREF(olditem);
-               }
-       } else {
-               result = PyTuple_New(tuplesize);
-               if (result == NULL)
-                       return NULL;
-               for (i=0 ; i < tuplesize ; i++) {
-                       it = PyTuple_GET_ITEM(lz->ittuple, i);
+                        olditem = PyTuple_GET_ITEM(result, i);
+                        PyTuple_SET_ITEM(result, i, item);
+                        Py_DECREF(olditem);
+                }
+        } else {
+                result = PyTuple_New(tuplesize);
+                if (result == NULL)
+                        return NULL;
+                for (i=0 ; i < tuplesize ; i++) {
+                        it = PyTuple_GET_ITEM(lz->ittuple, i);
                         if (it == NULL) {
                                 Py_INCREF(lz->fillvalue);
                                 item = lz->fillvalue;
                         } else {
-                                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 {
                                                 Py_INCREF(lz->fillvalue);
-                                                item = lz->fillvalue;                                        
+                                                item = lz->fillvalue;
                                                 PyTuple_SET_ITEM(lz->ittuple, i, NULL);
                                                 Py_DECREF(it);
                                         }
                                 }
                         }
-                       PyTuple_SET_ITEM(result, i, item);
-               }
-       }
-       return result;
+                        PyTuple_SET_ITEM(result, i, item);
+                }
+        }
+        return result;
 }
 
 PyDoc_STRVAR(zip_longest_doc,