# 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,
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)
MAKE_FUNCTION
SET_FUNCTION_ATTRIBUTE 8 (closure)
LOAD_DEREF 1 (y)
+ GET_ITER
CALL 0
CALL 1
RETURN_VALUE
#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 = [
>>> 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)
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):
--- /dev/null
+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.
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 */
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,
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)) {
}
Py_CLEAR(co);
- VISIT(c, expr, outermost->iter);
+ if (compiler_comprehension_iter(c, outermost)) {
+ goto error;
+ }
ADDOP_I(c, loc, CALL, 0);