@@ -237,33 +237,6 @@ async def inner():
237
237
with self .assertRaises (FooException ):
238
238
await foo ()
239
239
240
- async def test_wait_for_self_cancellation (self ):
241
- async def inner ():
242
- try :
243
- await asyncio .sleep (0.3 )
244
- except asyncio .CancelledError :
245
- try :
246
- await asyncio .sleep (0.3 )
247
- except asyncio .CancelledError :
248
- await asyncio .sleep (0.3 )
249
-
250
- return 42
251
-
252
- inner_task = asyncio .create_task (inner ())
253
-
254
- wait = asyncio .wait_for (inner_task , timeout = 0.1 )
255
-
256
- # Test that wait_for itself is properly cancellable
257
- # even when the initial task holds up the initial cancellation.
258
- task = asyncio .create_task (wait )
259
- await asyncio .sleep (0.2 )
260
- task .cancel ()
261
-
262
- with self .assertRaises (asyncio .CancelledError ):
263
- await task
264
-
265
- self .assertEqual (await inner_task , 42 )
266
-
267
240
async def _test_cancel_wait_for (self , timeout ):
268
241
loop = asyncio .get_running_loop ()
269
242
@@ -289,6 +262,106 @@ async def test_cancel_blocking_wait_for(self):
289
262
async def test_cancel_wait_for (self ):
290
263
await self ._test_cancel_wait_for (60.0 )
291
264
265
+ async def test_wait_for_cancel_suppressed (self ):
266
+ # GH-86296: Supressing CancelledError is discouraged
267
+ # but if a task subpresses CancelledError and returns a value,
268
+ # `wait_for` should return the value instead of raising CancelledError.
269
+ # This is the same behavior as `asyncio.timeout`.
270
+
271
+ async def return_42 ():
272
+ try :
273
+ await asyncio .sleep (10 )
274
+ except asyncio .CancelledError :
275
+ return 42
276
+
277
+ res = await asyncio .wait_for (return_42 (), timeout = 0.1 )
278
+ self .assertEqual (res , 42 )
279
+
280
+
281
+ async def test_wait_for_issue86296 (self ):
282
+ # GH-86296: The task should get cancelled and not run to completion.
283
+ # inner completes in one cycle of the event loop so it
284
+ # completes before the task is cancelled.
285
+
286
+ async def inner ():
287
+ return 'done'
288
+
289
+ inner_task = asyncio .create_task (inner ())
290
+ reached_end = False
291
+
292
+ async def wait_for_coro ():
293
+ await asyncio .wait_for (inner_task , timeout = 100 )
294
+ await asyncio .sleep (1 )
295
+ nonlocal reached_end
296
+ reached_end = True
297
+
298
+ task = asyncio .create_task (wait_for_coro ())
299
+ self .assertFalse (task .done ())
300
+ # Run the task
301
+ await asyncio .sleep (0 )
302
+ task .cancel ()
303
+ with self .assertRaises (asyncio .CancelledError ):
304
+ await task
305
+ self .assertTrue (inner_task .done ())
306
+ self .assertEqual (await inner_task , 'done' )
307
+ self .assertFalse (reached_end )
308
+
309
+
310
+ class WaitForShieldTests (unittest .IsolatedAsyncioTestCase ):
311
+
312
+ async def test_zero_timeout (self ):
313
+ # `asyncio.shield` creates a new task which wraps the passed in
314
+ # awaitable and shields it from cancellation so with timeout=0
315
+ # the task returned by `asyncio.shield` aka shielded_task gets
316
+ # cancelled immediately and the task wrapped by it is scheduled
317
+ # to run.
318
+
319
+ async def coro ():
320
+ await asyncio .sleep (0.01 )
321
+ return 'done'
322
+
323
+ task = asyncio .create_task (coro ())
324
+ with self .assertRaises (asyncio .TimeoutError ):
325
+ shielded_task = asyncio .shield (task )
326
+ await asyncio .wait_for (shielded_task , timeout = 0 )
327
+
328
+ # Task is running in background
329
+ self .assertFalse (task .done ())
330
+ self .assertFalse (task .cancelled ())
331
+ self .assertTrue (shielded_task .cancelled ())
332
+
333
+ # Wait for the task to complete
334
+ await asyncio .sleep (0.1 )
335
+ self .assertTrue (task .done ())
336
+
337
+
338
+ async def test_none_timeout (self ):
339
+ # With timeout=None the timeout is disabled so it
340
+ # runs till completion.
341
+ async def coro ():
342
+ await asyncio .sleep (0.1 )
343
+ return 'done'
344
+
345
+ task = asyncio .create_task (coro ())
346
+ await asyncio .wait_for (asyncio .shield (task ), timeout = None )
347
+
348
+ self .assertTrue (task .done ())
349
+ self .assertEqual (await task , "done" )
350
+
351
+ async def test_shielded_timeout (self ):
352
+ # shield prevents the task from being cancelled.
353
+ async def coro ():
354
+ await asyncio .sleep (0.1 )
355
+ return 'done'
356
+
357
+ task = asyncio .create_task (coro ())
358
+ with self .assertRaises (asyncio .TimeoutError ):
359
+ await asyncio .wait_for (asyncio .shield (task ), timeout = 0.01 )
360
+
361
+ self .assertFalse (task .done ())
362
+ self .assertFalse (task .cancelled ())
363
+ self .assertEqual (await task , "done" )
364
+
292
365
293
366
if __name__ == '__main__' :
294
367
unittest .main ()
0 commit comments