diff options
author | Raymond Hettinger <python@rcn.com> | 2009-11-01 20:45:16 (GMT) |
---|---|---|
committer | Raymond Hettinger <python@rcn.com> | 2009-11-01 20:45:16 (GMT) |
commit | fa7dadd339ab1d69f846fd4f7a4bf0d5882fc7c3 (patch) | |
tree | f6e9081807f8055f5f923369e3d854cfb87a3b0c | |
parent | 38f5d8fcc24f0ec04b8171cbde62d50238b69fa8 (diff) | |
download | cpython-fa7dadd339ab1d69f846fd4f7a4bf0d5882fc7c3.zip cpython-fa7dadd339ab1d69f846fd4f7a4bf0d5882fc7c3.tar.gz cpython-fa7dadd339ab1d69f846fd4f7a4bf0d5882fc7c3.tar.bz2 |
Fix exception handling in itertools.izip_longest().
-rw-r--r-- | Lib/test/test_itertools.py | 40 | ||||
-rw-r--r-- | Misc/NEWS | 3 | ||||
-rw-r--r-- | Modules/itertoolsmodule.c | 72 |
3 files changed, 80 insertions, 35 deletions
diff --git a/Lib/test/test_itertools.py b/Lib/test/test_itertools.py index f88b094..f8bdb8b 100644 --- a/Lib/test/test_itertools.py +++ b/Lib/test/test_itertools.py @@ -571,6 +571,46 @@ 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): + with test_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 = izip_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 @@ -15,6 +15,9 @@ Core and Builtins - Remove length limitation when constructing a complex number from a unicode string. +- Issue #7244: itertools.izip_longest() no longer ignores exceptions + raised during the formation of an output tuple. + - Issue #1087418: Boost performance of bitwise operations for longs. - Issue #1722344: threading._shutdown() is now called in Py_Finalize(), which diff --git a/Modules/itertoolsmodule.c b/Modules/itertoolsmodule.c index 64e3606..f12d874 100644 --- a/Modules/itertoolsmodule.c +++ b/Modules/itertoolsmodule.c @@ -3865,71 +3865,73 @@ izip_longest_traverse(iziplongestobject *lz, visitproc visit, void *arg) static PyObject * izip_longest_next(iziplongestobject *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(izip_longest_doc, |