]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
[3.13] GH-135171: Roll back all fixes for GH-127682 as they are not suitable for...
authorT. Wouters <thomas@python.org>
Wed, 11 Jun 2025 14:57:35 +0000 (16:57 +0200)
committerGitHub <noreply@github.com>
Wed, 11 Jun 2025 14:57:35 +0000 (16:57 +0200)
Lib/test/test_coroutines.py
Lib/test/test_dis.py
Lib/test/test_generators.py
Lib/test/test_genexps.py
Lib/test/test_listcomps.py
Misc/NEWS.d/next/Core_and_Builtins/2025-06-11-14-09-12.gh-issue-135171.VUdivl.rst [new file with mode: 0644]
Python/compile.c

index 77cdbf98067e8ce7793af86c4f87c1b101794791..f705f4f5bfbd8848502184097245da8558eb7150 100644 (file)
@@ -2252,31 +2252,6 @@ class CoroutineTest(unittest.TestCase):
         # 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,
index 51e00418165467239ae47cd3783e6b739c060805..73807d7fa95fbdcde04f8018788cba1190637c11 100644 (file)
@@ -184,6 +184,7 @@ dis_bug1333982 = """\
               LOAD_CONST               1 (<code object <genexpr> 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 @@ Disassembly of <code object foo at 0x..., file "%s", line %d>:
                MAKE_FUNCTION
                SET_FUNCTION_ATTRIBUTE   8 (closure)
                LOAD_DEREF               1 (y)
+               GET_ITER
                CALL                     0
                CALL                     1
                RETURN_VALUE
index a6c1dd62a23cc3f0869e97d1d40a6d338e33a148..515fe7407f1d80e50523964cfc8822c1f9d9e587 100644 (file)
@@ -246,28 +246,6 @@ class GeneratorTest(unittest.TestCase):
         #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 = [
index bb241837bd6679c1e84f289eeaa8cd958f04ae8b..4f2d3cdcc7943eaebe7698ca556164a941142019 100644 (file)
@@ -123,6 +123,15 @@ Verify early binding for the outermost for-expression
     >>> 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 "<pyshell#4>", 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)
index 23fa5ef4f438108295eabf6763ca8a42dc0bb6e6..45644d6c0927827c4f1c3663082f1c98be5e5abb 100644 (file)
@@ -750,28 +750,6 @@ class ListComprehensionTest(unittest.TestCase):
                 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/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 (file)
index 0000000..ec8a8ca
--- /dev/null
@@ -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.
index e9506d6d978d893fd804bf4be116882e86f72b0b..bb2c2293a38c9a3fe291c96b32062f201f64180e 100644 (file)
@@ -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);