Index: Lib/test/test_iter.py =================================================================== --- Lib/test/test_iter.py (revision 66030) +++ Lib/test/test_iter.py (working copy) @@ -120,6 +120,13 @@ def test_seq_class_iter(self): self.check_iterator(iter(SequenceClass(10)), range(10)) + # Test a new_style class with __iter__ but no next() method + def test_new_style_iter_class(self): + class IterClass(object): + def __iter__(self): + return self + self.assertRaises(TypeError, iter, IterClass()) + # Test two-argument iter() with callable instance def test_iter_callable(self): class C: @@ -877,7 +884,22 @@ self.assertEqual(list(b), zip(range(5), range(5))) self.assertEqual(list(b), []) + def test_3720(self): + # Avoid a crash, when an iterator deletes its next() method. + class BadIterator(object): + def __iter__(self): + return self + def next(self): + del BadIterator.next + return 1 + try: + for i in BadIterator() : + pass + except TypeError: + pass + + def test_main(): run_unittest(TestCase) Index: Include/object.h =================================================================== --- Include/object.h (revision 66030) +++ Include/object.h (working copy) @@ -472,6 +472,7 @@ PyAPI_FUNC(int) PyObject_HasAttr(PyObject *, PyObject *); PyAPI_FUNC(PyObject **) _PyObject_GetDictPtr(PyObject *); PyAPI_FUNC(PyObject *) PyObject_SelfIter(PyObject *); +PyAPI_FUNC(PyObject *) PyObject_NextNotImplemented(PyObject *); PyAPI_FUNC(PyObject *) PyObject_GenericGetAttr(PyObject *, PyObject *); PyAPI_FUNC(int) PyObject_GenericSetAttr(PyObject *, PyObject *, PyObject *); Index: Include/abstract.h =================================================================== --- Include/abstract.h (revision 66030) +++ Include/abstract.h (working copy) @@ -636,7 +636,8 @@ #define PyIter_Check(obj) \ (PyType_HasFeature((obj)->ob_type, Py_TPFLAGS_HAVE_ITER) && \ - (obj)->ob_type->tp_iternext != NULL) + (obj)->ob_type->tp_iternext != NULL && \ + (obj)->ob_type->tp_iternext != &PyObject_NextNotImplemented) PyAPI_FUNC(PyObject *) PyIter_Next(PyObject *); /* Takes an iterator object and calls its tp_iternext slot, Index: Objects/object.c =================================================================== --- Objects/object.c (revision 66030) +++ Objects/object.c (working copy) @@ -1286,6 +1286,15 @@ return obj; } +PyObject * +PyObject_NextNotImplemented(PyObject *self) +{ + PyErr_Format(PyExc_TypeError, + "'%.200s' object is not iterable", + Py_TYPE(self)->tp_name); + return NULL; +} + /* Generic GetAttr functions - put these in your tp_[gs]etattro slot */ PyObject * Index: Objects/typeobject.c =================================================================== --- Objects/typeobject.c (revision 66030) +++ Objects/typeobject.c (working copy) @@ -6012,8 +6012,12 @@ } do { descr = _PyType_Lookup(type, p->name_strobj); - if (descr == NULL) + if (descr == NULL) { + if (ptr == (void**)&type->tp_iternext) { + specific = PyObject_NextNotImplemented; + } continue; + } if (Py_TYPE(descr) == &PyWrapperDescr_Type) { void **tptr = resolve_slotdups(type, p->name_strobj); if (tptr == NULL || tptr == ptr) Index: Objects/abstract.c =================================================================== --- Objects/abstract.c (revision 66030) +++ Objects/abstract.c (working copy) @@ -3056,7 +3056,6 @@ PyIter_Next(PyObject *iter) { PyObject *result; - assert(PyIter_Check(iter)); result = (*iter->ob_type->tp_iternext)(iter); if (result == NULL && PyErr_Occurred() && Index: Modules/itertoolsmodule.c =================================================================== --- Modules/itertoolsmodule.c (revision 66030) +++ Modules/itertoolsmodule.c (working copy) @@ -886,7 +886,6 @@ long ok; PyObject *(*iternext)(PyObject *); - assert(PyIter_Check(it)); iternext = *Py_TYPE(it)->tp_iternext; for (;;) { item = iternext(it); @@ -1031,7 +1030,6 @@ if (lz->stop == 1) return NULL; - assert(PyIter_Check(it)); item = (*Py_TYPE(it)->tp_iternext)(it); if (item == NULL) return NULL; @@ -1218,7 +1216,6 @@ Py_ssize_t oldnext; PyObject *(*iternext)(PyObject *); - assert(PyIter_Check(it)); iternext = *Py_TYPE(it)->tp_iternext; while (lz->cnt < lz->next) { item = iternext(it); @@ -1229,7 +1226,6 @@ } if (lz->stop != -1 && lz->cnt >= lz->stop) return NULL; - assert(PyIter_Check(it)); item = iternext(it); if (item == NULL) return NULL; @@ -1361,7 +1357,6 @@ PyObject *result; PyObject *it = lz->it; - assert(PyIter_Check(it)); args = (*Py_TYPE(it)->tp_iternext)(it); if (args == NULL) return NULL; @@ -2585,7 +2580,6 @@ long ok; PyObject *(*iternext)(PyObject *); - assert(PyIter_Check(it)); iternext = *Py_TYPE(it)->tp_iternext; for (;;) { item = iternext(it); @@ -2729,7 +2723,6 @@ long ok; PyObject *(*iternext)(PyObject *); - assert(PyIter_Check(it)); iternext = *Py_TYPE(it)->tp_iternext; for (;;) { item = iternext(it); @@ -3067,7 +3060,6 @@ Py_INCREF(result); for (i=0 ; i < tuplesize ; i++) { it = PyTuple_GET_ITEM(lz->ittuple, i); - assert(PyIter_Check(it)); item = (*Py_TYPE(it)->tp_iternext)(it); if (item == NULL) { Py_DECREF(result); @@ -3083,7 +3075,6 @@ return NULL; for (i=0 ; i < tuplesize ; i++) { it = PyTuple_GET_ITEM(lz->ittuple, i); - assert(PyIter_Check(it)); item = (*Py_TYPE(it)->tp_iternext)(it); if (item == NULL) { Py_DECREF(result); @@ -3419,7 +3410,6 @@ Py_INCREF(lz->fillvalue); item = lz->fillvalue; } else { - assert(PyIter_Check(it)); item = (*Py_TYPE(it)->tp_iternext)(it); if (item == NULL) { lz->numactive -= 1; @@ -3448,7 +3438,6 @@ Py_INCREF(lz->fillvalue); item = lz->fillvalue; } else { - assert(PyIter_Check(it)); item = (*Py_TYPE(it)->tp_iternext)(it); if (item == NULL) { lz->numactive -= 1;