Safeguard
Developer Tools•

How should you set requires-python for a Python library?

Set requires-python to the oldest Python you test, add no upper cap, and know how pip uses it to pick older releases. Syntax examples and common mistakes.

Safeguard Security Team
4 min read

Set requires-python to the oldest Python version you actually test, written as a lower bound such as >= 3.9. Avoid upper bounds. Installers use this field to skip releases that do not match the user's Python, so a wrong value either blocks users or lets broken installs through.

What the field does

requires-python in the project table maps to the Requires-Python core metadata field. The packaging guide describes it as declaring the minimum version of Python you support. Installers that understand this metadata, including pip, compare it to the running interpreter.

If your newest release does not match, pip looks back through older releases until it finds one that does. That behaviour is what lets you drop old Python versions without stranding users on old interpreters.

Syntax

[project]
requires-python = ">= 3.9"

You can also exclude specific point releases.

requires-python = ">= 3.7, != 3.7.0, != 3.7.1"

The guide says exclusion rules must follow the version specifiers specification. For how those operators behave, see our explainer on compatible release versus exact match.

Why not add an upper cap

The packaging guide says to avoid upper bounds on this field, for example >= 3.8, < 3.10, because they can cause different errors and version conflicts. The reason is practical. Dependency resolvers need to find a set of versions that all agree. If your library caps Python below a future release, every project that uses your library is blocked from upgrading Python, even if your code would have worked.

If a future Python release truly breaks your code, release a fix or a new version, not a pre emptive ban.

Requires-python versus classifiers

Classifiers like "Programming Language :: Python :: 3.12" are for search and browsing on PyPI. The guide states plainly that this information is not used for installing. Only requires-python restricts what can be installed.

FieldControls installsShows on PyPI
requires-pythonYesAs metadata
Python version classifiersNoYes, for browsing

Choosing the lower bound

  1. List the Python versions your CI runs.
  2. Take the oldest one that passes.
  3. Use that as the lower bound.
  4. Remove the bound's old versions from CI only when you also change the field.

Do not claim a version you do not test. A lower bound is a promise to every user on that version.

Keep it honest over time

When a Python release reaches end of life, many libraries raise their lower bound at the next major or minor release. Doing so is safe for existing users, because pip falls back to the last release that supports their interpreter. We cover the mechanics in how to drop support for an old Python version.

Safeguard's dependency scanning and SBOM generation record the versions your product resolves to. A free scan shows what you ship today.

Quick check

Does requires-python affect old releases already on PyPI?

Metadata is stored per release. Changing the field only affects the release you build next.

Is the Python classifier enough to block old interpreters?

No. Classifiers are for searching and browsing. Use requires-python to restrict installs.

Should I set an upper bound for the next Python release?

The packaging guide advises against it, because it can cause resolver errors and blocks users from upgrading.

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.