← 返回首页
PEP 763 – Limiting deletions on PyPI | peps.python.org Following system colour scheme Selected dark colour scheme Selected light colour scheme

Python Enhancement Proposals

Toggle light / dark / auto colour theme PEP 763 – Limiting deletions on PyPI

PEP 763 – Limiting deletions on PyPI

Author: William Woodruff <william at yossarian.net>, Alexis Challande <alexis.challande at trailofbits.com> Sponsor: Donald Stufft <donald at stufft.io> PEP-Delegate: Donald Stufft <donald at stufft.io> Discussions-To: Discourse thread Status: Withdrawn Type: Standards Track Topic: Packaging Created: 24-Oct-2024 Post-History: 09-Jul-2022, 01-Oct-2024, 28-Oct-2024 Resolution: 21-Sep-2025 Table of Contents

PEP Withdrawal

This PEP has been withdrawn as of 22-Sep-2025.

During discussion of the PEP, it became clear that a PEP is not necessarily the appropriate venue for changes to PyPI’s deletion policy, as PyPI’s usage policies are not presently (or necessarily should) be part of the PEP process.

Abstract

We propose limiting when users can delete files, releases, and projects from PyPI. A project, release, or file may only be deleted within 72 hours of when it is uploaded to the index. From this point, users may only use the “yank” mechanism specified by PEP 592.

An exception to this restriction is made for releases and files that are marked with pre-release specifiers, which will remain deletable at any time. The PyPI administrators will retain the ability to delete files, releases, and projects at any time, for example for moderation or security purposes.

Rationale and Motivation

As observed in PEP 592, user-level deletion of projects on PyPI enables a catch-22 situation of dependency breakage:

Whenever a project detects that a particular release on PyPI might be broken, they oftentimes will want to prevent further users from inadvertently using that version. However, the obvious solution of deleting the existing file from a repository will break users who have pinned to a specific version of the project.

This leaves projects in a catch-22 situation where new projects may be pulling down this known broken version, but if they do anything to prevent that they’ll break projects that are already using it.

On a technical level, the problem of deletion is mitigated by “yanking,” also specified in PEP 592. However, deletions continue to be allowed on PyPI, and have caused multiple notable disruptions to the Python ecosystem over the interceding years:

In addition to their disruptive effect on downstreams, deletions also have detrimental effects on PyPI’s sustainability as well as the overall security of the ecosystem:

The Python ecosystem is continuing to grow, meaning that future deletions of projects can be reasonably assumed to be just, as if not more, disruptive than the deletions sampled above.

Given all of the above, this PEP concludes that deletions now present a greater risk and detriment to the Python ecosystem than a benefit.

In addition to these technical arguments, there is also precedent from other packaging ecosystems for limiting the ability of users to delete projects and their constituent releases. This precedent is documented in Appendix A.

Specification

There are three different types of deletable objects:

  1. Files, which are individual project distributions (such as source distributions or wheels).

    Example: requests-2.32.3-py3-none-any.whl.

  2. Releases, which contain one or more files that share the same version number.

    Example: requests v2.32.3.

  3. Projects, which contain one or more releases.

    Example: requests.

Deletion eligibility rules

This PEP proposes the following deletion eligibility rules:

These rules allow new projects to be deleted entirely, and allow old projects to delete new files or releases, but do not allow old projects to delete old files or releases.

Implementation

This PEP’s implementation primarily concerns aspects of PyPI that are not standardized or subject to standardization, such as the web interface and signed-in user operations. As a result, this section describes its implementation in behavioral terms.

Changes

Security Implications

This PEP does not identify negative security implications associated with the proposed approach.

This PEP identifies one minor positive security implication: by restricting user-controlled deletions, this PEP makes it more difficult for a malicious actor to cover their tracks by deleting malware from the index. This is particularly useful for external (i.e. non-PyPI administrator) triage and incident response, where the defending party needs easy access to malware samples to develop indicators of compromise.

How To Teach This

This PEP suggests at least two pieces of public-facing material to help the larger Python packaging community (and its downstream consumers) understand its changes:

Rejected Ideas

Conditioning deletion on dependency relationships

An alternative to time-based deletion windows is deletion eligibility based on downstream dependents. For example, a release could be considered deletable if and only if it has fewer than N downstream dependents on PyPI, where N could be as low as 1.

This idea is appealing since it directly links deletion eligibility to disruptiveness. npm uses it and conditions project removal on the absence of any downstream dependencies known to the index.

Despite its appeal, this PEP identifies several disadvantages and technical limitations that make dependency-conditioned deletion not appropriate for PyPI:

  1. PyPI is not aware of dependency relationships. In Python packaging, both project builds and metadata generation are frequently dynamic operations, involving arbitrary project-specified code. This is typified by source distributions containing setup.py scripts, where the execution of setup.py is responsible for computing the set of dependencies encoded in the project’s metadata.

    This is in marked contrast to ecosystems like npm and Rust’s crates, where project builds can be dynamic but the project’s metadata itself is static.

    As a result of this, PyPI doesn’t know your project’s dependencies, and is architecturally incapable of knowing them without either running arbitrary code (a significant security risk) or performing a long-tail deprecation of setup.py-based builds in favor of PEP 517 and PEP 621-style static metadata.

  2. Results in an unintuitive permissions model. Dependency-conditioned deletion results in a “reversed” power relationship, where anybody who introduces a dependency on a project can prevent that project from being deleted.

    This is reasonable on face value, but can be abused to produce unexpected and undesirable (in the context of enabling some deletions) outcomes. A notable example of this is npm’s everything package, which depends on every public package on npm (as of 30 Dec 2023) and thereby prevents their deletion.

Conditioning deletion on download count

Another alternative to time-based deletion windows is to delete based on the number of downloads. For example, a release could be considered deletable if and only if it has fewer than N downloads during the last period.

While presenting advantages by tying a project deletion possibility to its usage, this PEP identifies several limitations to this approach:

  1. Ecosystem diversity. The Python ecosystem includes projects with widely varying usage patterns. A fixed download threshold would not adequately account for niche but critical projects with naturally low download counts.
  2. Time sensitivity. Download counts do not necessarily reflect a project’s current status or importance. A previously popular project might have low recent downloads but still be crucial for maintaining older systems.
  3. Technical complexity. Accessing the download count of a project within PyPI is not straightforward, and there is limited possibility to gather a project’s download statistics from mirrors or other distributions systems.

Appendix A: Precedent in other ecosystems

The following is a table of support for deletion in different packaging ecosystems. An ecosystem is considered to not support deletion if it restrict’s a user’s ability to perform deletions in a manner similar to this PEP.

An earlier version of this table, showing only deletion, was compiled by Donald Stufft and others on the Python discussion forum in July 2022.

Ecosystem (Index) Deletion Yanking Notes
Python (PyPI) [1] [2] Deletion currently completely unrestricted.
Rust (crates.io) [3] Deletion by users not allowed at all.
JavaScript (npm) [4] [5] Deletion is limited by criteria similar to this PEP.
Ruby (RubyGems) [6] RubyGems calls deletion “yanking.” Yanking in PyPI’s terms is not supported at all.
Java (Maven Central) [7] Deletion by users not allowed at all.
PHP (Packagist) [8] Deletion restricted after an undocumented number of installs.
.NET (NuGet) [9] [10] NuGet calls yanking “unlisting.”
Elixir (Hex) [11] [11] Hex calls yanking “retiring.”
R (CRAN) [12] [12] Deletion is limited to within 24 hours of initial release or 60 minutes for subsequent versions. CRAN calls yanking “archiving.”
Perl (CPAN) Yanking is not supported at all. Deletion seemingly encouraged, at least as of 2021 [13].
Lua (LuaRocks) [14] [14] LuaRocks calls yanking “archiving.”
Haskell (Hackage) [15] [16] Hackage calls yanking “deprecating.”
OCaml (OPAM) [17] [17] Deletion is allowed if it occurs “reasonably soon” after inclusion. Yanking is de facto supported by the available: false marker, which effectively disables resolution.

The following trends are present:

Footnotes

[1] https://pypi.org/help/#deletion [2] https://pypi.org/help/#yanked [3] https://doc.rust-lang.org/cargo/commands/cargo-yank.html [4] https://docs.npmjs.com/unpublishing-packages-from-the-registry [5] https://docs.npmjs.com/deprecating-and-undeprecating-packages-or-package-versions [6] https://guides.rubygems.org/removing-a-published-gem/ [7] https://central.sonatype.org/faq/can-i-change-a-component/ [8] https://github.com/composer/packagist/issues/875 [9] https://learn.microsoft.com/en-us/nuget/nuget-org/policies/deleting-packages [10] https://learn.microsoft.com/en-us/nuget/nuget-org/policies/deleting-packages#unlisting-a-package [11] (1, 2) https://hex.pm/docs/faq#can-packages-be-removed-from-the-repository [12] (1, 2) https://cran.r-project.org/web/packages/policies.html [13] https://neilb.org/2021/05/10/delete-your-old-releases.html [14] (1, 2) https://luarocks.org/changes [15] https://hackage.haskell.org/upload [16] https://hackage.haskell.org/packages/deprecated [17] (1, 2) https://github.com/ocaml/opam-repository/wiki/Policies#1-removal-of-packages-should-be-avoided

Copyright

This document is placed in the public domain or under the CC0-1.0-Universal license, whichever is more permissive.

Contents


Page Source (GitHub)

Source: https://github.com/python/peps/blob/main/peps/pep-0763.rst

Last modified: 2025-09-29 13:35:57 UTC