Skip to content

Commit ee3f34c

Browse files
committed
Fix _asyncgen_finalizer_hook to correctly wakeup the loop (issue #68)
1 parent 104c35b commit ee3f34c

File tree

2 files changed

+73
-18
lines changed

2 files changed

+73
-18
lines changed

tests/test_base.py

Lines changed: 72 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -498,29 +498,31 @@ def coro():
498498
self.assertFalse(isinstance(task, MyTask))
499499
self.loop.run_until_complete(task)
500500

501-
def test_shutdown_asyncgens_01(self):
502-
finalized = list()
503-
504-
if not hasattr(self.loop, 'shutdown_asyncgens'):
505-
raise unittest.SkipTest()
506-
507-
waiter_src = '''async def waiter(timeout, finalized, loop):
508-
try:
509-
await asyncio.sleep(timeout, loop=loop)
510-
yield 1
511-
finally:
512-
await asyncio.sleep(0, loop=loop)
513-
finalized.append(1)
514-
'''
515-
501+
def _compile_agen(self, src):
516502
try:
517503
g = {}
518-
exec(waiter_src, globals(), g)
504+
exec(src, globals(), g)
519505
except SyntaxError:
520506
# Python < 3.6
521507
raise unittest.SkipTest()
522508
else:
523-
waiter = g['waiter']
509+
return g['waiter']
510+
511+
def test_shutdown_asyncgens_01(self):
512+
finalized = list()
513+
514+
if not hasattr(self.loop, 'shutdown_asyncgens'):
515+
raise unittest.SkipTest()
516+
517+
waiter = self._compile_agen(
518+
'''async def waiter(timeout, finalized, loop):
519+
try:
520+
await asyncio.sleep(timeout, loop=loop)
521+
yield 1
522+
finally:
523+
await asyncio.sleep(0, loop=loop)
524+
finalized.append(1)
525+
''')
524526

525527
async def wait():
526528
async for _ in waiter(1, finalized, self.loop):
@@ -539,6 +541,59 @@ async def wait():
539541
t2.cancel()
540542
self.loop.run_until_complete(asyncio.sleep(0.1, loop=self.loop))
541543

544+
def test_shutdown_asyncgens_02(self):
545+
if not hasattr(self.loop, 'shutdown_asyncgens'):
546+
raise unittest.SkipTest()
547+
548+
logged = 0
549+
550+
def logger(loop, context):
551+
nonlocal logged
552+
self.assertIn('asyncgen', context)
553+
expected = 'an error occurred during closing of asynchronous'
554+
if expected in context['message']:
555+
logged += 1
556+
557+
waiter = self._compile_agen('''async def waiter(timeout, loop):
558+
try:
559+
await asyncio.sleep(timeout, loop=loop)
560+
yield 1
561+
finally:
562+
1 / 0
563+
''')
564+
565+
async def wait():
566+
async for _ in waiter(1, self.loop):
567+
pass
568+
569+
t = self.loop.create_task(wait())
570+
self.loop.run_until_complete(asyncio.sleep(0.1, loop=self.loop))
571+
572+
self.loop.set_exception_handler(logger)
573+
self.loop.run_until_complete(self.loop.shutdown_asyncgens())
574+
575+
self.assertEqual(logged, 1)
576+
577+
# Silence warnings
578+
t.cancel()
579+
self.loop.run_until_complete(asyncio.sleep(0.1, loop=self.loop))
580+
581+
def test_shutdown_asyncgens_03(self):
582+
if not hasattr(self.loop, 'shutdown_asyncgens'):
583+
raise unittest.SkipTest()
584+
585+
waiter = self._compile_agen('''async def waiter():
586+
yield 1
587+
yield 2
588+
''')
589+
590+
async def foo():
591+
# We specifically want to hit _asyncgen_finalizer_hook
592+
# method.
593+
await waiter().asend(None)
594+
595+
self.loop.run_until_complete(foo())
596+
self.loop.run_until_complete(asyncio.sleep(0.01, loop=self.loop))
542597

543598
class TestBaseUV(_TestBase, UVTestCase):
544599

uvloop/loop.pyx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2494,7 +2494,7 @@ cdef class Loop:
24942494
self.create_task(agen.aclose())
24952495
# Wake up the loop if the finalizer was called from
24962496
# a different thread.
2497-
self._write_to_self()
2497+
self.handler_async.send()
24982498

24992499
def _asyncgen_firstiter_hook(self, agen):
25002500
if self._asyncgens_shutdown_called:

0 commit comments

Comments
 (0)