Index: Python/bltinmodule.c =================================================================== --- Python/bltinmodule.c (revision 83896) +++ Python/bltinmodule.c (working copy) @@ -974,11 +974,10 @@ curseq = PyTuple_GetItem(args, i+1); sqp->it = PyObject_GetIter(curseq); if (sqp->it == NULL) { - static char errmsg[] = - "argument %d to map() must support iteration"; - char errbuf[sizeof(errmsg) + 25]; - PyOS_snprintf(errbuf, sizeof(errbuf), errmsg, i+2); - PyErr_SetString(PyExc_TypeError, errbuf); + if (PyErr_ExceptionMatches(PyExc_TypeError)) + PyErr_Format(PyExc_TypeError, + "argument %d to map() must support iteration", + i+2); goto Fail_2; } Index: Lib/test/test_functools.py =================================================================== --- Lib/test/test_functools.py (revision 83896) +++ Lib/test/test_functools.py (working copy) @@ -297,6 +297,9 @@ self.assertEqual(wrapper.attr, 'This is a different test') self.assertEqual(wrapper.dict_attr, f.dict_attr) +class TestFailingIter: + def __iter__(self): + raise RuntimeError class TestReduce(unittest.TestCase): @@ -337,6 +340,10 @@ self.assertEqual(reduce(42, "1"), "1") # func is never called with one item self.assertEqual(reduce(42, "", "1"), "1") # func is never called with one item self.assertRaises(TypeError, reduce, 42, (42, 42)) + class G: + pass + self.assertRaises(TypeError, reduce, lambda x, y: x+y, G()) + self.assertRaises(RuntimeError, reduce, lambda x, y: x+y, TestFailingIter()) class TestCmpToKey(unittest.TestCase): def test_cmp_to_key(self): Index: Lib/test/test_builtin.py =================================================================== --- Lib/test/test_builtin.py (revision 83896) +++ Lib/test/test_builtin.py (working copy) @@ -843,7 +843,13 @@ def badfunc(x): raise RuntimeError self.assertRaises(RuntimeError, map, badfunc, range(5)) + class G: + pass + self.assertRaises(TypeError, map, None, [], G()) + self.assertRaises(RuntimeError, map, None, [], TestFailingIter()) + + def test_max(self): self.assertEqual(max('123123'), '3') self.assertEqual(max(1, 2, 3), 3) @@ -1254,6 +1260,8 @@ self.assertRaises(TypeError, reduce, add, []) # arg 2 must not be empty sequence with no initial value self.assertRaises(TypeError, reduce, add, "") self.assertRaises(TypeError, reduce, add, ()) + self.assertRaises(TypeError, reduce, add, object()) + self.assertRaises(RuntimeError, reduce, add, TestFailingIter()) self.assertEqual(reduce(add, [], None), None) self.assertEqual(reduce(add, [], 42), 42) @@ -1475,6 +1483,7 @@ class G: pass self.assertRaises(TypeError, zip, a, G()) + self.assertRaises(RuntimeError, zip, a, TestFailingIter()) # Make sure zip doesn't try to allocate a billion elements for the # result list when one of its arguments doesn't say how long it is. Index: Modules/_functoolsmodule.c =================================================================== --- Modules/_functoolsmodule.c (revision 83896) +++ Modules/_functoolsmodule.c (working copy) @@ -23,8 +23,9 @@ it = PyObject_GetIter(seq); if (it == NULL) { - PyErr_SetString(PyExc_TypeError, - "reduce() arg 2 must support iteration"); + if (PyErr_ExceptionMatches(PyExc_TypeError)) + PyErr_SetString(PyExc_TypeError, + "reduce() arg 2 must support iteration"); Py_XDECREF(result); return NULL; }