@@ -351,3 +351,69 @@ async def run_asyncio_loop(nursery, *, task_status=trio.TASK_STATUS_IGNORED):
351351 await nursery .start (run_asyncio_loop , nursery )
352352 # Trigger KeyboardInterrupt that should propagate accross the coroutines
353353 signal .pthread_kill (threading .get_ident (), signal .SIGINT )
354+
355+
356+ @pytest .mark .trio
357+ @pytest .mark .parametrize ("throw_another" , [False , True ])
358+ async def test_cancel_loop (throw_another ):
359+ """Regression test for #76: ensure that cancelling a trio-asyncio loop
360+ does not cause any of the tasks running within it to yield a
361+ result of Cancelled.
362+ """
363+ async def manage_loop (task_status ):
364+ try :
365+ with trio .CancelScope () as scope :
366+ async with trio_asyncio .open_loop () as loop :
367+ task_status .started ((loop , scope ))
368+ await trio .sleep_forever ()
369+ finally :
370+ assert scope .cancelled_caught
371+
372+ # Trio-flavored async function. Runs as a trio-aio loop task
373+ # and gets cancelled when the loop does.
374+ async def trio_task ():
375+ async with trio .open_nursery () as nursery :
376+ nursery .start_soon (trio .sleep_forever )
377+ try :
378+ await trio .sleep_forever ()
379+ except trio .Cancelled :
380+ if throw_another :
381+ # This will combine with the Cancelled from the
382+ # background sleep_forever task to create a
383+ # MultiError escaping from trio_task
384+ raise ValueError ("hi" )
385+
386+ async with trio .open_nursery () as nursery :
387+ loop , scope = await nursery .start (manage_loop )
388+ fut = loop .trio_as_future (trio_task )
389+ await trio .testing .wait_all_tasks_blocked ()
390+ scope .cancel ()
391+ assert fut .done ()
392+ if throw_another :
393+ with pytest .raises (ValueError , match = "hi" ):
394+ fut .result ()
395+ else :
396+ assert fut .cancelled ()
397+
398+
399+ @pytest .mark .trio
400+ @pytest .mark .skipif (sys .version_info < (3 , 7 ), reason = "needs asyncio contextvars" )
401+ async def test_contextvars ():
402+ import contextvars
403+
404+ cvar = contextvars .ContextVar ("test_cvar" )
405+ cvar .set ("outer" )
406+
407+ async def fudge_in_aio ():
408+ assert cvar .get () == "outer"
409+ cvar .set ("middle" )
410+ await trio_asyncio .trio_as_aio (fudge_in_trio )()
411+ assert cvar .get () == "middle"
412+
413+ async def fudge_in_trio ():
414+ assert cvar .get () == "middle"
415+ cvar .set ("inner" )
416+
417+ async with trio_asyncio .open_loop () as loop :
418+ await trio_asyncio .aio_as_trio (fudge_in_aio )()
419+ assert cvar .get () == "outer"
0 commit comments