PyPI limits how long a release can gain new files
PyPI now rejects uploads to releases older than fourteen days. The restriction addresses a gap between pinning a version and fixing the set of artifacts available under that version.
An old package version could acquire a new distribution file long after users had decided to trust it. PyPI's July 22 announcement closes much of that opportunity by rejecting new files for releases older than fourteen days. The restriction targets the possibility that a stolen publishing credential could poison a long-stable release with additional files.
The announcement also limits what consumers should infer. PyPI says users should not yet rely on the behavior as a defined closed-release contract. There is no API to confirm that state, and the formal semantics are intended to accompany the Upload 2.0 and staged-preview work. The immediate protection is an enforced upload restriction, not a new installer-visible proof of immutability.
Python packaging is the part of the language's ecosystem I find hardest to like. This change addresses a particular ambiguity that contributes to that view. Choosing a version feels like choosing a release, but the release may contain several artifacts with different compatibility tags. Fixing the version does not necessarily fix which bytes an installer can select.
A release contains multiple installation artifacts
The wheel format described in PEP 427 includes compatibility information in the filename. A wheel identifies its Python compatibility, ABI requirements, and platform. Multiple wheels can therefore belong to one package version while serving different environments.
That arrangement solves a real deployment problem. A binary extension needs an artifact compatible with the interpreter and system that will load it. Building the extension once and distributing the resulting wheel avoids rebuilding it in every target environment. The format separates producing an installable package from installing it.
It also means that the package version is a coarser identity than the distribution file. Two machines can request the same version and legitimately select different wheels. A source distribution supplies another path, with its own build step. A release is consequently a collection of possible installation inputs, not one universal archive.
The late-upload behavior allowed that collection to expand over time. A platform for which no wheel existed could later receive one under the same version. That was useful when maintainers added support for a newer Python interpreter without publishing another version of the package. It also created the opportunity that PyPI now restricts.
For a compromised publisher, adding a malicious artifact to a familiar old version could exploit the confidence attached to that version. The new artifact would not share the history of the existing files merely because it shared their release number. This is the design risk described by the announcement, not evidence that such an attack has already happened. PyPI says it is not aware of prior abuse of this mechanism.
The compatibility cost was examined
The announcement traces discussion of the restriction to January 2024, during work on digital attestations. It resumed after the LiteLLM and Telnyx compromises in March. The objection was practical: some projects depended on late uploads to add interpreter compatibility to existing releases.
PyPI examined upload data to estimate the disruption. Among the top fifteen thousand packages, it found fifty-six projects that had added a CPython 3.14-compatible wheel more than fourteen days after the release. The Packaging Summit discussion supported requiring a version increment for that later compatibility work. The implementation merged on July 8.
The resulting policy moves a release-management decision into the version history. Once a release is outside the window, supplying another wheel requires a newer release. That makes a newly available installation artifact correspond to a new version choice. Consumers can evaluate the newer release as a dependency update instead of discovering that an old choice now includes another option.
The cost falls most directly on maintainers who previously extended old releases. They must prepare another release even if their Python source has not changed. The benefit is a smaller set of old releases that a newly compromised publishing route can alter by adding artifacts. The policy reflects a decision about that balance, with evidence about actual upload behavior behind it.
Locks identify files more precisely
PEP 751 addresses the consumer side through a reproducible installation record. Its format can record the distribution files and their hashes, allowing installation without repeating dependency resolution. That provides a more precise input than a version constraint alone.
A file hash identifies the selected contents. Another wheel with a different filename and hash is a different input even when it uses the same package version. Recording acceptable artifacts in a lock gives the installation process a way to preserve the earlier choice. The age restriction and the lock therefore constrain different operations.
The distinction matters for multiple target environments. A lock may contain several compatible artifacts so that each target can select its appropriate file. Reproducibility then means selecting from the recorded set according to the environment, not forcing every machine to install the same incompatible binary. Reviewing that set is part of reviewing what the application can consume.
Hashes do not certify that a file is benign. They establish whether the retrieved bytes match the recorded bytes. Similarly, rejecting late uploads does not certify the files that arrived during the permitted period. Each mechanism has a narrower claim that remains useful without becoming a complete security judgment.
Formal closure needs a protocol
The broader direction is described by PEP 694, the draft Upload 2.0 proposal. Its motivation includes the legacy upload API's use of a single file as the unit of publication. A release with several wheels and a source distribution can become visible incrementally as files arrive, so consumers may observe an incomplete set.
Staging and publishing a set of artifacts together would give release management a more explicit operation. That is related to closing a release, but the July announcement does not claim that the complete proposal is already available. Its warning about missing closure semantics prevents consumers from assuming the upload restriction supplies those interfaces.
The immediate rule is still useful for maintainers planning their release matrix. Required wheels need to arrive within the permitted period, or their addition needs another package version. For consumers, artifact hashes remain the direct record of the bytes selected for an application. The announced restriction reduces late changes to older releases while work on an explicit publication protocol continues.