PyPI Blog: Releases now reject new files after 14 days

(blog.pypi.org)

44 points | by miketheman 3 days ago

6 comments

  • skinfaxi 1 hour ago
    14 days is still too long if you ask me. Releases should be immutable.
    • simonw 26 minutes ago
      Published files within a release are immutable.

      The time limit is needed because a release can contain different binary wheels for different architectures.

      Consider the simplest case: your releases go out via GitHub Actions and separate wheels are built on the Windows, Linux, and macOS runners.

      Those won't all end at exactly the same time, so you need a release window during which they can finish and upload their generated files.

      That window used to be unlimited, now it's 14 days.

      That might seem like a long time, but it means more manual release processes still have time to coordinate, or release processes that need access to less common hardware that might require queuing for a while.

      • stackskipton 8 minutes ago
        Seems like better setup would be you stage a release and upload but once it’s promoted, its immutable.
        • woodruffw 4 minutes ago
          Yes, that would be a better setup and it’s exactly what PyPI is moving to[1]. This closes a gap in the legacy upload API, which evolved over time instead of being designed to avoid these kinds of problems.

          [1]: https://peps.python.org/pep-0694/

      • dralley 11 minutes ago
        I'd be happier if it was 24 hours by default, with an increased timeout configurable behind 2FA.
  • yladiz 2 hours ago
    I’m a bit surprised this is possible in the first place. I get that you might not be able to upload everything in one go, but it feels like you should “start” and “finish” a release in that case, and once it’s finished you can’t modify it.

    I guess the use case is that you might want to build a wheel for an older release for a newer version of Python?

    • woodruffw 2 hours ago
      The use case of uploading new wheels to an old release was actually (kind of) an accident: PyPI’s current upload API is stateless and originally there was only one file per release (sdists), so there was no need for a start-finish transition for releases.

      (This will hopefully change pretty soon, with the “upload 2.0” work.)

  • firesteelrain 1 hour ago
    This seems like common sense configuration management 101. If I download v1.2 and it’s been published then it should be considered released and not modifiable. With exceptions for ‘dev’ releases of course. I have never published anything on PyPI but I would expect there is a publish button and finalize (?) optional button that if not checked after 14 days makes it final ?
  • edelbitter 2 hours ago
    > To quantify how disruptive this change would be to existing workflows, the PyPI database was queried for projects that have published new files to old releases

    While this may quantify how disruptive the change would be to those projects that are able to and do upload additional binaries to PyPI later, it fails to quantify how many projects already completely circumvent this block before it is even introduced.

    e.g. If you tell pip to install from source.. the result may already be that you install a binary that PyPI never saw. A common hack for dealing with NVidia internals, which can explode into a large CUDA major version x GPU arch x platform x implementation x python_version cartesian product. The "extras" mechanism is not quite sufficient to model such combinations.

    sample code: https://github.com/Dao-AILab/causal-conv1d/blob/4f6ae4e26ae5... https://pypi.org/project/causal-conv1d/

  • PhilipRoman 2 hours ago
    There seems to be a severe lack of hash pinning in "modern" software ecosystems. We figured out how to do it 20+ years ago with Git bringing hash addressed storage to the masses. Coming from a different background it was very surprising for me to see things like docker images, packages and github actions being updated at the whim of upstream registry. I much prefer the philosophy where builds are fully offline and predictable, even if not fully reproducible.
    • woodruffw 2 hours ago
      I’m not sure what this has to do with TFA: Python does have hash-pinning. TFA is not about modifying existing files on the index (PyPI doesn’t allow that), but about adding new files to a pre-existing release. But that doesn’t change the hash of older distributions on that release.
      • nobodyandproud 1 hour ago
        I feel you’re quibbling over semantics here.

        In concept why can’t the full set of files in a release be a single, one-way hash value, with both adding or releasing changing the hash value?

        • woodruffw 8 minutes ago
          Because uploads to PyPI are not atomic. They’re now capped within a 14 day window, but it would be extremely confusing to users to have the “release” hash of their dependencies change repeatedly.

          (Also: we’d need to determine what it even means to hash a set of files. Do we order by canonicalized filename, by upload time, etc. Each of these has surprising implications!)

          Edit: to be clear, it’s not ideal or fully intentional that uploads to PyPI are not atomic. But it’s the status quo and any change will take years.

        • joombaga 28 minutes ago
          The semantics are important. A release is composed of multiple distributions (sets of files). Each distribution does have a one-way hash value. This is what you lock to. Adding files does change the value of that hash. Files cannot be removed or changed.

          You lock to the distribution instead of the release so your build doesn't have to download distributions for platforms you're not using.

    • winstonwinston 1 hour ago
      Hash pinning (already) works, and this change is all about when you as a PyPI user do not use hash pinning for installing releases, when you pin just release version for example.

      The release consists of one sdist and zero or more wheels. Until now you were able to upload additional wheels at later time.

      • woodruffw 1 minute ago
        Very pedantic of me, but I figure it’s interesting to note: technically a release on PyPI can have zero files or even one or more wheels but no sdist. The former is a degenerate case that users don’t normally see, and the latter happens if the user chooses to only upload wheels (or their sdist upload fails for whatever reason).

        (This doesn’t change your observations at all! Just as a demonstration of how Python packaging’s data model can be unintuitive.)

    • edelbitter 2 hours ago
      Would not count that as 20 years of sticking to that philosophy, though.

      We also figured out 20 years ago that SHA1 was not quite as strong as initially estimated, and not quite 10 years ago that generating two colliding documents was merely a matter of some serious computing power. A few projects went ahead and changed the name of their master branch, but SHA256 preference remains elusive.

    • tyingq 1 hour ago
      BitTorrent used hash pinning earlier than that even.
  • lexicality 2 hours ago
    14 days still seems way too long to me. As a user I thought releases on pypi were immutable!
    • kzrdude 51 minutes ago
      How it works in practice is that some release flows add wheels for different platforms, as they get ready, separately.
    • woodruffw 1 hour ago
      Files are immutable on PyPI, releases are not (because releases are comprised of a set of files, and files are uploaded one by one).

      This is unintuitive, but the TL;DR is that files will never change on PyPI, but (previously) a user could upload a new file to a release years after their last upload to that release. This has some legitimate use cases (like allowing people to support new Python versions without bumping a package’s version), but also makes introduces challenges around locking and release security that are elaborated in the thread linked by the blog post.

      I agree this could probably be ratcheted down from 14 days over time, though.