asyncio icon indicating copy to clipboard operation
asyncio copied to clipboard

Wrong exception re-raises if task raises CancelledError inside except block

Open germn opened this issue 10 years ago • 6 comments

import asyncio
from contextlib import suppress


async def main():
    task = asyncio.ensure_future(asyncio.sleep(1))
    task.cancel()

    try:
        raise Exception()
    except Exception:
        with suppress(asyncio.CancelledError):
            await task
        raise

if __name__ == "__main__":
    loop = asyncio.get_event_loop()
    loop.run_until_complete(main())

Expected output:

Exception

Actual output:

concurrent.futures._base.CancelledError

Windows 10, Python 3.5.0

germn avatar Nov 12 '15 13:11 germn

I can repro this too -- it's not unique to Windows or to PEP 492 (it fails the same way with coroutine/yield-from in Python 3.4). It's also not due to something in contextlib.suppress() or due to having a try/except in the outer except clause.

@1st1 -- do you have any suggestions? I suspect there's some special-casing of CancelledError that goes wrong here.

gvanrossum avatar Nov 12 '15 17:11 gvanrossum

I might be mistaken here, but it looks like this a bug in CPython...

class MainError(Exception):
    pass

class SubError(Exception):
    pass

def sub():
    yield

def main():
    try:
        raise MainError()
    except MainError:
        try:
            yield from sub()
        except SubError:
            pass
        raise

coro = main()
coro.send(None)
coro.throw(SubError())

Outputs:

Traceback (most recent call last):
  File "t.py", line 47, in <module>
    coro.throw(SubError())
  File "t.py", line 43, in main
    raise
RuntimeError: No active exception to reraise

1st1 avatar Nov 12 '15 18:11 1st1

And if you replace except MainError: with except MainError as e:, and raise with raise e then everything works correctly.

1st1 avatar Nov 12 '15 19:11 1st1

It's not even a yield from bug:

class MainError(Exception):
    pass

class SubError(Exception):
    pass

def main():
    try:
        raise MainError()
    except MainError:
        try:
            yield
        except SubError:
            print('got SubError')
        raise

coro = main()
coro.send(None)
coro.throw(SubError())

Outputs:

got SubError
Traceback (most recent call last):
  File "t.py", line 19, in <module>
    coro.throw(SubError())
  File "t.py", line 15, in main
    raise
RuntimeError: No active exception to reraise

1st1 avatar Nov 12 '15 20:11 1st1

http://bugs.python.org/issue25612

1st1 avatar Nov 12 '15 20:11 1st1

Thanks for the thorough investigation!

gvanrossum avatar Nov 12 '15 21:11 gvanrossum