1- import asyncio
1+ import functools
22from contextlib import (
33 asynccontextmanager , AbstractAsyncContextManager ,
44 AsyncExitStack , nullcontext , aclosing , contextmanager )
88
99from test .test_contextlib import TestBaseExitStack
1010
11- support .requires_working_socket (module = True )
1211
13- def tearDownModule ():
14- asyncio ._set_event_loop_policy (None )
12+ def _run_async_fn (async_fn , / , * args , ** kwargs ):
13+ coro = async_fn (* args , ** kwargs )
14+ gen = type (coro ).__await__ (coro )
15+ try :
16+ gen .send (None )
17+ except StopIteration as e :
18+ return e .value
19+ else :
20+ raise AssertionError ("coroutine did not stop" )
21+ finally :
22+ gen .close ()
1523
1624
17- class TestAbstractAsyncContextManager (unittest .IsolatedAsyncioTestCase ):
25+ def _async_test (async_fn ):
26+ """Decorator to turn an async function into a test case."""
27+ @functools .wraps (async_fn )
28+ def wrapper (* args , ** kwargs ):
29+ return _run_async_fn (async_fn , * args , ** kwargs )
1830
31+ return wrapper
32+
33+
34+ class TestAbstractAsyncContextManager (unittest .TestCase ):
35+
36+ @_async_test
1937 async def test_enter (self ):
2038 class DefaultEnter (AbstractAsyncContextManager ):
2139 async def __aexit__ (self , * args ):
@@ -27,6 +45,7 @@ async def __aexit__(self, *args):
2745 async with manager as context :
2846 self .assertIs (manager , context )
2947
48+ @_async_test
3049 async def test_slots (self ):
3150 class DefaultAsyncContextManager (AbstractAsyncContextManager ):
3251 __slots__ = ()
@@ -38,6 +57,7 @@ async def __aexit__(self, *args):
3857 manager = DefaultAsyncContextManager ()
3958 manager .var = 42
4059
60+ @_async_test
4161 async def test_async_gen_propagates_generator_exit (self ):
4262 # A regression test for https://bugs.python.org/issue33786.
4363
@@ -88,8 +108,9 @@ class NoneAexit(ManagerFromScratch):
88108 self .assertFalse (issubclass (NoneAexit , AbstractAsyncContextManager ))
89109
90110
91- class AsyncContextManagerTestCase (unittest .IsolatedAsyncioTestCase ):
111+ class AsyncContextManagerTestCase (unittest .TestCase ):
92112
113+ @_async_test
93114 async def test_contextmanager_plain (self ):
94115 state = []
95116 @asynccontextmanager
@@ -103,6 +124,7 @@ async def woohoo():
103124 state .append (x )
104125 self .assertEqual (state , [1 , 42 , 999 ])
105126
127+ @_async_test
106128 async def test_contextmanager_finally (self ):
107129 state = []
108130 @asynccontextmanager
@@ -120,6 +142,7 @@ async def woohoo():
120142 raise ZeroDivisionError ()
121143 self .assertEqual (state , [1 , 42 , 999 ])
122144
145+ @_async_test
123146 async def test_contextmanager_traceback (self ):
124147 @asynccontextmanager
125148 async def f ():
@@ -175,6 +198,7 @@ class StopAsyncIterationSubclass(StopAsyncIteration):
175198 self .assertEqual (frames [0 ].name , 'test_contextmanager_traceback' )
176199 self .assertEqual (frames [0 ].line , 'raise stop_exc' )
177200
201+ @_async_test
178202 async def test_contextmanager_no_reraise (self ):
179203 @asynccontextmanager
180204 async def whee ():
@@ -184,6 +208,7 @@ async def whee():
184208 # Calling __aexit__ should not result in an exception
185209 self .assertFalse (await ctx .__aexit__ (TypeError , TypeError ("foo" ), None ))
186210
211+ @_async_test
187212 async def test_contextmanager_trap_yield_after_throw (self ):
188213 @asynccontextmanager
189214 async def whoo ():
@@ -199,6 +224,7 @@ async def whoo():
199224 # The "gen" attribute is an implementation detail.
200225 self .assertFalse (ctx .gen .ag_suspended )
201226
227+ @_async_test
202228 async def test_contextmanager_trap_no_yield (self ):
203229 @asynccontextmanager
204230 async def whoo ():
@@ -208,6 +234,7 @@ async def whoo():
208234 with self .assertRaises (RuntimeError ):
209235 await ctx .__aenter__ ()
210236
237+ @_async_test
211238 async def test_contextmanager_trap_second_yield (self ):
212239 @asynccontextmanager
213240 async def whoo ():
@@ -221,6 +248,7 @@ async def whoo():
221248 # The "gen" attribute is an implementation detail.
222249 self .assertFalse (ctx .gen .ag_suspended )
223250
251+ @_async_test
224252 async def test_contextmanager_non_normalised (self ):
225253 @asynccontextmanager
226254 async def whoo ():
@@ -234,6 +262,7 @@ async def whoo():
234262 with self .assertRaises (SyntaxError ):
235263 await ctx .__aexit__ (RuntimeError , None , None )
236264
265+ @_async_test
237266 async def test_contextmanager_except (self ):
238267 state = []
239268 @asynccontextmanager
@@ -251,6 +280,7 @@ async def woohoo():
251280 raise ZeroDivisionError (999 )
252281 self .assertEqual (state , [1 , 42 , 999 ])
253282
283+ @_async_test
254284 async def test_contextmanager_except_stopiter (self ):
255285 @asynccontextmanager
256286 async def woohoo ():
@@ -277,6 +307,7 @@ class StopAsyncIterationSubclass(StopAsyncIteration):
277307 else :
278308 self .fail (f'{ stop_exc } was suppressed' )
279309
310+ @_async_test
280311 async def test_contextmanager_wrap_runtimeerror (self ):
281312 @asynccontextmanager
282313 async def woohoo ():
@@ -321,12 +352,14 @@ def test_contextmanager_doc_attrib(self):
321352 self .assertEqual (baz .__doc__ , "Whee!" )
322353
323354 @support .requires_docstrings
355+ @_async_test
324356 async def test_instance_docstring_given_cm_docstring (self ):
325357 baz = self ._create_contextmanager_attribs ()(None )
326358 self .assertEqual (baz .__doc__ , "Whee!" )
327359 async with baz :
328360 pass # suppress warning
329361
362+ @_async_test
330363 async def test_keywords (self ):
331364 # Ensure no keyword arguments are inhibited
332365 @asynccontextmanager
@@ -335,6 +368,7 @@ async def woohoo(self, func, args, kwds):
335368 async with woohoo (self = 11 , func = 22 , args = 33 , kwds = 44 ) as target :
336369 self .assertEqual (target , (11 , 22 , 33 , 44 ))
337370
371+ @_async_test
338372 async def test_recursive (self ):
339373 depth = 0
340374 ncols = 0
@@ -361,6 +395,7 @@ async def recursive():
361395 self .assertEqual (ncols , 10 )
362396 self .assertEqual (depth , 0 )
363397
398+ @_async_test
364399 async def test_decorator (self ):
365400 entered = False
366401
@@ -379,6 +414,7 @@ async def test():
379414 await test ()
380415 self .assertFalse (entered )
381416
417+ @_async_test
382418 async def test_decorator_with_exception (self ):
383419 entered = False
384420
@@ -401,6 +437,7 @@ async def test():
401437 await test ()
402438 self .assertFalse (entered )
403439
440+ @_async_test
404441 async def test_decorating_method (self ):
405442
406443 @asynccontextmanager
@@ -435,14 +472,15 @@ async def method(self, a, b, c=None):
435472 self .assertEqual (test .b , 2 )
436473
437474
438- class AclosingTestCase (unittest .IsolatedAsyncioTestCase ):
475+ class AclosingTestCase (unittest .TestCase ):
439476
440477 @support .requires_docstrings
441478 def test_instance_docs (self ):
442479 cm_docstring = aclosing .__doc__
443480 obj = aclosing (None )
444481 self .assertEqual (obj .__doc__ , cm_docstring )
445482
483+ @_async_test
446484 async def test_aclosing (self ):
447485 state = []
448486 class C :
@@ -454,6 +492,7 @@ async def aclose(self):
454492 self .assertEqual (x , y )
455493 self .assertEqual (state , [1 ])
456494
495+ @_async_test
457496 async def test_aclosing_error (self ):
458497 state = []
459498 class C :
@@ -467,6 +506,7 @@ async def aclose(self):
467506 1 / 0
468507 self .assertEqual (state , [1 ])
469508
509+ @_async_test
470510 async def test_aclosing_bpo41229 (self ):
471511 state = []
472512
@@ -492,45 +532,27 @@ async def agenfunc():
492532 self .assertEqual (state , [1 ])
493533
494534
495- class TestAsyncExitStack (TestBaseExitStack , unittest .IsolatedAsyncioTestCase ):
535+ class TestAsyncExitStack (TestBaseExitStack , unittest .TestCase ):
496536 class SyncAsyncExitStack (AsyncExitStack ):
497- @staticmethod
498- def run_coroutine (coro ):
499- loop = asyncio .new_event_loop ()
500- t = loop .create_task (coro )
501- t .add_done_callback (lambda f : loop .stop ())
502- loop .run_forever ()
503-
504- exc = t .exception ()
505- if not exc :
506- return t .result ()
507- else :
508- context = exc .__context__
509-
510- try :
511- raise exc
512- except :
513- exc .__context__ = context
514- raise exc
515537
516538 def close (self ):
517- return self . run_coroutine (self .aclose () )
539+ return _run_async_fn (self .aclose )
518540
519541 def __enter__ (self ):
520- return self . run_coroutine (self .__aenter__ () )
542+ return _run_async_fn (self .__aenter__ )
521543
522544 def __exit__ (self , * exc_details ):
523- return self . run_coroutine (self .__aexit__ ( * exc_details ) )
545+ return _run_async_fn (self .__aexit__ , * exc_details )
524546
525547 exit_stack = SyncAsyncExitStack
526548 callback_error_internal_frames = [
527- ('__exit__' , 'return self.run_coroutine(self.__aexit__(*exc_details))' ),
528- ('run_coroutine' , 'raise exc' ),
529- ('run_coroutine' , 'raise exc' ),
549+ ('__exit__' , 'return _run_async_fn(self.__aexit__, *exc_details)' ),
550+ ('_run_async_fn' , 'gen.send(None)' ),
530551 ('__aexit__' , 'raise exc' ),
531552 ('__aexit__' , 'cb_suppress = cb(*exc_details)' ),
532553 ]
533554
555+ @_async_test
534556 async def test_async_callback (self ):
535557 expected = [
536558 ((), {}),
@@ -573,6 +595,7 @@ async def _exit(*args, **kwds):
573595 stack .push_async_callback (callback = _exit , arg = 3 )
574596 self .assertEqual (result , [])
575597
598+ @_async_test
576599 async def test_async_push (self ):
577600 exc_raised = ZeroDivisionError
578601 async def _expect_exc (exc_type , exc , exc_tb ):
@@ -608,6 +631,7 @@ async def __aexit__(self, *exc_details):
608631 self .assertIs (stack ._exit_callbacks [- 1 ][1 ], _expect_exc )
609632 1 / 0
610633
634+ @_async_test
611635 async def test_enter_async_context (self ):
612636 class TestCM (object ):
613637 async def __aenter__ (self ):
@@ -629,6 +653,7 @@ async def _exit():
629653
630654 self .assertEqual (result , [1 , 2 , 3 , 4 ])
631655
656+ @_async_test
632657 async def test_enter_async_context_errors (self ):
633658 class LacksEnterAndExit :
634659 pass
@@ -648,6 +673,7 @@ async def __aenter__(self):
648673 await stack .enter_async_context (LacksExit ())
649674 self .assertFalse (stack ._exit_callbacks )
650675
676+ @_async_test
651677 async def test_async_exit_exception_chaining (self ):
652678 # Ensure exception chaining matches the reference behaviour
653679 async def raise_exc (exc ):
@@ -679,6 +705,7 @@ async def suppress_exc(*exc_details):
679705 self .assertIsInstance (inner_exc , ValueError )
680706 self .assertIsInstance (inner_exc .__context__ , ZeroDivisionError )
681707
708+ @_async_test
682709 async def test_async_exit_exception_explicit_none_context (self ):
683710 # Ensure AsyncExitStack chaining matches actual nested `with` statements
684711 # regarding explicit __context__ = None.
@@ -713,6 +740,7 @@ async def my_cm_with_exit_stack():
713740 else :
714741 self .fail ("Expected IndexError, but no exception was raised" )
715742
743+ @_async_test
716744 async def test_instance_bypass_async (self ):
717745 class Example (object ): pass
718746 cm = Example ()
@@ -725,7 +753,8 @@ class Example(object): pass
725753 self .assertIs (stack ._exit_callbacks [- 1 ][1 ], cm )
726754
727755
728- class TestAsyncNullcontext (unittest .IsolatedAsyncioTestCase ):
756+ class TestAsyncNullcontext (unittest .TestCase ):
757+ @_async_test
729758 async def test_async_nullcontext (self ):
730759 class C :
731760 pass
0 commit comments