Asyncio Exceptions Changes from Python 3.6 to 3.7 to 3.8 (CancelledError & TimeoutError)

Jean-François Lévesque
2 min readMay 9, 2020

--

I started to work with Python asyncio library a few years ago with Python 3.6. At that time, the CancelledError exception was defined in concurrent.futures. The code looked like this:

import asynciofrom concurrent.futures import CancelledErrorasync def wait():
try:
await asyncio.sleep(60)
exception CancelledError:
pass

In Python 3.7, the asyncio.CancelledError exception was added.

When I migrated some code from 3.6 to 3.7, I did not change the CancelledError in my code and everything was working fine. Then I migrated from 3.7 to 3.8 and now I have some errors in my exception handling…

But why did it work when I migrated from 3.6 to 3.7? Looking at the CPython 3.7 source code gives us the answer:

In 3.7, the CancelledError exception was in fact the same concurrent.futures.CancelledError. This is why my code was still working.

In 3.8, the exceptions have been redefined and no longer refer to concurrent.futures. This is why my code broke when using 3.8:

Now my code works like a charm…

import asyncioasync def wait():
try:
await asyncio.sleep(60)
exception asyncio.CancelledError:
pass

This change was not documented in the What’s New In Python 3.8 but it is mentioned in the full changelog (search for bpo-34622).

And by the way, CancelledError base class changed from Exception to BaseException in 3.8 to avoid breaking task cancellation with except Exception pattern. All the details at https://bugs.python.org/issue32528.

I am the founder of Obkio, a network performance monitoring SaaS solution for enterprises. We are using a lot of Python and some of our projets are based on asyncio.

--

--