Safeguard
Developer Tools•

How do you drop an old Python version without breaking your users?

Raise requires-python, fix the wheel tag, and check metadata before release. Installers then serve older releases to users on old Python. Steps included.

Safeguard Security Team
4 min read

Raise requires-python in your next release and check that your wheels are tagged correctly. Installers that read this metadata will give users on old interpreters the last release that still supports them, instead of a broken install. You do not need to delete or edit anything old.

Why this works

The Python Packaging User Guide explains the mechanism. Installers that follow core metadata 1.2 or newer, such as pip, match the running Python against the Requires-Python field. If the newest release does not match, the installer attempts the last distribution that did.

So dropping Python support is a metadata change, not a deletion. Old releases stay available for users who still need them.

Steps

  1. Pick the new minimum. Choose a version you test in CI. Do not guess.
  2. Edit pyproject.toml. Set the lower bound, for example requires-python = ">= 3.10". Avoid upper bounds.
  3. Fix leftover wheel tags. The guide warns that wheels built by older setuptools projects for both Python 2 and 3 were often tagged py2.py3. When dropping Python 2, change that to py3. If your config sets universal = 1 in a bdist_wheel section, remove it or set it to 0.
  4. Update classifiers. Remove version classifiers for versions you dropped, so the PyPI page matches.
  5. Build with python -m build. Do not call setup.py directly, because the guide says those commands are deprecated.
  6. Check the metadata. Open PKG-INFO in the sdist and confirm Requires-Python shows your new value.
  7. Validate with twine. The guide recommends installing twine and checking the metadata before upload.
  8. Release with a clear version bump and changelog entry. Use whichever bump your versioning policy says signals a compatibility change.

What users will see

User's PythonResult after your release
Meets the new minimumGets the new release
Below the new minimumGets the last older release that matches
Uses an installer that ignores the fieldMay get a failed install or import errors

The last row is why the guide states a requirement: this workflow relies on users installing with pip or another installer that supports metadata 1.2.

Pitfalls

  • Forgetting to tag wheels correctly. A wheel tagged for versions you no longer support is misleading.
  • Dropping and adding features in one release. If a user lands on the older release, they miss both. Keep the release focused.
  • Not backporting security fixes. Users on the older line stay on the older release. If a vulnerability affects it, decide whether to publish a patch for that line, or say plainly that it is unsupported.

That last point matters for security. Python itself stops issuing security fixes for old branches, and dependencies you pull in may drop support too. Check our note on which Python versions still get security fixes.

Safeguard's dependency scanning and SBOM generation can show which of your product's components sit on an unsupported line. A free scan is a place to start.

Quick check

Do I need to yank old releases when I drop a Python version?

No. Yanking is for broken or vulnerable releases. Old releases keep serving users on old Python.

What if a user ignores the metadata?

Installers that do not support core metadata 1.2 may fetch the newest release anyway. Mention the change in your changelog.

Should I cap the upper Python version?

The packaging guide advises against upper bounds on this field because they cause conflicts.

Sources

Last reviewed: 19 October 2026.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.