How to Use the Python 3.9 to 3.13 Upgrade Prompt to Catch Removed Modules Before CI Does
Plan a Python 3.9 to 3.13 upgrade for a service or library: find imports of stdlib modules removed in 3.12 and 3.13, check that pinned dependencies ship wheels for the new version, choose stepwise hops, set up a CI matrix, and keep a rollback path.

Python 3.9 has reached end of life, and a lot of services are still running it. The jump to 3.13 is not one big change but a pile of small ones: standard library modules that disappeared in 3.12 and 3.13, dependencies that need newer versions to ship wheels, and test tools that quietly stopped working. The Python 3.9 to 3.13 Upgrade Planner: Removed Stdlib Modules Sweep, Dependency Wheel Check, Stepwise Version Hops, CI Matrix, and a Rollback Plan prompt turns your grep output and lockfile into a concrete plan.
What the prompt produces
- A removed module sweep that maps each risky import to the version that removed it and the replacement.
- A dependency wheel table with your current pins, a target version to confirm on PyPI, and a risk level.
- A native extension note for anything you compile yourself.
- A hop plan: straight to 3.13 or through 3.11 first, with the reason.
- A CI matrix change that runs old and new versions side by side.
- A runtime switch checklist for base images, lockfiles, and smoke tests.
- A rollback plan that keeps the previous image deployable.
- A risk register with the three most likely breakages.
How to fill the inputs
ProjectAndRuntime sets the shape of the plan. A published library needs to support a range of versions, while a service only needs to run on one. Include the base image or runtime tag.
DependencyPins should be pasted straight from requirements.txt, poetry.lock, or uv.lock. The prompt does not invent versions; it marks targets for you to confirm on PyPI.
ImportGrep is the most valuable input. Run a search across the repo for imports of modules like imp, distutils, asyncore, asynchat, cgi, cgitb, crypt, telnetlib, pipes, imghdr, and lib2to3, and paste the hits with file paths. The first three groups went away in 3.12, and 3.13 removed the set of old modules listed in PEP 594.
NativeDeps covers anything you build from C or Rust. If everything comes from PyPI wheels, say so.
CiMatrix and ReleaseConstraints let the plan fit how you ship. A team that deploys weekly with a holiday freeze needs a different schedule than one that deploys daily.
Reading the example output
The example is a Flask service on a python:3.9-slim image with pandas and numpy pinned to old versions.
- The sweep finds imp, distutils, and imghdr and names the replacement for each: importlib.reload, setuptools, and a magic byte check.
- It flags asynctest, a test helper that does not come from the standard library at all but breaks on newer Python, and swaps in unittest.IsolatedAsyncioTestCase.
- The wheel table marks pandas and numpy as high risk because the move to their 2.x lines brings API and binary changes.
- The hop plan splits the work into two releases so the data stack upgrade does not land in the same deploy as the Flask upgrade.
- The rollback keeps the last 3.9 image tag and task definition so a revert is one click.
Tips for better results
- Treat DeprecationWarning from your own package as an error in CI. That turns quiet future breakage into a failing test now.
- Regenerate the lockfile inside the new base image instead of on a laptop with a different Python.
- Add one smoke test for each external system the service touches: database, queue, object storage.
Mistakes to avoid
- Do not bump every dependency and the interpreter in the same pull request. You will not know which change broke what.
- Do not trust a package's version number alone. Check that a wheel exists for your platform and Python version.
- Do not delete the old runtime path until the new one has been stable for a full release cycle.
Who it is for
Backend engineers, platform teams, and library maintainers moving off 3.9 who want a reviewable plan instead of a weekend of trial and error.
A practical rollout order
Start with the sweep and fix the removed imports on the current version, since most replacements work on 3.9 too. Then add the new Python version to CI as a non blocking job and watch what fails. Once it is green, make it blocking, switch the base image in staging, and run the smoke tests. Move production only after staging has handled a normal week of traffic.
Related PromptDig links
Open the Python 3.9 to 3.13 Upgrade Planner: Removed Stdlib Modules Sweep, Dependency Wheel Check, Stepwise Version Hops, CI Matrix, and a Rollback Plan prompt with your lockfile and grep output. For more coding prompts, Browse more prompts. If your team has a tested upgrade checklist, Share a prompt.