nikkie-ftnextの日記

イベントレポートや読書メモを発信

改訂版:uv init --libで環境構築して開発中の自作Pythonライブラリを含んだDockerイメージをビルドする

はじめに

絵羽模様😭😭😭 nikkieです。

先日の、uvでライブラリとして環境構築したPythonプロジェクトのDockerイメージの記事を更新します。

コメントいただき、uvだけで達成できました。
ありがとうございます!

目次

uv init --libで環境構築して開発中の自作Pythonライブラリを含んだDockerイメージをビルドする

プロジェクト構造

mylib/
├── .venv/
├── .python-version
├── src/
│   └── mylib/
│       ├── __init__.py
│       ├── __main__.py
│       └── py.typed
├── pyproject.toml
└── uv.lock
% uv run python -m mylib
Hello from mylib!
['kokoro', 'aki', 'fuka', 'rion', 'subaru', 'masamune', 'ureshino']

python -m mylibを実行するDockerイメージを作りました。
https://gist.github.com/ftnext/5b0bb4784d806140aea22a807f171fef

  • マルチステージビルド
    • 前段のuvのDockerイメージで、仮想環境(.venv)に全ての依存をインストール。これを成果物イメージにコピーするだけ
    • 成果物イメージはpythonイメージ。uvは含めない
  • uvはプロジェクト自体をeditable installするので、仮想環境にライブラリ自体のコードがコピーされない課題があった
    • 仮想環境にpipを入れ(ensurepip)、pip installしてライブラリ自体のコードをコピーした(ねじ伏せた💪)

uvでライブラリ自体のeditableでないインストールもできればいいのですが、editable installのみのように思われたので、pipを持ち出しています。

コメントでuv buildを教わる

uvはプロジェクトをビルドできます(uv build)。
ビルドしてできたwheelからインストールすれば、editableでないインストール(=ソースコードをコピーするインストール)になると気づきました!

改訂版の結論

% docker run --rm uv-practice-lib:0.2.0  
Hello from mylib!
['kokoro', 'aki', 'fuka', 'rion', 'subaru', 'masamune', 'ureshino']

全容はこちらからどうぞ

wheelをビルドしてインストールすることで、editableでないインストールを達成する

差分箇所について、置き換えたコマンドを見ていきます

RUN <<INSTALL_PROJECT
-    .venv/bin/python -m ensurepip
-    .venv/bin/python -m pip install --no-deps .
+    uv build
+    uv pip install --no-deps dist/mylib-*.whl
INSTALL_PROJECT

uv build

「Working on projects」のドキュメントより
https://docs.astral.sh/uv/guides/projects/#building-distributions

uv build can be used to build source distributions and binary distributions (wheel) for your project.

uv buildを叩くとdistディレクトリができて、そこに配布物(distribution)が2つの形式でできます

% uv build
Building source distribution...
Building wheel from source distribution...
Successfully built dist/mylib-0.1.0.tar.gz and dist/mylib-0.1.0-py3-none-any.whl

さらに詳しいドキュメントはこちら
https://docs.astral.sh/uv/concepts/projects/#building-projects
--sdist--wheelというフラグを指定して、sdistやwheelの欲しい方だけを作ることもできるようです。

uv pip install

https://docs.astral.sh/uv/reference/cli/#uv-pip-install

uv buildしたwheelですが、(pip installでできるように)uv pip installでもwheelからインストールできます。
その際、--no-depsは指定し続けています

Ignore package dependencies, instead only installing those packages explicitly listed on the command line or in the requirements files

Dockerfileの uv sync --frozen --no-dev --no-install-project の行で、プロジェクト(今回は自作ライブラリ)が依存するライブラリをすべてインストールしています。
--frozenの指定により、uv.lockの記載と同じバージョンの依存がインストールされます。

残るインストールは、自作ライブラリ本体です。
自作ライブラリのwheelをインストールするときに--no-depsを指定して、自作ライブラリだけを、ソースコードをコピーしてインストールしています

終わりに

uvで環境構築したPythonライブラリのDockerイメージについて、いただいたコメントをもとに改訂しました。

  • マルチステージビルドで成果物イメージからuvは除く
  • ライブラリ自体のeditableでないインストールのために、uvでwheelをビルドし、それをインストールした
  • 開発中のライブラリを含むすべての依存ライブラリをステージ間でコピーした

uv buildしてwheelからインストールすればeditableでないインストールができるというのは、見えていませんでした。
attakeiさん、コメント誠にありがとうございます!

nikkie、uv、なかよし、なかよし


  1. wheelファイルはzipファイルと知りました