@@ -351,3 +351,69 @@ async def run_asyncio_loop(nursery, *, task_status=trio.TASK_STATUS_IGNORED):
351
351
await nursery .start (run_asyncio_loop , nursery )
352
352
# Trigger KeyboardInterrupt that should propagate accross the coroutines
353
353
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