Skip to content

Commit 1b7d965

Browse files
committed
Fix use of asend() instead of __anext__() for None values.
1 parent 84f9706 commit 1b7d965

2 files changed

Lines changed: 68 additions & 38 deletions

File tree

Lib/test/test_async_yield_from.py

Lines changed: 31 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -976,23 +976,23 @@ async def two():
976976
self.assertEqual(res, [0, 1, 2, 3])
977977
raise
978978

979-
# @_async_test
980-
# async def test_delegating_generators_claim_to_be_running_with_aclose(self):
981-
# # Check with close
982-
# class MyIt:
983-
# def __aiter__(self):
984-
# return self
985-
# async def __anext__(self):
986-
# return 42
987-
# async def aclose(self_):
988-
# self.assertTrue(g1.gi_running)
989-
# with self.assertRaises(RuntimeError):
990-
# await anext(g1)
991-
# async def one():
992-
# async yield from MyIt()
993-
# g1 = one()
994-
# await anext(g1)
995-
# await g1.aclose()
979+
@_async_test
980+
async def test_delegating_generators_claim_to_be_running_with_aclose(self):
981+
# Check with close
982+
class MyIt:
983+
def __aiter__(self):
984+
return self
985+
async def __anext__(self):
986+
return 42
987+
async def aclose(self_):
988+
self.assertTrue(g1.gi_running)
989+
with self.assertRaises(RuntimeError):
990+
await anext(g1)
991+
async def one():
992+
async yield from MyIt()
993+
g1 = one()
994+
await anext(g1)
995+
await g1.aclose()
996996

997997
@_async_test
998998
async def test_delegator_is_visible_to_debugger(self):
@@ -1016,20 +1016,20 @@ async def eggs(g):
10161016
async for stack in spam(eggs(gen())):
10171017
self.assertTrue('spam' in stack and 'eggs' in stack)
10181018

1019-
# @_async_test
1020-
# async def test_custom_iterator_return(self):
1021-
# # See issue #15568
1022-
# class MyIter:
1023-
# def __aiter__(self):
1024-
# return self
1025-
# async def __anext__(self):
1026-
# raise StopAsyncIteration(42)
1027-
# async def gen():
1028-
# nonlocal ret
1029-
# ret = async yield from MyIter()
1030-
# ret = None
1031-
# [e async for e in gen()]
1032-
# self.assertEqual(ret, 42)
1019+
@_async_test
1020+
async def test_custom_iterator_return(self):
1021+
# See issue #15568
1022+
class MyIter:
1023+
def __aiter__(self):
1024+
return self
1025+
async def __anext__(self):
1026+
raise StopAsyncIteration(42)
1027+
async def gen():
1028+
nonlocal ret
1029+
ret = async yield from MyIter()
1030+
ret = None
1031+
[e async for e in gen()]
1032+
self.assertEqual(ret, 42)
10331033

10341034
@_async_test
10351035
async def test_close_with_cleared_frame(self):

Python/codegen.c

Lines changed: 37 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -515,27 +515,36 @@ codegen_async_yield_from(compiler *c, location loc, expr_ty e)
515515
{
516516
NEW_JUMP_TARGET_LABEL(c, send);
517517
NEW_JUMP_TARGET_LABEL(c, exit);
518-
518+
NEW_JUMP_TARGET_LABEL(c, use_anext);
519+
NEW_JUMP_TARGET_LABEL(c, got_coroutine);
519520

520521
// ADDOP_NAME(c, loc, LOAD_ATTR, &_Py_ID(__aiter__), names);
521522
// ADDOP(c, loc, PUSH_NULL);
522523
// ADDOP_I(c, loc, CALL, 0);
523524
VISIT(c, expr, e->v.AsyncYieldFrom.value);
524525
// Stack: [value]
525526

526-
// Call value.__aiter__()
527527
ADDOP_NAME(c, loc, LOAD_ATTR, &_Py_ID(__aiter__), names);
528528
ADDOP(c, loc, PUSH_NULL);
529529
ADDOP_I(c, loc, CALL, 0);
530+
// Stack: [aiterator]
530531

531532
ADDOP_LOAD_CONST(c, loc, Py_None);
532533
// Stack: [aiterator, None]
533534

534535
USE_LABEL(c, send);
535-
// Virtual try/except for the StopIteration; see above.
536-
ADDOP_JUMP(c, loc, SETUP_FINALLY, exit);
537536

538537
// Stack: [aiterator, asend_value]
538+
ADDOP_I(c, loc, COPY, 1);
539+
// Stack: [aiterator, asend_value, asend_value]
540+
541+
ADDOP_LOAD_CONST(c, loc, Py_None);
542+
// Stack: [aiterator, asend_value, asend_value, None]
543+
544+
ADDOP_I(c, loc, IS_OP, 0);
545+
// Stack: [aiterator, asend_value, bool]
546+
547+
ADDOP_JUMP(c, loc, POP_JUMP_IF_TRUE, use_anext);
539548

540549
ADDOP_I(c, loc, COPY, 2);
541550
// Stack: [aiterator, asend_value, aiterator]
@@ -555,6 +564,28 @@ codegen_async_yield_from(compiler *c, location loc, expr_ty e)
555564
ADDOP_I(c, loc, CALL, 1);
556565
// Stack: [aiterator, coroutine]
557566

567+
ADDOP_JUMP(c, loc, JUMP_NO_INTERRUPT, got_coroutine);
568+
569+
USE_LABEL(c, use_anext);
570+
// Stack: [aiterator, asend_value]
571+
572+
ADDOP(c, loc, POP_TOP);
573+
// Stack: [aiterator]
574+
575+
ADDOP_I(c, loc, COPY, 1);
576+
// Stack: [aiterator, aiterator]
577+
578+
ADDOP_NAME(c, loc, LOAD_ATTR, &_Py_ID(__anext__), names);
579+
ADDOP(c, loc, PUSH_NULL);
580+
ADDOP_I(c, loc, CALL, 0);
581+
// Stack: [aiterator, coroutine]
582+
583+
USE_LABEL(c, got_coroutine);
584+
// Stack: [aiterator, coroutine]
585+
586+
// Virtual try/except for the StopAsyncIteration
587+
ADDOP_JUMP(c, loc, SETUP_FINALLY, exit);
588+
558589
ADDOP(c, loc, PUSH_NULL);
559590
ADDOP_LOAD_CONST(c, loc, Py_None);
560591
// Stack: [aiterator, coroutine, NULL, None]
@@ -575,14 +606,13 @@ codegen_async_yield_from(compiler *c, location loc, expr_ty e)
575606
ADDOP_I(c, loc, YIELD_VALUE, 1);
576607
// Stack: [aiterator, aiterator, resumed_value]
577608

609+
ADDOP(c, NO_LOCATION, POP_BLOCK);
610+
578611
ADDOP_I(c, loc, SWAP, 2);
579612
// Stack: [aiterator, resumed_value, aiterator]
580613
ADDOP(c, loc, POP_TOP);
581614
// Stack: [aiterator, resumed_value]
582615

583-
ADDOP(c, NO_LOCATION, POP_BLOCK);
584-
// Stack: [aiterator, resumed_value]
585-
586616
ADDOP_JUMP(c, loc, JUMP_NO_INTERRUPT, send);
587617

588618
USE_LABEL(c, exit);

0 commit comments

Comments
 (0)