Andrew Svetlov <[email protected]> added the comment:
Suppose we have a case when two nested timeouts are reached at the same event
loop iteration:
async def asyncio.timeout(1) as cm1:
async with third_party_cm() as cm2:
async def asyncio.timeout(1) as cm3:
async with third_party_cm() as cm4:
await asyncio.sleep(10)
What exception should be bubbled between outer and inner context manager 'exit'
executions?
`sleep()` is interrupted with CancelledError, it is clear (and the only
possible solution in asyncio world). `cm4.__aexit__` receives the
CancelledError, does the cleanup if required, and re-raises the cancellation.
`cm3.__aexit__` receives the bubbled CancelledError and updates its own state
and raises an exception.
The question is: what exception should be raised, CancelledError or
TimeoutError?
What exception should see `cm2.__aexit__` code?
After careful thinking, I believe that CancelledError should be re-raised by
*inner affected* timeout context managers, the only top-level *affected*
context should convert CancelledError and raise TimeoutError.
My reasons for this behavior are:
A generic asyncio code is usually *ready* for cancellation. If it wants to
react to the cancellation event, it caught `asyncio.CancelledError` and
reraised it. Also, the asyncio code is cancellation-ready by default because
usually `BaseException` is now handled (asyncio.CancelledError is derived from
BaseException). TimeoutError is caught by `except Exception` instead, it adds
extra difficulty.
Handling both CancelledError and TimeoutError by *any* asyncio code on async
stack unwinding is tedious and error-prone. If we should choose one I bet on
CancelledError.
The inner code ignores timeouts usually (and executes resource cleanup only).
That's what CancelledError handling exists for already. If the cleanup differs
depending on timeout expiration, `cm3.expired` (name it) can be used as a flag.
You can disagree with me here, my opinion is based on my experience of writing
asyncio code only.
The top-level affected timeout context manager should raise TimeoutError
because it exists and is used for such things.
Long story short: all *internal affected* timeout context managers should not
raise TimeoutError (or it should be configurable and 'off' by default) because
`third_party_cm()` should have the same simple implementation whether is it
used as `cm2` or `cm4`.
Happy to see your opinions regarding the question, folks!
----------
_______________________________________
Python tracker <[email protected]>
<https://bugs.python.org/issue46771>
_______________________________________
_______________________________________________
Python-bugs-list mailing list
Unsubscribe:
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com