achimnol / aiotools

Idiomatic asyncio utilties
https://aiotools.readthedocs.io
MIT License
153 stars 11 forks source link

`TaskGroup` propagates `CancelledError` rather than a `MultiError` on exception #34

Closed bdowning closed 2 years ago

bdowning commented 2 years ago

See the following snippet:

import asyncio
import aiotools

async def error():
    await asyncio.sleep(1)
    raise Exception("bad stuff")

async def main():
    try:
        async with aiotools.TaskGroup() as tg:
            tg.create_task(error())
            await asyncio.sleep(5)
    except Exception as e:
        print(f"Got inner {repr(e)}")
        raise

try:
    asyncio.run(main())
except BaseException as e:
    print(f"Got outer {repr(e)}")
Got outer CancelledError()

Is this expected behavior? It feels wrong, since a) it ate an exception and b) the task wasn't actually cancelled.

This is Python 3.9 and aiotools 1.4.0.

achimnol commented 2 years ago

Let's inspect how python/cpython#31270 handles this...

achimnol commented 2 years ago

Also refer https://bugs.python.org/issue46771

achimnol commented 2 years ago

I have tested your code with asyncio.TaskGroup introduced in Python 3.11 development version.

Got inner ExceptionGroup('unhandled errors in a TaskGroup', [Exception('bad stuff')])
Got outer ExceptionGroup('unhandled errors in a TaskGroup', [Exception('bad stuff')])

With aiotools.TaskGroup,

Got outer CancelledError()

It seems to have some problem, definitely. I'll look into more.