bpo-39622: Interrupt the main asyncio task on Ctrl+C (GH-32105)

Co-authored-by: Kumar Aditya <59607654+kumaraditya303@users.noreply.github.com>
This commit is contained in:
Andrew Svetlov 2022-03-30 15:15:06 +03:00 committed by GitHub
parent 04acfa94bb
commit f08a191882
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 122 additions and 2 deletions

View file

@ -1,7 +1,9 @@
import _thread
import asyncio
import contextvars
import gc
import re
import threading
import unittest
from unittest import mock
@ -12,6 +14,10 @@ def tearDownModule():
asyncio.set_event_loop_policy(None)
def interrupt_self():
_thread.interrupt_main()
class TestPolicy(asyncio.AbstractEventLoopPolicy):
def __init__(self, loop_factory):
@ -298,7 +304,7 @@ class RunnerTests(BaseTest):
self.assertEqual(2, runner.run(get_context()).get(cvar))
def test_recursine_run(self):
def test_recursive_run(self):
async def g():
pass
@ -318,6 +324,57 @@ class RunnerTests(BaseTest):
):
runner.run(f())
def test_interrupt_call_soon(self):
# The only case when task is not suspended by waiting a future
# or another task
assert threading.current_thread() is threading.main_thread()
async def coro():
with self.assertRaises(asyncio.CancelledError):
while True:
await asyncio.sleep(0)
raise asyncio.CancelledError()
with asyncio.Runner() as runner:
runner.get_loop().call_later(0.1, interrupt_self)
with self.assertRaises(KeyboardInterrupt):
runner.run(coro())
def test_interrupt_wait(self):
# interrupting when waiting a future cancels both future and main task
assert threading.current_thread() is threading.main_thread()
async def coro(fut):
with self.assertRaises(asyncio.CancelledError):
await fut
raise asyncio.CancelledError()
with asyncio.Runner() as runner:
fut = runner.get_loop().create_future()
runner.get_loop().call_later(0.1, interrupt_self)
with self.assertRaises(KeyboardInterrupt):
runner.run(coro(fut))
self.assertTrue(fut.cancelled())
def test_interrupt_cancelled_task(self):
# interrupting cancelled main task doesn't raise KeyboardInterrupt
assert threading.current_thread() is threading.main_thread()
async def subtask(task):
await asyncio.sleep(0)
task.cancel()
interrupt_self()
async def coro():
asyncio.create_task(subtask(asyncio.current_task()))
await asyncio.sleep(10)
with asyncio.Runner() as runner:
with self.assertRaises(asyncio.CancelledError):
runner.run(coro())
if __name__ == '__main__':
unittest.main()