Skip to content

Commit

Permalink
pythongh-125038: Raise TypeError on such case instead of silently sto…
Browse files Browse the repository at this point in the history
…pping the loop
  • Loading branch information
efimov-mikhail committed Oct 7, 2024
1 parent 3b6e814 commit f056908
Show file tree
Hide file tree
Showing 4 changed files with 76 additions and 22 deletions.
20 changes: 16 additions & 4 deletions Lib/test/test_generators.py
Original file line number Diff line number Diff line change
Expand Up @@ -269,10 +269,22 @@ def loop():
loop()

def test_issue125038(self):
g = (x for x in range(10))
g.gi_frame.f_locals['.0'] = range(20)
l = list(g)
self.assertListEqual(l, [])
def get_generator():
g = (x for x in range(10))
g.gi_frame.f_locals['.0'] = range(20)
return g

def genexpr_to_list():
try:
l = list(get_generator())
return "NoError"
except TypeError:
return "TypeError"

# This should not raise
r = genexpr_to_list()

self.assertIs(r, "TypeError")

class ExceptionTest(unittest.TestCase):
# Tests for the issue #23353: check that the currently handled exception
Expand Down
36 changes: 27 additions & 9 deletions Python/bytecodes.c
Original file line number Diff line number Diff line change
Expand Up @@ -2804,10 +2804,16 @@ dummy_func(
replaced op(_FOR_ITER, (iter -- iter, next)) {
/* before: [iter]; after: [iter, iter()] *or* [] (and jump over END_FOR.) */
PyObject *iter_o = PyStackRef_AsPyObjectBorrow(iter);
PyObject *next_o = NULL;
if (PyIter_Check(iter_o)) {
next_o = (*Py_TYPE(iter_o)->tp_iternext)(iter_o);
PyTypeObject *type = Py_TYPE(iter_o);
iternextfunc iternext = type->tp_iternext;
if (iternext == NULL) {
_PyErr_Format(tstate, PyExc_TypeError,
"'for' requires an object with "
"__iter__ method, got %.100s",
type->tp_name);
ERROR_NO_POP();
}
PyObject *next_o = (*iternext)(iter_o);
if (next_o == NULL) {
if (_PyErr_Occurred(tstate)) {
int matches = _PyErr_ExceptionMatches(tstate, PyExc_StopIteration);
Expand All @@ -2833,10 +2839,16 @@ dummy_func(
op(_FOR_ITER_TIER_TWO, (iter -- iter, next)) {
/* before: [iter]; after: [iter, iter()] *or* [] (and jump over END_FOR.) */
PyObject *iter_o = PyStackRef_AsPyObjectBorrow(iter);
PyObject *next_o = NULL;
if (PyIter_Check(iter_o)) {
next_o = (*Py_TYPE(iter_o)->tp_iternext)(iter_o);
PyTypeObject *type = Py_TYPE(iter_o);
iternextfunc iternext = type->tp_iternext;
if (iternext == NULL) {
_PyErr_Format(tstate, PyExc_TypeError,
"'for' requires an object with "
"__iter__ method, got %.100s",
type->tp_name);
ERROR_NO_POP();
}
PyObject *next_o = (*iternext)(iter_o);
if (next_o == NULL) {
if (_PyErr_Occurred(tstate)) {
int matches = _PyErr_ExceptionMatches(tstate, PyExc_StopIteration);
Expand All @@ -2860,10 +2872,16 @@ dummy_func(
_Py_CODEUNIT *target;
_PyStackRef iter_stackref = TOP();
PyObject *iter = PyStackRef_AsPyObjectBorrow(iter_stackref);
PyObject *next = NULL;
if (PyIter_Check(iter)) {
next = (*Py_TYPE(iter)->tp_iternext)(iter);
PyTypeObject *type = Py_TYPE(iter);
iternextfunc iternext = type->tp_iternext;
if (iternext == NULL) {
_PyErr_Format(tstate, PyExc_TypeError,
"'for' requires an object with "
"__iter__ method, got %.100s",
type->tp_name);
ERROR_NO_POP();
}
PyObject *next = (*iternext)(iter);
if (next != NULL) {
PUSH(PyStackRef_FromPyObjectSteal(next));
target = next_instr;
Expand Down
14 changes: 11 additions & 3 deletions Python/executor_cases.c.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

28 changes: 22 additions & 6 deletions Python/generated_cases.c.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit f056908

Please sign in to comment.