はじめに
「uv buildが壊れたの!!」1 nikkieです。
最近uvで経験した事象です。
目次
uvを残さないDockerイメージビルド
思想が強いのは重々承知の上ですが、uv自体は(開発者には大いに価値を提供しますが)アプリケーションのユーザに価値を提供していないので、ビルドしたDockerイメージからは除きたい立場です。
uvで開発中のPythonライブラリをDockerイメージにビルドする際は
- 自作ライブラリに必要な依存を
uv sync --no-install-projectでインストール - 自作ライブラリ自体は
uv buildしたwheelをuv pip install(editable installをしない措置)
と考えています。
詳しくはこちらの記事をどうぞ
Dockerfileの例はこちらにあります。
uv buildが壊れた
DockerfileではFROM ghcr.io/astral-sh/uv:python3.12-bookworm AS builderと指定しています。
そのため、このイメージに含まれるuvは自然とバージョンが上がっていきます。
上記の記事を書いた後しばらくしてビルドしたところ、できあがったイメージをrunできませんでした。
ベースイメージをghcr.io/astral-sh/uv:0.4.18-python3.12-bookwormにすることで再現します2。
% docker --version Docker version 27.2.1-rd, build cc0ee3e % docker build --no-cache -t uv-practice-lib:0.2.0-uv0.4.18 . % docker run --rm uv-practice-lib:0.2.0-uv0.4.18 /usr/local/bin/python: No module named mylib
イメージの状態を見てみます。
% docker run --rm -it uv-practice-lib:0.2.0-uv0.4.18 bash root@d72844b8f6ac:/# ls /usr/local/lib/python3.12/site-packages/ README.txt _virtualenv.py pip __pycache__ kojo_fan_art-0.1.1.dist-info pip-24.2.dist-info _virtualenv.pth mylib-0.1.0.dist-info the_solitary_castle_in_the_mirror
site-packagesにmylibというディレクトリがありません。
mylib-0.1.0.dist-infoはあるのですが、mylibがないのです。
そのため、CMDでイメージに指定しているpython -m mylibは「No module named mylib」というわけですね。
site-packagesの中身はbuilderイメージからコピーしているため、builderイメージにあるuvの問題と思われました。
uv buildしたwheelを確認したところ、ソースコードを含んでいませんでした。
なお、ベースイメージをghcr.io/astral-sh/uv:0.4.22-python3.12-bookwormに上げると解決します。
(どのバージョンで壊れているかをしらみつぶしに調べた後、uvのissueを見に行きました)
% docker build --no-cache -t uv-practice-lib:0.2.0-uv0.4.22 . % docker run --rm uv-practice-lib:0.2.0-uv0.4.22 Hello from mylib! ['kokoro', 'aki', 'fuka', 'rion', 'subaru', 'masamune', 'ureshino']
uvのリポジトリのissueより
issue #8200 - regression: uv build silently produces empty wheels with hatchling if .gitignore is missing
私がDockerイメージビルドで直面したのと同様のissueが報告されていました。
再現手順がわかりやすいです。
- demoプロジェクトで
src/demo/__init__.pyだけを用意 uv build(wheel作成)unzip -l dist/demo-0.1.1-py3-none-any.whl(wheelに含まれるファイルを一覧3)
再現手順3でdemo/__init__.pyがwheelに含まれません。
これを展開してもsite-packagesにdemoディレクトリはできませんね(すなわち「No module named demo」をきたす)
pull request #8220 - Run uv build builds in the source distribution bucket
修正いただき感謝です4。
このプルリクエストには何が原因でどう直したかが書いてあります。
- 今回のケースはビルドバックエンドに
hatchlingを使っている uv buildの出力先は、デフォルトでdistディレクトリ- uvはv0.4.18で
distディレクトリに*という内容の.gitignoreを置くようになった5 - この
dist/.gitignoreのために、hatchlingはビルド用一時ディレクトリ(イメージdist/temp)の中のすべてのファイルを無視し6、ソースコードを含まないwheelが作成された7 - にせのgit rootとして
.gitファイルを追加して、hatchlingがファイルを無視しないようにした
uvがdist/.gitignoreを置いたことで、ビルドバックエンドにhatchlingを使うときに、開発者が想定していない振る舞いとなったということですね。
なお、このプルリクエストではテストコードも追加されているので、今後の再発はないと安心しました(テストが壊れることでリリース前に気づけるはずですので)
終わりに
直近で直面した、uv buildがソースコードを含まないwheelを作ってしまう事象についてでした。
ビルドに使うディレクトリの親に.gitignoreを置くようにしたことと、ビルドバックエンドhatchlingの振る舞いとの不整合でした。
詳細に報告いただき、そして直していただき、ありがとうございました。
- ↩
- https://github.com/astral-sh/uv/pkgs/container/uv からイメージの一覧を確認できます↩
-
今回の事象でwheelはZIPファイルということを思い出しました
↩aodagさんのお話興味深かったな〜👏#PyConK #PyConK_B
— nikkie / にっきー (@ftnext) 2024年5月25日
PyPI相当の配布の仕組みを標準ライブラリで作るという話。まさに"配ろう"
PEPに仕様があるから作れる。
配布だけなら標準ライブラリだけで全然行ける(大変なのは登録)。
wheelはzipファイルなのか! - https://github.com/astral-sh/uv/releases/tag/0.4.22 の #8220↩
- https://github.com/astral-sh/uv/releases/tag/0.4.18 の #7835↩
- issueの中に見つけたhatchlingの関連するかもissue(積ん読)↩
- 原文「By adding a gitignore in dist/ with *, we caused hatchling to ignore all files in our temporary build directory below it, causing empty wheels.」↩