From: Raymond Hettinger Date: Sun, 1 Nov 2009 08:53:21 +0000 (+0000) Subject: Issue 7244: fix exception handling in itertools.izip_longest(). X-Git-Tag: v2.6.5rc1~400 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=80d49b33b12d3726baff0b3b99307457167dd67b;p=python Issue 7244: fix exception handling in itertools.izip_longest(). --- diff --git a/Lib/test/test_itertools.py b/Lib/test/test_itertools.py index d297848774..ee5af4b601 100644 --- a/Lib/test/test_itertools.py +++ b/Lib/test/test_itertools.py @@ -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): diff --git a/Misc/NEWS b/Misc/NEWS index 4ad6ca7f09..a8918dbdfa 100644 --- 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 diff --git a/Modules/itertoolsmodule.c b/Modules/itertoolsmodule.c index 5875d10458..ecd5e173da 100644 --- a/Modules/itertoolsmodule.c +++ b/Modules/itertoolsmodule.c @@ -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 {