SF #950057: itertools.chain doesn't "process" exceptions as they occur

Both cycle() and chain() were handling exceptions only when switching
input sources.  The patch makes the handle more immediate.

Will backport.
This commit is contained in:
Raymond Hettinger 2004-05-08 19:49:42 +00:00
parent ffa5a5015a
commit 9d7c870c6d
2 changed files with 42 additions and 0 deletions

View File

@ -644,6 +644,36 @@ class RegressionTests(unittest.TestCase):
self.assertEqual(first, second) self.assertEqual(first, second)
def test_sf_950057(self):
# Make sure that chain() and cycle() catch exceptions immediately
# rather than when shifting between input sources
def gen1():
hist.append(0)
yield 1
hist.append(1)
assert False
hist.append(2)
def gen2(x):
hist.append(3)
yield 2
hist.append(4)
if x:
raise StopIteration
hist = []
self.assertRaises(AssertionError, list, chain(gen1(), gen2(False)))
self.assertEqual(hist, [0,1])
hist = []
self.assertRaises(AssertionError, list, chain(gen1(), gen2(True)))
self.assertEqual(hist, [0,1])
hist = []
self.assertRaises(AssertionError, list, cycle(gen1()))
self.assertEqual(hist, [0,1])
libreftest = """ Doctest for examples in the library reference: libitertools.tex libreftest = """ Doctest for examples in the library reference: libitertools.tex

View File

@ -699,6 +699,12 @@ cycle_next(cycleobject *lz)
PyList_Append(lz->saved, item); PyList_Append(lz->saved, item);
return item; return item;
} }
if (PyErr_Occurred()) {
if (PyErr_ExceptionMatches(PyExc_StopIteration))
PyErr_Clear();
else
return NULL;
}
if (PyList_Size(lz->saved) == 0) if (PyList_Size(lz->saved) == 0)
return NULL; return NULL;
it = PyObject_GetIter(lz->saved); it = PyObject_GetIter(lz->saved);
@ -1658,6 +1664,12 @@ chain_next(chainobject *lz)
item = PyIter_Next(it); item = PyIter_Next(it);
if (item != NULL) if (item != NULL)
return item; return item;
if (PyErr_Occurred()) {
if (PyErr_ExceptionMatches(PyExc_StopIteration))
PyErr_Clear();
else
return NULL;
}
lz->iternum++; lz->iternum++;
} }
return NULL; return NULL;