CINXE.COM
PEP 763 – Limiting deletions on PyPI | peps.python.org
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="color-scheme" content="light dark"> <title>PEP 763 – Limiting deletions on PyPI | peps.python.org</title> <link rel="shortcut icon" href="../_static/py.png"> <link rel="canonical" href="https://peps.python.org/pep-0763/"> <link rel="stylesheet" href="../_static/style.css" type="text/css"> <link rel="stylesheet" href="../_static/mq.css" type="text/css"> <link rel="stylesheet" href="../_static/pygments.css" type="text/css" media="(prefers-color-scheme: light)" id="pyg-light"> <link rel="stylesheet" href="../_static/pygments_dark.css" type="text/css" media="(prefers-color-scheme: dark)" id="pyg-dark"> <link rel="alternate" type="application/rss+xml" title="Latest PEPs" href="https://peps.python.org/peps.rss"> <meta property="og:title" content='PEP 763 – Limiting deletions on PyPI | peps.python.org'> <meta property="og:description" content="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..."> <meta property="og:type" content="website"> <meta property="og:url" content="https://peps.python.org/pep-0763/"> <meta property="og:site_name" content="Python Enhancement Proposals (PEPs)"> <meta property="og:image" content="https://peps.python.org/_static/og-image.png"> <meta property="og:image:alt" content="Python PEPs"> <meta property="og:image:width" content="200"> <meta property="og:image:height" content="200"> <meta name="description" content="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..."> <meta name="theme-color" content="#3776ab"> </head> <body> <svg xmlns="http://www.w3.org/2000/svg" style="display: none;"> <symbol id="svg-sun-half" viewBox="0 0 24 24" pointer-events="all"> <title>Following system colour scheme</title> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <circle cx="12" cy="12" r="9"></circle> <path d="M12 3v18m0-12l4.65-4.65M12 14.3l7.37-7.37M12 19.6l8.85-8.85"></path> </svg> </symbol> <symbol id="svg-moon" viewBox="0 0 24 24" pointer-events="all"> <title>Selected dark colour scheme</title> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <path stroke="none" d="M0 0h24v24H0z" fill="none"></path> <path d="M12 3c.132 0 .263 0 .393 0a7.5 7.5 0 0 0 7.92 12.446a9 9 0 1 1 -8.313 -12.454z"></path> </svg> </symbol> <symbol id="svg-sun" viewBox="0 0 24 24" pointer-events="all"> <title>Selected light colour scheme</title> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <circle cx="12" cy="12" r="5"></circle> <line x1="12" y1="1" x2="12" y2="3"></line> <line x1="12" y1="21" x2="12" y2="23"></line> <line x1="4.22" y1="4.22" x2="5.64" y2="5.64"></line> <line x1="18.36" y1="18.36" x2="19.78" y2="19.78"></line> <line x1="1" y1="12" x2="3" y2="12"></line> <line x1="21" y1="12" x2="23" y2="12"></line> <line x1="4.22" y1="19.78" x2="5.64" y2="18.36"></line> <line x1="18.36" y1="5.64" x2="19.78" y2="4.22"></line> </svg> </symbol> </svg> <script> document.documentElement.dataset.colour_scheme = localStorage.getItem("colour_scheme") || "auto" </script> <section id="pep-page-section"> <header> <h1>Python Enhancement Proposals</h1> <ul class="breadcrumbs"> <li><a href="https://www.python.org/" title="The Python Programming Language">Python</a> » </li> <li><a href="../pep-0000/">PEP Index</a> » </li> <li>PEP 763</li> </ul> <button id="colour-scheme-cycler" onClick="setColourScheme(nextColourScheme())"> <svg aria-hidden="true" class="colour-scheme-icon-when-auto"><use href="#svg-sun-half"></use></svg> <svg aria-hidden="true" class="colour-scheme-icon-when-dark"><use href="#svg-moon"></use></svg> <svg aria-hidden="true" class="colour-scheme-icon-when-light"><use href="#svg-sun"></use></svg> <span class="visually-hidden">Toggle light / dark / auto colour theme</span> </button> </header> <article> <section id="pep-content"> <h1 class="page-title">PEP 763 – Limiting deletions on PyPI</h1> <dl class="rfc2822 field-list simple"> <dt class="field-odd">Author<span class="colon">:</span></dt> <dd class="field-odd">William Woodruff <william at yossarian.net>, Alexis Challande <alexis.challande at trailofbits.com></dd> <dt class="field-even">Sponsor<span class="colon">:</span></dt> <dd class="field-even">Donald Stufft <donald at stufft.io></dd> <dt class="field-odd">PEP-Delegate<span class="colon">:</span></dt> <dd class="field-odd">Donald Stufft <donald at stufft.io></dd> <dt class="field-even">Discussions-To<span class="colon">:</span></dt> <dd class="field-even"><a class="reference external" href="https://discuss.python.org/t/69487">Discourse thread</a></dd> <dt class="field-odd">Status<span class="colon">:</span></dt> <dd class="field-odd"><abbr title="Proposal under active discussion and revision">Draft</abbr></dd> <dt class="field-even">Type<span class="colon">:</span></dt> <dd class="field-even"><abbr title="Normative PEP with a new feature for Python, implementation change for CPython or interoperability standard for the ecosystem">Standards Track</abbr></dd> <dt class="field-odd">Topic<span class="colon">:</span></dt> <dd class="field-odd"><a class="reference external" href="../topic/packaging/">Packaging</a></dd> <dt class="field-even">Created<span class="colon">:</span></dt> <dd class="field-even">24-Oct-2024</dd> <dt class="field-odd">Post-History<span class="colon">:</span></dt> <dd class="field-odd"><a class="reference external" href="https://discuss.python.org/t/17227" title="Discourse thread">09-Jul-2022</a>, <a class="reference external" href="https://discuss.python.org/t/66351" title="Discourse thread">01-Oct-2024</a>, <a class="reference external" href="https://discuss.python.org/t/69487" title="Discourse thread">28-Oct-2024</a></dd> </dl> <hr class="docutils" /> <section id="contents"> <details><summary>Table of Contents</summary><ul class="simple"> <li><a class="reference internal" href="#abstract">Abstract</a></li> <li><a class="reference internal" href="#rationale-and-motivation">Rationale and Motivation</a></li> <li><a class="reference internal" href="#specification">Specification</a><ul> <li><a class="reference internal" href="#deletion-eligibility-rules">Deletion eligibility rules</a></li> </ul> </li> <li><a class="reference internal" href="#implementation">Implementation</a><ul> <li><a class="reference internal" href="#changes">Changes</a></li> </ul> </li> <li><a class="reference internal" href="#security-implications">Security Implications</a></li> <li><a class="reference internal" href="#how-to-teach-this">How To Teach This</a></li> <li><a class="reference internal" href="#rejected-ideas">Rejected Ideas</a><ul> <li><a class="reference internal" href="#conditioning-deletion-on-dependency-relationships">Conditioning deletion on dependency relationships</a></li> <li><a class="reference internal" href="#conditioning-deletion-on-download-count">Conditioning deletion on download count</a></li> </ul> </li> <li><a class="reference internal" href="#appendix-a-precedent-in-other-ecosystems">Appendix A: Precedent in other ecosystems</a></li> <li><a class="reference internal" href="#footnotes">Footnotes</a></li> <li><a class="reference internal" href="#copyright">Copyright</a></li> </ul> </details></section> <section id="abstract"> <h2><a class="toc-backref" href="#abstract" role="doc-backlink">Abstract</a></h2> <p>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 <a class="pep reference internal" href="../pep-0592/" title="PEP 592 – Adding “Yank” Support to the Simple API">PEP 592</a>.</p> <p>An exception to this restriction is made for releases and files that are marked with <a class="reference external" href="https://packaging.python.org/en/latest/specifications/version-specifiers/#version-specifiers" title="(in Python Packaging User Guide)"><span class="xref std std-ref">pre-release specifiers</span></a>, 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.</p> </section> <section id="rationale-and-motivation"> <h2><a class="toc-backref" href="#rationale-and-motivation" role="doc-backlink">Rationale and Motivation</a></h2> <p>As observed in <a class="pep reference internal" href="../pep-0592/" title="PEP 592 – Adding “Yank” Support to the Simple API">PEP 592</a>, user-level deletion of projects on PyPI enables a catch-22 situation of dependency breakage:</p> <blockquote> <div>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.<p>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.</p> </div></blockquote> <p>On a technical level, the problem of deletion is mitigated by “yanking,” also specified in <a class="pep reference internal" href="../pep-0592/" title="PEP 592 – Adding “Yank” Support to the Simple API">PEP 592</a>. However, deletions continue to be allowed on PyPI, and have caused multiple notable disruptions to the Python ecosystem over the interceding years:</p> <ul> <li>July 2022: <a class="reference external" href="https://pypi.org/project/atomicwrites/">atomicwrites</a> was <a class="reference external" href="https://github.com/untitaker/python-atomicwrites/issues/61">deleted by its maintainer</a> in an attempt to remove the project’s “critical” designation, without the maintainer realizing that project deletion would also delete all previously uploaded releases.<p>The project was subsequently restored with the maintainer’s consent, but at the cost of manual administrator action and extensive downstream breakage to projects like <a class="reference external" href="https://github.com/pytest-dev/pytest/issues/10114">pytest</a>. As of October 2024, atomicwrites is archived but still has around <a class="reference external" href="https://pypistats.org/packages/atomicwrites">4.5 million monthly downloads from PyPI</a>.</p> </li> <li>April 2023: <a class="reference external" href="https://pypi.org/project/codecov/">codecov</a> was deleted by its maintainers after a long deprecation period. This caused extensive breakage for many of Codecov’s CI/CD users, who were unaware of the deprecation period due to limited observability of deprecation warnings within CI/CD logs.<p>The project was <a class="reference external" href="https://about.codecov.io/blog/message-regarding-the-pypi-package/">subsequently re-created</a> by its maintainers, with a new release published to compensate for the deleted releases (which were not restored), meaning that any pinned installations remained broken. As of October 2024, this single release remains the only release on PyPI and has around <a class="reference external" href="https://pypistats.org/packages/codecov">1.5 million monthly downloads</a>.</p> </li> <li>June 2023: <a class="reference external" href="https://pypi.org/project/python-sonarqube-api/">python-sonarqube-api</a> deleted all released releases prior to 2.0.2.<p>The project’s maintainer subsequently <a class="reference external" href="https://discuss.python.org/t/stop-allowing-deleting-things-from-pypi/17227/114">deleted conversations</a> and force-pushed over the tag history for <code class="docutils literal notranslate"><span class="pre">python-sonarqube-api</span></code>’s source repository, impeding efforts by users to compare changes between releases.</p> </li> <li>June 2024: <a class="reference external" href="https://pypi.org/project/PySimpleGUI/">PySimpleGUI</a> changed licenses and deleted <a class="reference external" href="https://discuss.python.org/t/48790/27">nearly all previous releases</a>. This resulted in widespread disruption for users, who (prior to the relicensing) were downloading PySimpleGUI approximately 25,000 times a day.</li> </ul> <p>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:</p> <ul class="simple"> <li>Deletions increase support workload for PyPI’s administrators and moderators, as users mistakenly file support requests believing that PyPI is broken, or that the administrators themselves have removed the project.</li> <li>Deletions impair external (meaning end-user) incident response and analysis, making it difficult to distinguish “good faith” maintainer behavior from a malicious actor attempting the cover their tracks.</li> </ul> <p>The Python ecosystem is continuing to grow, meaning that future deletions of projects can be reasonably assumed to be <em>just, as if not more,</em> disruptive than the deletions sampled above.</p> <p>Given all of the above, this PEP concludes that deletions now present a greater risk and detriment to the Python ecosystem than a benefit.</p> <p>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 <a class="reference internal" href="#pep763-appendix-a"><span class="std std-ref">Appendix A</span></a>.</p> </section> <section id="specification"> <h2><a class="toc-backref" href="#specification" role="doc-backlink">Specification</a></h2> <p>There are three different types of deletable objects:</p> <ol class="arabic"> <li><strong>Files</strong>, which are individual project distributions (such as source distributions or wheels).<p>Example: <code class="docutils literal notranslate"><span class="pre">requests-2.32.3-py3-none-any.whl</span></code>.</p> </li> <li><strong>Releases</strong>, which contain one or more files that share the same version number.<p>Example: <a class="reference external" href="https://pypi.org/project/requests/2.32.3/">requests v2.32.3</a>.</p> </li> <li><strong>Projects</strong>, which contain one or more releases.<p>Example: <a class="reference external" href="https://pypi.org/project/requests">requests</a>.</p> </li> </ol> <section id="deletion-eligibility-rules"> <h3><a class="toc-backref" href="#deletion-eligibility-rules" role="doc-backlink">Deletion eligibility rules</a></h3> <p>This PEP proposes the following <em>deletion eligibility rules</em>:</p> <ul class="simple"> <li>A <strong>file</strong> is deletable if and only if it was uploaded to PyPI less than 72 hours from the current time, <strong>or</strong> if it has a <a class="reference external" href="https://packaging.python.org/en/latest/specifications/version-specifiers/#version-specifiers" title="(in Python Packaging User Guide)"><span class="xref std std-ref">pre-release specifier</span></a>.</li> <li>A <strong>release</strong> is deletable if and only if all of its contained files are deletable.</li> <li>A <strong>project</strong> is deletable if and only if all of its releases are deletable.</li> </ul> <p>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.</p> </section> </section> <section id="implementation"> <h2><a class="toc-backref" href="#implementation" role="doc-backlink">Implementation</a></h2> <p>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.</p> <section id="changes"> <h3><a class="toc-backref" href="#changes" role="doc-backlink">Changes</a></h3> <ul class="simple"> <li>Per the eligibility rules above, PyPI will reject web interface requests (using an appropriate HTTP response code of its choosing) for file, release, or project deletion if the respective object is not eligible for deletion.</li> <li>PyPI will amend its web interface to indicate a file/release/project’s deletion ineligibility, e.g. by styling the relevant UI elements as “inactive” and making relevant bottoms/forms unclickable.</li> </ul> </section> </section> <section id="security-implications"> <h2><a class="toc-backref" href="#security-implications" role="doc-backlink">Security Implications</a></h2> <p>This PEP does not identify negative security implications associated with the proposed approach.</p> <p>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.</p> </section> <section id="how-to-teach-this"> <h2><a class="toc-backref" href="#how-to-teach-this" role="doc-backlink">How To Teach This</a></h2> <p>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:</p> <ul class="simple"> <li>An announcement post on the <a class="reference external" href="https://blog.pypi.org">PyPI blog</a> explaining the nature of the PEP, its motivations, and its behavioral implications for PyPI.</li> <li>An announcement banner on PyPI itself, linking to the above.</li> <li>Updates to the <a class="reference external" href="https://docs.pypi.org/">PyPI user documentation</a> explaining the difference between deletion and yanking and the limited conditions under which the former can still be initiated by package owners.</li> </ul> </section> <section id="rejected-ideas"> <h2><a class="toc-backref" href="#rejected-ideas" role="doc-backlink">Rejected Ideas</a></h2> <section id="conditioning-deletion-on-dependency-relationships"> <h3><a class="toc-backref" href="#conditioning-deletion-on-dependency-relationships" role="doc-backlink">Conditioning deletion on dependency relationships</a></h3> <p>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 <code class="docutils literal notranslate"><span class="pre">N</span></code> downstream dependents on PyPI, where <code class="docutils literal notranslate"><span class="pre">N</span></code> could be as low as 1.</p> <p>This idea is appealing since it directly links deletion eligibility to disruptiveness. <a class="reference external" href="https://www.npmjs.com/">npm</a> uses it and conditions project removal on the absence of any downstream dependencies known to the index.</p> <p>Despite its appeal, this PEP identifies several disadvantages and technical limitations that make dependency-conditioned deletion not appropriate for PyPI:</p> <ol class="arabic"> <li><em>PyPI is not aware of dependency relationships.</em> In Python packaging, both project builds <em>and</em> metadata generation are frequently dynamic operations, involving arbitrary project-specified code. This is typified by source distributions containing <code class="docutils literal notranslate"><span class="pre">setup.py</span></code> scripts, where the execution of <code class="docutils literal notranslate"><span class="pre">setup.py</span></code> is responsible for computing the set of dependencies encoded in the project’s metadata.<p>This is in marked contrast to ecosystems like npm and Rust’s <a class="reference external" href="https://crates.io/">crates</a>, where project <em>builds</em> can be dynamic but the project’s metadata itself is static.</p> <p>As a result of this, <a class="reference external" href="https://dustingram.com/articles/2018/03/05/why-pypi-doesnt-know-dependencies/">PyPI doesn’t know your project’s dependencies</a>, and is architecturally incapable of knowing them without either running arbitrary code (a significant security risk) or performing a long-tail deprecation of <code class="docutils literal notranslate"><span class="pre">setup.py</span></code>-based builds in favor of <a class="pep reference internal" href="../pep-0517/" title="PEP 517 – A build-system independent format for source trees">PEP 517</a> and <a class="pep reference internal" href="../pep-0621/" title="PEP 621 – Storing project metadata in pyproject.toml">PEP 621</a>-style static metadata.</p> </li> <li><em>Results in an unintuitive permissions model.</em> 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.<p>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 <a class="reference external" href="https://www.npmjs.com/package/everything">everything package</a>, which depends on every public package on npm (as of 30 Dec 2023) and thereby prevents their deletion.</p> </li> </ol> </section> <section id="conditioning-deletion-on-download-count"> <h3><a class="toc-backref" href="#conditioning-deletion-on-download-count" role="doc-backlink">Conditioning deletion on download count</a></h3> <p>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 <code class="docutils literal notranslate"><span class="pre">N</span></code> downloads during the last period.</p> <p>While presenting advantages by tying a project deletion possibility to its usage, this PEP identifies several limitations to this approach:</p> <ol class="arabic simple"> <li><em>Ecosystem diversity.</em> 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.</li> <li><em>Time sensitivity.</em> 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.</li> <li><em>Technical complexity.</em> 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.</li> </ol> </section> </section> <section id="appendix-a-precedent-in-other-ecosystems"> <span id="pep763-appendix-a"></span><h2><a class="toc-backref" href="#appendix-a-precedent-in-other-ecosystems" role="doc-backlink">Appendix A: Precedent in other ecosystems</a></h2> <p>The following is a table of support for deletion in different packaging ecosystems. An ecosystem is considered to <strong>not</strong> support deletion if it restrict’s a user’s ability to perform deletions in a manner similar to this PEP.</p> <p>An earlier version of this table, showing only deletion, was compiled by Donald Stufft and others on the Python discussion forum in <a class="reference external" href="https://discuss.python.org/t/17227/59">July 2022</a>.</p> <table class="docutils align-default"> <thead> <tr class="row-odd"><th class="head">Ecosystem (Index)</th> <th class="head">Deletion</th> <th class="head">Yanking</th> <th class="head">Notes</th> </tr> </thead> <tbody> <tr class="row-even"><td>Python (PyPI)</td> <td>✅ <a class="footnote-reference brackets" href="#f1" id="id1">[1]</a></td> <td>✅ <a class="footnote-reference brackets" href="#f2" id="id2">[2]</a></td> <td>Deletion currently completely unrestricted.</td> </tr> <tr class="row-odd"><td>Rust (crates.io)</td> <td>❌</td> <td>✅ <a class="footnote-reference brackets" href="#f3" id="id3">[3]</a></td> <td>Deletion by users not allowed at all.</td> </tr> <tr class="row-even"><td>JavaScript (npm)</td> <td>❌ <a class="footnote-reference brackets" href="#f4" id="id4">[4]</a></td> <td>✅ <a class="footnote-reference brackets" href="#f5" id="id5">[5]</a></td> <td>Deletion is limited by criteria similar to this PEP.</td> </tr> <tr class="row-odd"><td>Ruby (RubyGems)</td> <td>✅ <a class="footnote-reference brackets" href="#f6" id="id6">[6]</a></td> <td>❌</td> <td>RubyGems calls deletion “yanking.” Yanking in PyPI’s terms is not supported at all.</td> </tr> <tr class="row-even"><td>Java (Maven Central)</td> <td>❌ <a class="footnote-reference brackets" href="#f7" id="id7">[7]</a></td> <td>❌</td> <td>Deletion by users not allowed at all.</td> </tr> <tr class="row-odd"><td>PHP (Packagist)</td> <td>❌ <a class="footnote-reference brackets" href="#f8" id="id8">[8]</a></td> <td>❌</td> <td>Deletion restricted after an undocumented number of installs.</td> </tr> <tr class="row-even"><td>.NET (NuGet)</td> <td>❌ <a class="footnote-reference brackets" href="#f9" id="id9">[9]</a></td> <td>✅ <a class="footnote-reference brackets" href="#f10" id="id10">[10]</a></td> <td>NuGet calls yanking “unlisting.”</td> </tr> <tr class="row-odd"><td>Elixir (Hex)</td> <td>❌ <a class="footnote-reference brackets" href="#f11" id="id11">[11]</a></td> <td>✅ <a class="footnote-reference brackets" href="#f11" id="id12">[11]</a></td> <td>Hex calls yanking “retiring.”</td> </tr> <tr class="row-even"><td>R (CRAN)</td> <td>❌ <a class="footnote-reference brackets" href="#f12" id="id13">[12]</a></td> <td>✅ <a class="footnote-reference brackets" href="#f12" id="id14">[12]</a></td> <td>Deletion is limited to within 24 hours of initial release or 60 minutes for subsequent versions. CRAN calls yanking “archiving.”</td> </tr> <tr class="row-odd"><td>Perl (CPAN)</td> <td>✅</td> <td>❌</td> <td>Yanking is not supported at all. Deletion seemingly encouraged, at least as of 2021 <a class="footnote-reference brackets" href="#f13" id="id15">[13]</a>.</td> </tr> <tr class="row-even"><td>Lua (LuaRocks)</td> <td>✅ <a class="footnote-reference brackets" href="#f14" id="id16">[14]</a></td> <td>✅ <a class="footnote-reference brackets" href="#f14" id="id17">[14]</a></td> <td>LuaRocks calls yanking “archiving.”</td> </tr> <tr class="row-odd"><td>Haskell (Hackage)</td> <td>❌ <a class="footnote-reference brackets" href="#f15" id="id18">[15]</a></td> <td>✅ <a class="footnote-reference brackets" href="#f16" id="id19">[16]</a></td> <td>Hackage calls yanking “deprecating.”</td> </tr> <tr class="row-even"><td>OCaml (OPAM)</td> <td>❌ <a class="footnote-reference brackets" href="#f17" id="id20">[17]</a></td> <td>✅ <a class="footnote-reference brackets" href="#f17" id="id21">[17]</a></td> <td>Deletion is allowed if it occurs “reasonably soon” after inclusion. Yanking is <em>de facto</em> supported by the <code class="docutils literal notranslate"><span class="pre">available:</span> <span class="pre">false</span></code> marker, which effectively disables resolution.</td> </tr> </tbody> </table> <p>The following trends are present:</p> <ul class="simple"> <li>A strong majority of indices <strong>do not</strong> support deletion (9 vs. 4)</li> <li>A strong majority of indices <strong>do</strong> support yanking (9 vs. 4)</li> <li>An overwhelming majority of indices support one or the other or neither, but <strong>not</strong> both (11 vs. 2)<ul> <li>PyPI and LuaRocks are notable outliers in supporting <strong>both</strong> deletion and yanking.</li> </ul> </li> </ul> </section> <section id="footnotes"> <h2><a class="toc-backref" href="#footnotes" role="doc-backlink">Footnotes</a></h2> <aside class="footnote-list brackets"> <aside class="footnote brackets" id="f1" role="doc-footnote"> <dt class="label" id="f1">[<a href="#id1">1</a>]</dt> <dd><a class="reference external" href="https://pypi.org/help/#deletion">https://pypi.org/help/#deletion</a></aside> <aside class="footnote brackets" id="f2" role="doc-footnote"> <dt class="label" id="f2">[<a href="#id2">2</a>]</dt> <dd><a class="reference external" href="https://pypi.org/help/#yanked">https://pypi.org/help/#yanked</a></aside> <aside class="footnote brackets" id="f3" role="doc-footnote"> <dt class="label" id="f3">[<a href="#id3">3</a>]</dt> <dd><a class="reference external" href="https://doc.rust-lang.org/cargo/commands/cargo-yank.html">https://doc.rust-lang.org/cargo/commands/cargo-yank.html</a></aside> <aside class="footnote brackets" id="f4" role="doc-footnote"> <dt class="label" id="f4">[<a href="#id4">4</a>]</dt> <dd><a class="reference external" href="https://docs.npmjs.com/unpublishing-packages-from-the-registry">https://docs.npmjs.com/unpublishing-packages-from-the-registry</a></aside> <aside class="footnote brackets" id="f5" role="doc-footnote"> <dt class="label" id="f5">[<a href="#id5">5</a>]</dt> <dd><a class="reference external" href="https://docs.npmjs.com/deprecating-and-undeprecating-packages-or-package-versions">https://docs.npmjs.com/deprecating-and-undeprecating-packages-or-package-versions</a></aside> <aside class="footnote brackets" id="f6" role="doc-footnote"> <dt class="label" id="f6">[<a href="#id6">6</a>]</dt> <dd><a class="reference external" href="https://guides.rubygems.org/removing-a-published-gem/">https://guides.rubygems.org/removing-a-published-gem/</a></aside> <aside class="footnote brackets" id="f7" role="doc-footnote"> <dt class="label" id="f7">[<a href="#id7">7</a>]</dt> <dd><a class="reference external" href="https://central.sonatype.org/faq/can-i-change-a-component/">https://central.sonatype.org/faq/can-i-change-a-component/</a></aside> <aside class="footnote brackets" id="f8" role="doc-footnote"> <dt class="label" id="f8">[<a href="#id8">8</a>]</dt> <dd><a class="reference external" href="https://github.com/composer/packagist/issues/875">https://github.com/composer/packagist/issues/875</a></aside> <aside class="footnote brackets" id="f9" role="doc-footnote"> <dt class="label" id="f9">[<a href="#id9">9</a>]</dt> <dd><a class="reference external" href="https://learn.microsoft.com/en-us/nuget/nuget-org/policies/deleting-packages">https://learn.microsoft.com/en-us/nuget/nuget-org/policies/deleting-packages</a></aside> <aside class="footnote brackets" id="f10" role="doc-footnote"> <dt class="label" id="f10">[<a href="#id10">10</a>]</dt> <dd><a class="reference external" href="https://learn.microsoft.com/en-us/nuget/nuget-org/policies/deleting-packages#unlisting-a-package">https://learn.microsoft.com/en-us/nuget/nuget-org/policies/deleting-packages#unlisting-a-package</a></aside> <aside class="footnote brackets" id="f11" role="doc-footnote"> <dt class="label" id="f11">[11]<em> (<a href='#id11'>1</a>, <a href='#id12'>2</a>) </em></dt> <dd><a class="reference external" href="https://hex.pm/docs/faq#can-packages-be-removed-from-the-repository">https://hex.pm/docs/faq#can-packages-be-removed-from-the-repository</a></aside> <aside class="footnote brackets" id="f12" role="doc-footnote"> <dt class="label" id="f12">[12]<em> (<a href='#id13'>1</a>, <a href='#id14'>2</a>) </em></dt> <dd><a class="reference external" href="https://cran.r-project.org/web/packages/policies.html">https://cran.r-project.org/web/packages/policies.html</a></aside> <aside class="footnote brackets" id="f13" role="doc-footnote"> <dt class="label" id="f13">[<a href="#id15">13</a>]</dt> <dd><a class="reference external" href="https://neilb.org/2021/05/10/delete-your-old-releases.html">https://neilb.org/2021/05/10/delete-your-old-releases.html</a></aside> <aside class="footnote brackets" id="f14" role="doc-footnote"> <dt class="label" id="f14">[14]<em> (<a href='#id16'>1</a>, <a href='#id17'>2</a>) </em></dt> <dd><a class="reference external" href="https://luarocks.org/changes">https://luarocks.org/changes</a></aside> <aside class="footnote brackets" id="f15" role="doc-footnote"> <dt class="label" id="f15">[<a href="#id18">15</a>]</dt> <dd><a class="reference external" href="https://hackage.haskell.org/upload">https://hackage.haskell.org/upload</a></aside> <aside class="footnote brackets" id="f16" role="doc-footnote"> <dt class="label" id="f16">[<a href="#id19">16</a>]</dt> <dd><a class="reference external" href="https://hackage.haskell.org/packages/deprecated">https://hackage.haskell.org/packages/deprecated</a></aside> <aside class="footnote brackets" id="f17" role="doc-footnote"> <dt class="label" id="f17">[17]<em> (<a href='#id20'>1</a>, <a href='#id21'>2</a>) </em></dt> <dd><a class="reference external" href="https://github.com/ocaml/opam-repository/wiki/Policies#1-removal-of-packages-should-be-avoided">https://github.com/ocaml/opam-repository/wiki/Policies#1-removal-of-packages-should-be-avoided</a></aside> </aside> </section> <section id="copyright"> <h2><a class="toc-backref" href="#copyright" role="doc-backlink">Copyright</a></h2> <p>This document is placed in the public domain or under the CC0-1.0-Universal license, whichever is more permissive.</p> </section> </section> <hr class="docutils" /> <p>Source: <a class="reference external" href="https://github.com/python/peps/blob/main/peps/pep-0763.rst">https://github.com/python/peps/blob/main/peps/pep-0763.rst</a></p> <p>Last modified: <a class="reference external" href="https://github.com/python/peps/commits/main/peps/pep-0763.rst">2024-10-28 23:59:04 GMT</a></p> </article> <nav id="pep-sidebar"> <h2>Contents</h2> <ul> <li><a class="reference internal" href="#abstract">Abstract</a></li> <li><a class="reference internal" href="#rationale-and-motivation">Rationale and Motivation</a></li> <li><a class="reference internal" href="#specification">Specification</a><ul> <li><a class="reference internal" href="#deletion-eligibility-rules">Deletion eligibility rules</a></li> </ul> </li> <li><a class="reference internal" href="#implementation">Implementation</a><ul> <li><a class="reference internal" href="#changes">Changes</a></li> </ul> </li> <li><a class="reference internal" href="#security-implications">Security Implications</a></li> <li><a class="reference internal" href="#how-to-teach-this">How To Teach This</a></li> <li><a class="reference internal" href="#rejected-ideas">Rejected Ideas</a><ul> <li><a class="reference internal" href="#conditioning-deletion-on-dependency-relationships">Conditioning deletion on dependency relationships</a></li> <li><a class="reference internal" href="#conditioning-deletion-on-download-count">Conditioning deletion on download count</a></li> </ul> </li> <li><a class="reference internal" href="#appendix-a-precedent-in-other-ecosystems">Appendix A: Precedent in other ecosystems</a></li> <li><a class="reference internal" href="#footnotes">Footnotes</a></li> <li><a class="reference internal" href="#copyright">Copyright</a></li> </ul> <br> <a id="source" href="https://github.com/python/peps/blob/main/peps/pep-0763.rst">Page Source (GitHub)</a> </nav> </section> <script src="../_static/colour_scheme.js"></script> <script src="../_static/wrap_tables.js"></script> <script src="../_static/sticky_banner.js"></script> </body> </html>