[Python 3.10 Issues] Deprecation
By manhnv, at: Aug. 12, 2025, 9:12 p.m.
Estimated Reading Time: __READING_TIME__ minutes


1) from collections import X breaks (Mapping/MutableMapping/Iterable, etc.)
Symptoms
-
ImportError: cannot import name 'Mapping' from 'collections'
-
Similar errors for
MutableMapping, Iterable, Sequence
, etc.
Why
The ABCs stopped being re-exported from collections in 3.10. You must import them from collections.abc. This had been warned about for years and finally flipped in 3.10.
Fix (drop-in)
# old
from collections import Mapping, MutableMapping, Iterable
# new
from collections.abc import Mapping, MutableMapping, Iterable
Prevent it next time
-
Grep your code and templates for
from collections import
.
-
Add a linter rule or CI check that fails on
from collections import (Mapping|MutableMapping|Iterable|...).
-
If a dependency still
imports from collections
, upgrade it or patch locally.
2) parser module removal
Symptoms
-
ModuleNotFoundError: No module named 'parser'
-
Tools that relied on old LL(1) parser internals stop working.
Why
CPython switched to the PEG parser in 3.9. The legacy parser module and related C APIs were removed in 3.10.
Fix / Migration paths
-
If you parsed Python code: use ast or modern libraries like LibCST / Parso.
-
If you generated/inspected bytecode: use ast, dis, or higher-level introspection APIs.
-
If you depended on lib2to3/pgen2 style grammars, plan a move - those won’t parse future grammar changes reliably.
Prevent it next time
-
Avoid relying on undocumented internals; prefer ast and well-maintained parsing libs.
-
Skim “Removed” sections of each What’s New before upgrading.
3) asyncio’s loop= parameter removal
Symptoms
-
TypeError: ... got an unexpected keyword argument 'loop'
-
Failing code like asyncio.Queue(loop=loop), asyncio.Lock(loop=loop), asyncio.gather(..., loop=loop).
Why
loop= had been deprecated; in 3.10 it’s removed from most high-level APIs. The event loop is now discovered via asyncio.get_running_loop(), or managed by asyncio.run().
Fix (typical patterns)
# old
loop = asyncio.get_event_loop()
q = asyncio.Queue(loop=loop)
lock = asyncio.Lock(loop=loop)
# new
async def main():
q = asyncio.Queue()
lock = asyncio.Lock()
asyncio.run(main())
-
Need the loop object? Inside a coroutine:
loop = asyncio.get_running_loop().
-
Creating tasks: prefer
asyncio.create_task()
inside running code.
Prevent it next time
-
Keep your async style “modern”: asyncio.run, create_task, get_running_loop only when required.
-
In libs, avoid exposing loop juggling to users.
4) distutils deprecation warnings
Symptoms
-
Warnings like: distutils is deprecated and slated for removal in Python 3.12.
Why
PEP 632: distutils was deprecated in 3.10, fully removed in 3.12.
Fix (modern build backend)
-
Move to a pyproject.toml build with Setuptools/Flit/Hatch.
Example:
# pyproject.toml
[build-system]
requires = ["setuptools>=64", "wheel"]
build-backend = "setuptools.build_meta"
-
Replace from distutils... imports with Setuptools or packaging equivalents.
Prevent it next time
-
Track PyPA and PEP updates; avoid stdlib packaging APIs slated for removal.
5) Smaller but notable gotchas
-
importlib migration (find_module → find_spec): Old patterns using pkgutil.find_loader/imp.find_module should move to importlib.util.find_spec.
-
C-API/Embedding changes: Read Python 3.10 C API changes if you maintain C extensions.
Upgrade playbook
-
Run tests on 3.10 early (use tox/CI matrix).
-
Fail on deprecations:
pytest -W error::DeprecationWarning
-
Automate fixes: replace from collections import with collections.abc, remove loop= in asyncio.
-
Modernize packaging with pyproject.toml.
-
Pin and upgrade dependencies.
-
Read What’s New in 3.10 before rollout.