Skip to content

Commit 8c471f8

Browse files
Jackenmenvstinnerfantix
authored
Don't stop the loop in run_until_complete() on SystemExit and KeyboardInterrupt exceptions (#337)
* Don't stop the loop in run_until_complete on SystemExit & KeyboardInterrupt * Add unit test (based on CPython's equivalent) * Fix the test to resume its coverage. Co-authored-by: Victor Stinner <[email protected]> Co-authored-by: Fantix King <[email protected]>
1 parent b7048b9 commit 8c471f8

File tree

2 files changed

+28
-1
lines changed

2 files changed

+28
-1
lines changed

tests/test_base.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -361,6 +361,26 @@ def throw():
361361
# done-callback for the previous future.
362362
self.loop.run_until_complete(foo(0.2))
363363

364+
def test_run_until_complete_keyboard_interrupt(self):
365+
# Issue #336: run_until_complete() must not schedule a pending
366+
# call to stop() if the future raised a KeyboardInterrupt
367+
async def raise_keyboard_interrupt():
368+
raise KeyboardInterrupt
369+
370+
self.loop._process_events = mock.Mock()
371+
372+
with self.assertRaises(KeyboardInterrupt):
373+
self.loop.run_until_complete(raise_keyboard_interrupt())
374+
375+
def func():
376+
self.loop.stop()
377+
func.called = True
378+
379+
func.called = False
380+
self.loop.call_later(0.01, func)
381+
self.loop.run_forever()
382+
self.assertTrue(func.called)
383+
364384
def test_debug_slow_callbacks(self):
365385
logger = logging.getLogger('asyncio')
366386
self.loop.set_debug(True)

uvloop/loop.pyx

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1431,7 +1431,14 @@ cdef class Loop:
14311431
# is no need to log the "destroy pending task" message
14321432
future._log_destroy_pending = False
14331433

1434-
done_cb = lambda fut: self.stop()
1434+
def done_cb(fut):
1435+
if not fut.cancelled():
1436+
exc = fut.exception()
1437+
if isinstance(exc, (SystemExit, KeyboardInterrupt)):
1438+
# Issue #336: run_forever() already finished,
1439+
# no need to stop it.
1440+
return
1441+
self.stop()
14351442

14361443
future.add_done_callback(done_cb)
14371444
try:

0 commit comments

Comments
 (0)