New submission from Dmitrii Ivaniushin <defa...@gmail.com>: I found some issue that I suppose is a bug.
Let us have long running coroutines. We use them in gather, and one of them raises an error. Since then we cannot cancel the gather anymore, thus remaining children are not cancelable and executed until complete or raise an exception themselves. === import asyncio async def coro_with_error(): # Coro raises en error with 1 sec delay await asyncio.sleep(1) raise Exception('Error in coro') async def cancellator(coro): # We use this to cancel gather with delay 1 sec await asyncio.sleep(1) coro.cancel() async def success_long_coro(): # Long running coro, 2 sec try: await asyncio.sleep(2) print("I'm ok!") return 42 except asyncio.CancelledError: # Track that this coro is really cancelled print('I was cancelled') raise async def collector_with_error(): gather = asyncio.gather(coro_with_error(), success_long_coro()) try: await gather except Exception: print(f"WHOAGH ERROR, gather done={gather.done()}") print(f'EXC={type(gather.exception()).__name__}') # We want to cancel still running success_long_coro() gather.cancel() async def collector_with_cancel(): # Gather result from success_long_coro() gather = asyncio.gather(success_long_coro()) # schedule cancel in 1 sec asyncio.create_task(cancellator(gather)) try: await gather except Exception: print(f"WHOAGH ERROR, gather done={gather.done()}") print(f'EXC={type(gather.exception()).__name__}') # We want to cancel still running success_long_coro() gather.cancel() return # First case, cancel gather when children are running print('First case') loop = asyncio.get_event_loop() loop.create_task(collector_with_cancel()) # Ensure test coros we fully run loop.run_until_complete(asyncio.sleep(3)) print('Done') # Second case, cancel gather when child raise error print('Second case') loop = asyncio.get_event_loop() loop.create_task(collector_with_error()) # Ensure test coros we fully run loop.run_until_complete(asyncio.sleep(3)) print('Done') === Actual output: First case I was cancelled WHOAGH ERROR, gather done=True EXC=CancelledError Done Second case WHOAGH ERROR, gather done=True EXC=Exception I'm ok! Done Expected output: First case I was cancelled WHOAGH ERROR, gather done=True EXC=CancelledError Done Second case I was cancelled WHOAGH ERROR, gather done=True EXC=Exception Done Documentations says: > If gather() is cancelled, all submitted awaitables (that have not completed > yet) are also cancelled. But it mentions no cases on child coros' exceptions. >From doc: > If return_exceptions is False (default), the first raised exception is > immediately propagated to the task that awaits on gather(). Other awaitables > in the aws sequence won’t be cancelled and will continue to run. Which is true, exception is propagated, the gather has an exception set, marked as done() so its children are not cancelled. I believe asyncio should allow cancellation in that case. ---------- components: asyncio messages: 348603 nosy: Dmitrii Ivaniushin, asvetlov, yselivanov priority: normal severity: normal status: open title: Inconsistent gather with child exception type: behavior versions: Python 3.7 _______________________________________ Python tracker <rep...@bugs.python.org> <https://bugs.python.org/issue37703> _______________________________________ _______________________________________________ Python-bugs-list mailing list Unsubscribe: https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com