11import asyncio
2+ import contextvars
23import inspect
34import warnings
45
@@ -34,7 +35,7 @@ class IsolatedAsyncioTestCase(TestCase):
3435 def __init__ (self , methodName = 'runTest' ):
3536 super ().__init__ (methodName )
3637 self ._asyncioTestLoop = None
37- self ._asyncioCallsQueue = None
38+ self ._asyncioTestContext = contextvars . copy_context ()
3839
3940 async def asyncSetUp (self ):
4041 pass
@@ -58,7 +59,7 @@ def addAsyncCleanup(self, func, /, *args, **kwargs):
5859 self .addCleanup (* (func , * args ), ** kwargs )
5960
6061 def _callSetUp (self ):
61- self .setUp ( )
62+ self ._asyncioTestContext . run ( self . setUp )
6263 self ._callAsync (self .asyncSetUp )
6364
6465 def _callTestMethod (self , method ):
@@ -68,64 +69,42 @@ def _callTestMethod(self, method):
6869
6970 def _callTearDown (self ):
7071 self ._callAsync (self .asyncTearDown )
71- self .tearDown ( )
72+ self ._asyncioTestContext . run ( self . tearDown )
7273
7374 def _callCleanup (self , function , * args , ** kwargs ):
7475 self ._callMaybeAsync (function , * args , ** kwargs )
7576
7677 def _callAsync (self , func , / , * args , ** kwargs ):
7778 assert self ._asyncioTestLoop is not None , 'asyncio test loop is not initialized'
78- ret = func (* args , ** kwargs )
79- assert inspect .isawaitable (ret ), f'{ func !r} returned non-awaitable'
80- fut = self ._asyncioTestLoop .create_future ()
81- self ._asyncioCallsQueue .put_nowait ((fut , ret ))
82- return self ._asyncioTestLoop .run_until_complete (fut )
79+ assert inspect .iscoroutinefunction (func ), f'{ func !r} is not an async function'
80+ task = self ._asyncioTestLoop .create_task (
81+ func (* args , ** kwargs ),
82+ context = self ._asyncioTestContext ,
83+ )
84+ return self ._asyncioTestLoop .run_until_complete (task )
8385
8486 def _callMaybeAsync (self , func , / , * args , ** kwargs ):
8587 assert self ._asyncioTestLoop is not None , 'asyncio test loop is not initialized'
86- ret = func (* args , ** kwargs )
87- if inspect .isawaitable (ret ):
88- fut = self ._asyncioTestLoop .create_future ()
89- self ._asyncioCallsQueue .put_nowait ((fut , ret ))
90- return self ._asyncioTestLoop .run_until_complete (fut )
88+ if inspect .iscoroutinefunction (func ):
89+ task = self ._asyncioTestLoop .create_task (
90+ func (* args , ** kwargs ),
91+ context = self ._asyncioTestContext ,
92+ )
93+ return self ._asyncioTestLoop .run_until_complete (task )
9194 else :
92- return ret
93-
94- async def _asyncioLoopRunner (self , fut ):
95- self ._asyncioCallsQueue = queue = asyncio .Queue ()
96- fut .set_result (None )
97- while True :
98- query = await queue .get ()
99- queue .task_done ()
100- if query is None :
101- return
102- fut , awaitable = query
103- try :
104- ret = await awaitable
105- if not fut .cancelled ():
106- fut .set_result (ret )
107- except (SystemExit , KeyboardInterrupt ):
108- raise
109- except (BaseException , asyncio .CancelledError ) as ex :
110- if not fut .cancelled ():
111- fut .set_exception (ex )
95+ return self ._asyncioTestContext .run (func , * args , ** kwargs )
11296
11397 def _setupAsyncioLoop (self ):
11498 assert self ._asyncioTestLoop is None , 'asyncio test loop already initialized'
11599 loop = asyncio .new_event_loop ()
116100 asyncio .set_event_loop (loop )
117101 loop .set_debug (True )
118102 self ._asyncioTestLoop = loop
119- fut = loop .create_future ()
120- self ._asyncioCallsTask = loop .create_task (self ._asyncioLoopRunner (fut ))
121- loop .run_until_complete (fut )
122103
123104 def _tearDownAsyncioLoop (self ):
124105 assert self ._asyncioTestLoop is not None , 'asyncio test loop is not initialized'
125106 loop = self ._asyncioTestLoop
126107 self ._asyncioTestLoop = None
127- self ._asyncioCallsQueue .put_nowait (None )
128- loop .run_until_complete (self ._asyncioCallsQueue .join ())
129108
130109 try :
131110 # cancel all tasks
0 commit comments