@@ -85,15 +85,7 @@ def traced_function():
8585 self .fail (f"Exception wasn't raised @{ target_offset } " )
8686
8787
88- def _test_asynchronous_cm (self ):
89- # NOTE: this can't work, since asyncio is written in Python, and hence
90- # will always process pending calls at some point during the evaluation
91- # of __aenter__ and __aexit__
92- #
93- # So to handle that case, we need to some way to tell the event loop
94- # to convert pending call processing into calls to
95- # asyncio.get_event_loop().call_soon() instead of processing them
96- # immediately
88+ def test_asynchronous_cm (self ):
9789 class AsyncTrackingCM ():
9890 def __init__ (self ):
9991 self .enter_without_exit = None
@@ -106,17 +98,34 @@ async def traced_coroutine():
10698 async with tracking_cm :
10799 1 + 1
108100 return
101+ async def cushion ():
102+ await traced_coroutine ()
103+ # In case the last injected call spills over, we want the
104+ # exception to be raised here instead of deep in the bowels of
105+ # asyncio (which will probably lock up or something).
106+ while True :
107+ pass
109108 target_offset = - 1
110109 max_offset = len (traced_coroutine .__code__ .co_code ) - 2
111110 loop = asyncio .get_event_loop ()
112111 while target_offset < max_offset :
113112 target_offset += 1
114113 raise_after_offset (traced_coroutine , target_offset )
115114 try :
116- loop .run_until_complete (traced_coroutine ())
117- except InjectedException :
118- # key invariant: if we entered the CM, we exited it
119- self .assertFalse (tracking_cm .enter_without_exit )
115+ loop .run_until_complete (cushion ())
116+ except InjectedException as exc :
117+ # key invariant: if we entered the CM, we exited it. Meaning:
118+ # either __aexit__ ran fully, or else the exception was raised
119+ # *inside* __aexit__.
120+ tb = exc .__traceback__
121+ while tb is not None :
122+ if tb .tb_frame .f_code is AsyncTrackingCM .__aexit__ .__code__ :
123+ # This was raised inside __aexit__
124+ break
125+ tb = tb .tb_next
126+ else :
127+ # It wasn't raised inside __aexit__
128+ self .assertFalse (tracking_cm .enter_without_exit )
120129 else :
121130 self .fail (f"Exception wasn't raised @{ target_offset } " )
122131
0 commit comments