1+ import _thread
12import asyncio
23import contextvars
34import gc
45import re
6+ import threading
57import unittest
68
79from unittest import mock
@@ -12,6 +14,10 @@ def tearDownModule():
1214 asyncio .set_event_loop_policy (None )
1315
1416
17+ def interrupt_self ():
18+ _thread .interrupt_main ()
19+
20+
1521class TestPolicy (asyncio .AbstractEventLoopPolicy ):
1622
1723 def __init__ (self , loop_factory ):
@@ -298,7 +304,7 @@ async def get_context():
298304
299305 self .assertEqual (2 , runner .run (get_context ()).get (cvar ))
300306
301- def test_recursine_run (self ):
307+ def test_recursive_run (self ):
302308 async def g ():
303309 pass
304310
@@ -318,6 +324,57 @@ async def f():
318324 ):
319325 runner .run (f ())
320326
327+ def test_interrupt_call_soon (self ):
328+ # The only case when task is not suspended by waiting a future
329+ # or another task
330+ assert threading .current_thread () is threading .main_thread ()
331+
332+ async def coro ():
333+ with self .assertRaises (asyncio .CancelledError ):
334+ while True :
335+ await asyncio .sleep (0 )
336+ raise asyncio .CancelledError ()
337+
338+ with asyncio .Runner () as runner :
339+ runner .get_loop ().call_later (0.1 , interrupt_self )
340+ with self .assertRaises (KeyboardInterrupt ):
341+ runner .run (coro ())
342+
343+ def test_interrupt_wait (self ):
344+ # interrupting when waiting a future cancels both future and main task
345+ assert threading .current_thread () is threading .main_thread ()
346+
347+ async def coro (fut ):
348+ with self .assertRaises (asyncio .CancelledError ):
349+ await fut
350+ raise asyncio .CancelledError ()
351+
352+ with asyncio .Runner () as runner :
353+ fut = runner .get_loop ().create_future ()
354+ runner .get_loop ().call_later (0.1 , interrupt_self )
355+
356+ with self .assertRaises (KeyboardInterrupt ):
357+ runner .run (coro (fut ))
358+
359+ self .assertTrue (fut .cancelled ())
360+
361+ def test_interrupt_cancelled_task (self ):
362+ # interrupting cancelled main task doesn't raise KeyboardInterrupt
363+ assert threading .current_thread () is threading .main_thread ()
364+
365+ async def subtask (task ):
366+ await asyncio .sleep (0 )
367+ task .cancel ()
368+ interrupt_self ()
369+
370+ async def coro ():
371+ asyncio .create_task (subtask (asyncio .current_task ()))
372+ await asyncio .sleep (10 )
373+
374+ with asyncio .Runner () as runner :
375+ with self .assertRaises (asyncio .CancelledError ):
376+ runner .run (coro ())
377+
321378
322379if __name__ == '__main__' :
323380 unittest .main ()
0 commit comments