diff options
author | Andrew Svetlov <andrew.svetlov@gmail.com> | 2022-03-30 15:15:06 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-03-30 15:15:06 +0300 |
commit | f08a191882f75bb79d42a49039892105b2212fb9 (patch) | |
tree | e30c76a39b816edba83ade96c867de64277b1f05 /Lib/test/test_asyncio/test_runners.py | |
parent | 04acfa94bb383cce973739478a7b58ab20ab47f4 (diff) | |
download | cpython-git-f08a191882f75bb79d42a49039892105b2212fb9.tar.gz |
bpo-39622: Interrupt the main asyncio task on Ctrl+C (GH-32105)
Co-authored-by: Kumar Aditya <59607654+kumaraditya303@users.noreply.github.com>
Diffstat (limited to 'Lib/test/test_asyncio/test_runners.py')
-rw-r--r-- | Lib/test/test_asyncio/test_runners.py | 59 |
1 files changed, 58 insertions, 1 deletions
diff --git a/Lib/test/test_asyncio/test_runners.py b/Lib/test/test_asyncio/test_runners.py index 94f26797b3..42aa07a0e0 100644 --- a/Lib/test/test_asyncio/test_runners.py +++ b/Lib/test/test_asyncio/test_runners.py @@ -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() |