Commit 80d49b33 authored by Raymond Hettinger's avatar Raymond Hettinger

Issue 7244: fix exception handling in itertools.izip_longest().

parent e2670af0
...@@ -398,6 +398,42 @@ class TestBasicOps(unittest.TestCase): ...@@ -398,6 +398,42 @@ class TestBasicOps(unittest.TestCase):
ids = map(id, list(izip_longest('abc', 'def'))) ids = map(id, list(izip_longest('abc', 'def')))
self.assertEqual(len(dict.fromkeys(ids)), len(ids)) 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): def test_product(self):
for args, result in [ for args, result in [
([], [()]), # zero iterables ([], [()]), # zero iterables
...@@ -687,6 +723,7 @@ class TestBasicOps(unittest.TestCase): ...@@ -687,6 +723,7 @@ class TestBasicOps(unittest.TestCase):
self.assertRaises(StopIteration, f(lambda x:x, []).next) self.assertRaises(StopIteration, f(lambda x:x, []).next)
self.assertRaises(StopIteration, f(lambda x:x, StopNow()).next) self.assertRaises(StopIteration, f(lambda x:x, StopNow()).next)
class TestExamples(unittest.TestCase): class TestExamples(unittest.TestCase):
def test_chain(self): def test_chain(self):
......
...@@ -24,6 +24,9 @@ Core and Builtins ...@@ -24,6 +24,9 @@ Core and Builtins
Library 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 - 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 sure that they accept an int or long as the second argument. Also
fix buggy handling of large arguments (those with coefficient longer fix buggy handling of large arguments (those with coefficient longer
......
...@@ -3412,10 +3412,11 @@ izip_longest_next(iziplongestobject *lz) ...@@ -3412,10 +3412,11 @@ izip_longest_next(iziplongestobject *lz)
item = lz->fillvalue; item = lz->fillvalue;
} else { } else {
assert(PyIter_Check(it)); assert(PyIter_Check(it));
item = (*Py_TYPE(it)->tp_iternext)(it); item = PyIter_Next(it);
if (item == NULL) { if (item == NULL) {
lz->numactive -= 1; lz->numactive -= 1;
if (lz->numactive == 0) { if (lz->numactive == 0 || PyErr_Occurred()) {
lz->numactive = 0;
Py_DECREF(result); Py_DECREF(result);
return NULL; return NULL;
} else { } else {
...@@ -3441,10 +3442,11 @@ izip_longest_next(iziplongestobject *lz) ...@@ -3441,10 +3442,11 @@ izip_longest_next(iziplongestobject *lz)
item = lz->fillvalue; item = lz->fillvalue;
} else { } else {
assert(PyIter_Check(it)); assert(PyIter_Check(it));
item = (*Py_TYPE(it)->tp_iternext)(it); item = PyIter_Next(it);
if (item == NULL) { if (item == NULL) {
lz->numactive -= 1; lz->numactive -= 1;
if (lz->numactive == 0) { if (lz->numactive == 0 || PyErr_Occurred()) {
lz->numactive = 0;
Py_DECREF(result); Py_DECREF(result);
return NULL; return NULL;
} else { } else {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment