Cancelling current task
decaz opened this issue · comments
I'm using aiohttp's
WebSocket client and want to set my own exception for the current task on message receive timeout. But currently it's impossible due to async-timeout's
task cancelling.
Ref: https://github.com/aio-libs/aiohttp/blob/master/aiohttp/client_ws.py#L195
Simple example listing:
import asyncio
from async_timeout import timeout
async def main():
try:
async with timeout(1):
await asyncio.sleep(2)
except asyncio.TimeoutError:
future.set_exception(Exception('My exception'))
future = asyncio.ensure_future(main())
loop = asyncio.get_event_loop()
loop.run_forever()
Output:
$ python test_timeout.py
Exception in callback <TaskWakeupMethWrapper object at 0x7f0d9414bbb8>(<Future cancelled>)
handle: <Handle <TaskWakeupMethWrapper object at 0x7f0d9414bbb8>(<Future cancelled>)>
Traceback (most recent call last):
File "/usr/lib/python3.6/asyncio/events.py", line 145, in _run
self._callback(*self._args)
asyncio.base_futures.InvalidStateError: invalid state
How can I set my own exception if it possible?
If exception type is important inside the coroutine, you can catch CancelledError
and re-raise as an exception of you choice. If exception type is important inside the awaiting code, you can catch TimeoutError
.
Task.cancel()
doesn't support custom exceptions for good reason, async-timeout
should not invent anything in the area but follow the upstream.
@decaz Alternatively, you can subclass timeout
and override the _cancel_task
to throw an exception instead of cancelling.
Please no. Perhaps this way will be broken in a meantime.
The timeout
class is not intended for inheritance.
Ok, simply raising the exception helps:
...
except asyncio.TimeoutError:
raise Exception('My exception')
...
I guess the problem comes when you want to use exactly future.set_exception
instead of raising.
In example you basically trying to call Task.set_exception()
.
This is explicitly forbidden in Python 3.7 and was buggy in previous Python versions