Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 41782e4

Browse files
committed
Issue #28721: Fix asynchronous generators aclose() and athrow()
1 parent a83a6a3 commit 41782e4

3 files changed

Lines changed: 154 additions & 3 deletions

File tree

Lib/test/test_asyncgen.py

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -450,6 +450,41 @@ async def run():
450450

451451
self.loop.run_until_complete(run())
452452

453+
def test_async_gen_asyncio_anext_06(self):
454+
DONE = 0
455+
456+
# test synchronous generators
457+
def foo():
458+
try:
459+
yield
460+
except:
461+
pass
462+
g = foo()
463+
g.send(None)
464+
with self.assertRaises(StopIteration):
465+
g.send(None)
466+
467+
# now with asynchronous generators
468+
469+
async def gen():
470+
nonlocal DONE
471+
try:
472+
yield
473+
except:
474+
pass
475+
DONE = 1
476+
477+
async def run():
478+
nonlocal DONE
479+
g = gen()
480+
await g.asend(None)
481+
with self.assertRaises(StopAsyncIteration):
482+
await g.asend(None)
483+
DONE += 10
484+
485+
self.loop.run_until_complete(run())
486+
self.assertEqual(DONE, 11)
487+
453488
def test_async_gen_asyncio_anext_tuple(self):
454489
async def foo():
455490
try:
@@ -594,6 +629,76 @@ async def run():
594629
self.loop.run_until_complete(run())
595630
self.assertEqual(DONE, 1)
596631

632+
def test_async_gen_asyncio_aclose_10(self):
633+
DONE = 0
634+
635+
# test synchronous generators
636+
def foo():
637+
try:
638+
yield
639+
except:
640+
pass
641+
g = foo()
642+
g.send(None)
643+
g.close()
644+
645+
# now with asynchronous generators
646+
647+
async def gen():
648+
nonlocal DONE
649+
try:
650+
yield
651+
except:
652+
pass
653+
DONE = 1
654+
655+
async def run():
656+
nonlocal DONE
657+
g = gen()
658+
await g.asend(None)
659+
await g.aclose()
660+
DONE += 10
661+
662+
self.loop.run_until_complete(run())
663+
self.assertEqual(DONE, 11)
664+
665+
def test_async_gen_asyncio_aclose_11(self):
666+
DONE = 0
667+
668+
# test synchronous generators
669+
def foo():
670+
try:
671+
yield
672+
except:
673+
pass
674+
yield
675+
g = foo()
676+
g.send(None)
677+
with self.assertRaisesRegex(RuntimeError, 'ignored GeneratorExit'):
678+
g.close()
679+
680+
# now with asynchronous generators
681+
682+
async def gen():
683+
nonlocal DONE
684+
try:
685+
yield
686+
except:
687+
pass
688+
yield
689+
DONE += 1
690+
691+
async def run():
692+
nonlocal DONE
693+
g = gen()
694+
await g.asend(None)
695+
with self.assertRaisesRegex(RuntimeError, 'ignored GeneratorExit'):
696+
await g.aclose()
697+
DONE += 10
698+
699+
self.loop.run_until_complete(run())
700+
self.assertEqual(DONE, 10)
701+
597702
def test_async_gen_asyncio_asend_01(self):
598703
DONE = 0
599704

@@ -801,6 +906,41 @@ async def run():
801906
self.loop.run_until_complete(run())
802907
self.assertEqual(DONE, 1)
803908

909+
def test_async_gen_asyncio_athrow_03(self):
910+
DONE = 0
911+
912+
# test synchronous generators
913+
def foo():
914+
try:
915+
yield
916+
except:
917+
pass
918+
g = foo()
919+
g.send(None)
920+
with self.assertRaises(StopIteration):
921+
g.throw(ValueError)
922+
923+
# now with asynchronous generators
924+
925+
async def gen():
926+
nonlocal DONE
927+
try:
928+
yield
929+
except:
930+
pass
931+
DONE = 1
932+
933+
async def run():
934+
nonlocal DONE
935+
g = gen()
936+
await g.asend(None)
937+
with self.assertRaises(StopAsyncIteration):
938+
await g.athrow(ValueError)
939+
DONE += 10
940+
941+
self.loop.run_until_complete(run())
942+
self.assertEqual(DONE, 11)
943+
804944
def test_async_gen_asyncio_athrow_tuple(self):
805945
async def gen():
806946
try:

Misc/NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@ Core and Builtins
3131

3232
- Issue #26182: Fix a refleak in code that raises DeprecationWarning.
3333

34+
- Issue #28721: Fix asynchronous generators aclose() and athrow() to
35+
handle StopAsyncIteration propagation properly.
36+
3437
Library
3538
-------
3639

Objects/genobject.c

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1931,9 +1931,17 @@ async_gen_athrow_send(PyAsyncGenAThrow *o, PyObject *arg)
19311931
return NULL;
19321932

19331933
check_error:
1934-
if (PyErr_ExceptionMatches(PyExc_StopAsyncIteration)
1935-
|| PyErr_ExceptionMatches(PyExc_GeneratorExit)
1936-
) {
1934+
if (PyErr_ExceptionMatches(PyExc_StopAsyncIteration)) {
1935+
o->agt_state = AWAITABLE_STATE_CLOSED;
1936+
if (o->agt_args == NULL) {
1937+
/* when aclose() is called we don't want to propagate
1938+
StopAsyncIteration; just raise StopIteration, signalling
1939+
that 'aclose()' is done. */
1940+
PyErr_Clear();
1941+
PyErr_SetNone(PyExc_StopIteration);
1942+
}
1943+
}
1944+
else if (PyErr_ExceptionMatches(PyExc_GeneratorExit)) {
19371945
o->agt_state = AWAITABLE_STATE_CLOSED;
19381946
PyErr_Clear(); /* ignore these errors */
19391947
PyErr_SetNone(PyExc_StopIteration);

0 commit comments

Comments
 (0)