From 15beb579dbcd932ef5347a6b86e32009e0a1db1f Mon Sep 17 00:00:00 2001 From: Thomas Wouters Date: Wed, 11 Jun 2025 15:53:56 +0200 Subject: [PATCH 1/2] Roll back commits c6af7f4bf7edc9924efbaa7352c4eb636258d072 (GH-134799), 814ac0d58789fd544855a6c1afb9d89a690a0c3b (GH-134788) and 132bdf6990003df61d30c379a12c041010d00245 (GH-132384), which changed bytecode (not allowed in patch releases) and semantics (also problematic in patch releases). This reopens GH-127682 as an issue. --- Lib/test/test_coroutines.py | 25 ------------------------- Lib/test/test_dis.py | 2 ++ Lib/test/test_generators.py | 22 ---------------------- Lib/test/test_genexps.py | 9 +++++++++ Lib/test/test_listcomps.py | 22 ---------------------- Python/compile.c | 21 ++++++++++++++++++--- 6 files changed, 29 insertions(+), 72 deletions(-) diff --git a/Lib/test/test_coroutines.py b/Lib/test/test_coroutines.py index 77cdbf98067e8c..f705f4f5bfbd88 100644 --- a/Lib/test/test_coroutines.py +++ b/Lib/test/test_coroutines.py @@ -2252,31 +2252,6 @@ def c(): # before fixing, visible stack from throw would be shorter than from send. self.assertEqual(len_send, len_throw) - def test_call_aiter_once_in_comprehension(self): - - class Iterator: - - def __init__(self): - self.val = 0 - - async def __anext__(self): - if self.val == 2: - raise StopAsyncIteration - self.val += 1 - return self.val - - # No __aiter__ method - - class C: - - def __aiter__(self): - return Iterator() - - async def run(): - return [i async for i in C()] - - self.assertEqual(run_async(run()), ([], [1,2])) - @unittest.skipIf( support.is_emscripten or support.is_wasi, diff --git a/Lib/test/test_dis.py b/Lib/test/test_dis.py index 51e00418165467..73807d7fa95fbd 100644 --- a/Lib/test/test_dis.py +++ b/Lib/test/test_dis.py @@ -184,6 +184,7 @@ def bug1333982(x=[]): LOAD_CONST 1 ( at 0x..., file "%s", line %d>) MAKE_FUNCTION LOAD_FAST 0 (x) + GET_ITER CALL 0 %3d LOAD_CONST 2 (1) @@ -764,6 +765,7 @@ def foo(x): MAKE_FUNCTION SET_FUNCTION_ATTRIBUTE 8 (closure) LOAD_DEREF 1 (y) + GET_ITER CALL 0 CALL 1 RETURN_VALUE diff --git a/Lib/test/test_generators.py b/Lib/test/test_generators.py index a6c1dd62a23cc3..515fe7407f1d80 100644 --- a/Lib/test/test_generators.py +++ b/Lib/test/test_generators.py @@ -246,28 +246,6 @@ def loop(): #This should not raise loop() - def test_genexpr_only_calls_dunder_iter_once(self): - - class Iterator: - - def __init__(self): - self.val = 0 - - def __next__(self): - if self.val == 2: - raise StopIteration - self.val += 1 - return self.val - - # No __iter__ method - - class C: - - def __iter__(self): - return Iterator() - - self.assertEqual([1,2], list(i for i in C())) - class ModifyUnderlyingIterableTest(unittest.TestCase): iterables = [ diff --git a/Lib/test/test_genexps.py b/Lib/test/test_genexps.py index bb241837bd6679..4f2d3cdcc7943e 100644 --- a/Lib/test/test_genexps.py +++ b/Lib/test/test_genexps.py @@ -123,6 +123,15 @@ >>> list(g) [0, 1, 4, 9, 16, 25, 36, 49, 64, 81] +Verify that the outermost for-expression makes an immediate check +for iterability + + >>> (i for i in 6) + Traceback (most recent call last): + File "", line 1, in -toplevel- + (i for i in 6) + TypeError: 'int' object is not iterable + Verify late binding for the outermost if-expression >>> include = (2,4,6,8) diff --git a/Lib/test/test_listcomps.py b/Lib/test/test_listcomps.py index 23fa5ef4f43810..45644d6c092782 100644 --- a/Lib/test/test_listcomps.py +++ b/Lib/test/test_listcomps.py @@ -750,28 +750,6 @@ def iter_raises(): self.assertEqual(f.line[f.colno - indent : f.end_colno - indent], expected) - def test_only_calls_dunder_iter_once(self): - - class Iterator: - - def __init__(self): - self.val = 0 - - def __next__(self): - if self.val == 2: - raise StopIteration - self.val += 1 - return self.val - - # No __iter__ method - - class C: - - def __iter__(self): - return Iterator() - - self.assertEqual([1,2], [i for i in C()]) - __test__ = {'doctests' : doctests} def load_tests(loader, tests, pattern): diff --git a/Python/compile.c b/Python/compile.c index e9506d6d978d89..bb2c2293a38c9a 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -5501,9 +5501,9 @@ compiler_async_comprehension_generator(struct compiler *c, location loc, else { /* Sub-iter - calculate on the fly */ VISIT(c, expr, gen->iter); + ADDOP(c, LOC(gen->iter), GET_AITER); } } - ADDOP(c, LOC(gen->iter), GET_AITER); USE_LABEL(c, start); /* Runtime will push a block here, so we need to account for that */ @@ -5790,6 +5790,19 @@ pop_inlined_comprehension_state(struct compiler *c, location loc, return SUCCESS; } +static inline int +compiler_comprehension_iter(struct compiler *c, comprehension_ty comp) +{ + VISIT(c, expr, comp->iter); + if (comp->is_async) { + ADDOP(c, LOC(comp->iter), GET_AITER); + } + else { + ADDOP(c, LOC(comp->iter), GET_ITER); + } + return SUCCESS; +} + static int compiler_comprehension(struct compiler *c, expr_ty e, int type, identifier name, asdl_comprehension_seq *generators, expr_ty elt, @@ -5811,7 +5824,7 @@ compiler_comprehension(struct compiler *c, expr_ty e, int type, outermost = (comprehension_ty) asdl_seq_GET(generators, 0); if (is_inlined) { - if (compiler_visit_expr(c, outermost->iter) < 0) { + if (compiler_comprehension_iter(c, outermost)) { goto error; } if (push_inlined_comprehension_state(c, loc, entry, &inline_state)) { @@ -5897,7 +5910,9 @@ compiler_comprehension(struct compiler *c, expr_ty e, int type, } Py_CLEAR(co); - VISIT(c, expr, outermost->iter); + if (compiler_comprehension_iter(c, outermost)) { + goto error; + } ADDOP_I(c, loc, CALL, 0); From 311ca5133eca2a24fa889cb71ca8cceda3e0d8e4 Mon Sep 17 00:00:00 2001 From: "blurb-it[bot]" <43283697+blurb-it[bot]@users.noreply.github.com> Date: Wed, 11 Jun 2025 14:09:23 +0000 Subject: [PATCH 2/2] =?UTF-8?q?=F0=9F=93=9C=F0=9F=A4=96=20Added=20by=20blu?= =?UTF-8?q?rb=5Fit.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../2025-06-11-14-09-12.gh-issue-135171.VUdivl.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2025-06-11-14-09-12.gh-issue-135171.VUdivl.rst diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-06-11-14-09-12.gh-issue-135171.VUdivl.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-06-11-14-09-12.gh-issue-135171.VUdivl.rst new file mode 100644 index 00000000000000..ec8a8ca39c1365 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2025-06-11-14-09-12.gh-issue-135171.VUdivl.rst @@ -0,0 +1 @@ +Roll back changes to generator and list comprehensions that went into 3.13.4 to fix GH-127682, but which involved semantic and bytecode changes not appropriate for a bugfix release.