Featured image of post PyPIで古いバージョンのwheelが削除されてないちゃった

PyPIで古いバージョンのwheelが削除されてないちゃった

自分がPythonパッケージに詳しくなかったというだけなんだが...

まとめ

  • ある日PyPIからPyAV 10.0.0のwheelが消えてpip installがうまくいかないことがあった
  • PyAVに限らず、PyPIで公開されているパッケージのwheelは削除されることがある
  • どのパッケージも最新版はだいたいwheelが公開されているのでなるべく新しいバージョンを使おう!

昨日まで動いてたのに…

PyAV 10.*系に依存しているプロジェクトを開発していて、
ある日何気なく再インストール(pip uninstall & pip install)したらこれまでインストールできていたものが急に失敗してしまった。

(DockerのPythonコンテナで実施: docker container run --rm -it python:3.10.12 /bin/bash)

(tutorial-env) root@e199492ba090:/# pip install av==10.*
Collecting av==10.*
  Downloading av-10.0.0.tar.gz (2.4 MB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 2.4/2.4 MB 17.7 MB/s  0:00:00
  Installing build dependencies ... done
  Getting requirements to build wheel ... error
  error: subprocess-exited-with-error

  × Getting requirements to build wheel did not run successfully.
exit code: 1
  ╰─> [11 lines of output]
      Package libavformat was not found in the pkg-config search path.
      Perhaps you should add the directory containing `libavformat.pc'
      to the PKG_CONFIG_PATH environment variable
      Package 'libavformat', required by 'virtual:world', not found
      Package 'libavcodec', required by 'virtual:world', not found
      Package 'libavdevice', required by 'virtual:world', not found
      Package 'libavutil', required by 'virtual:world', not found
      Package 'libavfilter', required by 'virtual:world', not found
      Package 'libswscale', required by 'virtual:world', not found
      Package 'libswresample', required by 'virtual:world', not found
      pkg-config could not find libraries ['avformat', 'avcodec', 'avdevice', 'avutil', 'avfilter', 'swscale', 'swresample']
      [end of output]

  note: This error originates from a subprocess, and is likely not a problem with pip.
error: subprocess-exited-with-error

× Getting requirements to build wheel did not run successfully.
exit code: 1
╰─> See above for output.

note: This error originates from a subprocess, and is likely not a problem with pip.

なんでやねん…と思いながらもログを見てみると、
なぜかsdist(av-10.0.0.tar.gz)をダウンロードしてwheelをローカルでビルドしようとしている。
(そしてビルドに必要なFFmpegのパッケージが実行環境にないため失敗している)

wheelはどこへ消えた?

Python Packaging User Guideにも説明がある通り、
そもそもローカルでwheelをビルドしようとしているのはpipが対象のwheelを見つけられなかったからである。

When pip, the standard Python package installer, cannot find a wheel to install, it will fall back on downloading a source distribution, compiling a wheel from it, and installing the wheel. https://packaging.python.org/en/latest/discussions/package-formats/#what-is-a-source-distribution

ということは、これまではwheelが見つかる状態だったのにある日から対象のwheelが取得できなくなった?

実際にPyPIでPyAV 10.0.0のFilesを確認すると、たしかにsdistだけ残っていてwheelが消えている。
https://pypi.org/project/av/10.0.0/#files

sdist(tar.gz)しかないやん

(ちなみにWayback Machineで過去のページをみるとwheelが公開されていた痕跡が…)

いきなりwheelが消えるなんて、そんなことある…?

ありました。

「PyAV 9.2.0のwheelがPyPIから消えたんだけど!(意訳)」というissueでのコメント。

Old binary wheels were removed to have space for the 14.4.0 release.
https://github.com/PyAV-Org/PyAV/issues/1906#issuecomment-2899577746

「古いwheelは新しいバージョン(14.4.0)リリースの領域を確保するために削除した(意訳)」

はえ〜…
そんなことあるんすね…

自分がPyPIに詳しくないので初めて知ったのだが、
どうやらプロジェクトあたり最大10GBまでのサイズ上限があるらしい。

PyPI imposes storage limits on the size of individually uploaded files, as well as the total size of all files in a project.
The current default limits are 100.0 MB for individual files and 10.0 GB for the entire project. https://docs.pypi.org/project-management/storage-limits/

まあサイズ上限があるなら古いやつから消すよな…
ソース(sdist)さえあればビルドできないわけじゃないし… (自分の環境はダメだったが)

ちなみに「重要なパッケージはたとえOwnerであってもPyPI上からの削除を制限した方が良いのでは?」的な議論もあるっぽい。
自分も使う側の人間なので気持ちはわかるが、開発者に責任を押し付けすぎでは?とも思う。
OSSむずかしい…。
https://discuss.python.org/t/stop-allowing-deleting-things-from-pypi/

あとはPyPIから削除されたwheelをアーカイブしているサイトもいくつかあるようだが、
非公式でメンテナンスは期待できないだろうし、
なにかあった時に自己責任なのであんまり触りたくないな〜という気持ち。
https://dashboard.stablebuild.com/pypi-deleted-packages/

素直にバージョンを上げよう

じゃあどうすんねんという話だが、
古いバージョンへの依存をやめれば良い。

バージョン縛りをなくしたところ、あっさり成功。
https://pypi.org/project/av/16.0.1/#files で公開されている最新版のwheelをダウンロード&インストールできた。

(tutorial-env) root@6673fc741395:/# pip install av
Collecting av
  Downloading av-16.0.1-cp310-cp310-manylinux_2_28_aarch64.whl.metadata (4.6 kB)
Downloading av-16.0.1-cp310-cp310-manylinux_2_28_aarch64.whl (38.2 MB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 38.2/38.2 MB 21.9 MB/s  0:00:01
Installing collected packages: av
Successfully installed av-16.0.1
(tutorial-env) root@6673fc741395:/# python
Python 3.10.12 (main, Aug 16 2023, 08:07:04) [GCC 12.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import av
>>>

やったぜ。

…というより、そもそも3年前のバージョンに依存して使ってる方が悪いな、これ。
完全に自業自得。
これだけ古いと脆弱性も見つかってるだろうし、そこらへん自分で運用管理できてないのがバレバレ。
自力でビルドもできないOSSフリーライダーはなにをやってもダメ。

よいこのみんなはおとなしく提供元の意向にしたがって最新のバージョンを使いましょう。

おわり

Python弱者すぎてこんなので1日消耗してしまったので、備忘録として書いてみた。

PyPIやpipについてあまり理解せずに使ってしまっていたので勉強になったが、
そもそも古いバージョンに固定して放置している怠惰な自分が悪いわけで、
おそらく大多数の人はひっかからない気がする。

他のパッケージでもpip install時のログで急にtar.gzをダウンロードしてるときはPyPIでwheelが配布されているか確認するとよさそう。
弱者はおとなしく新しいバージョンを使おう!

おまけ

ピンク肉球ガン見せねこ