nikkie-ftnextの日記

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

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

はじめに

絵羽模様😭😭😭 nikkieです。

uvで環境構築したPythonプロジェクトのDockerイメージの作り方を考えていきます。
今回はライブラリ編です

目次

uvのライブラリ

uv 0.4.0から、プロジェクトをアプリケーション(--app)またはライブラリ(--lib)と区別してuv initできるようになりました

  • アプリケーションは、配布を想定していないPythonプロジェクト
  • ライブラリは、配布を想定しているPythonプロジェクト
    • 他のPythonプロジェクトにインストールして、importできるということです

この記事では、ライブラリ用のDockerイメージを考えていきます。
ちなみに、アプリケーション用のDockerイメージの提案はこちらです。

さて、サンプルライブラリを用意しました(uv init --lib mylib --no-readme1

% uv --version
uv 0.4.9 (Homebrew 2024-09-10)
mylib/
├── .venv/
├── .python-version
├── src/
│   └── mylib/
│       ├── __init__.py
│       └── py.typed
├── pyproject.toml
└── uv.lock

src/mylib/__main__.py を追加しています

from the_solitary_castle_in_the_mirror import characters

from mylib import hello


def main():
    print(hello())
    print(characters)


if __name__ == "__main__":
    main()

python -mで、パッケージの__main__.pyを実行します。
ref: https://docs.python.org/ja/3/using/cmdline.html#cmdoption-m

% uv run python -m mylib
Hello from mylib!
['kokoro', 'aki', 'fuka', 'rion', 'subaru', 'masamune', 'ureshino']

結論

⚠️以下のDockerfileは、uvの開発者の方やuvを愛用している方には、刺激が強すぎるかもしれません🙇‍♂️

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

全容はこちらからどうぞ

思想の対立:私 vs uv

2者間で相容れない部分があり、今回は私がuvをねじ伏せた形となります💪

小さいサイズのDockerイメージを作りたい私

小さいは正義!
アプリケーション編でも示しましたが、uv自体はDockerイメージには不要という立場です。

uv run <command>pyproject.tomlに宣言した環境でコマンドを実行すると理解しています。
上記のuv run python -m mylibは、pyproject.tomlに宣言した環境(.venv)をuvが用意した上で、コマンドを実行しました。

ところで、ライブラリに必要な依存がインストールされている仮想環境のPython処理系を直接指定してもpython -mを実行できます

% .venv/bin/python -m mylib
Hello from mylib!
['kokoro', 'aki', 'fuka', 'rion', 'subaru', 'masamune', 'ureshino']

仮想環境の処理系を直接指定できるという見方をしているので、Dockerイメージには以下だけを含めるのが自然に思えてきました。

ただしゆーゔい、テメーはダメだ」(この見方ではuvは過剰なんです)

uvはライブラリ自体をeditable installのみ

uvのライブラリ自体のインストールなのですが、editable installのみのようでした2
mylibの行です

% uv pip list
Package      Version Editable project location
------------ ------- --------------------------------------
kojo-fan-art 0.1.1
mylib        0.1.0   /.../uv-practice/mylib

uvがPythonプロジェクト自体をインストールするか(私の理解)
ref: https://docs.astral.sh/uv/concepts/projects/#build-systems

  • プロジェクトがアプリケーションのとき
    • pyproject.toml[build-system]テーブルなし
    • -> プロジェクト自体をインストールしない
  • プロジェクトがライブラリのとき
    • pyproject.toml[build-system]テーブルあり
    • -> プロジェクト自体のeditable installのみサポート
    • If a build system is defined, uv will build and install the project into the project environment. Projects are installed in editable mode so changes to the source code are reflected immediately, without reinstallation.

(参照したドキュメントにあるのですが、tool.uv.package = trueのとき、editable installなのか、コードをコピーするインストールなのかは未検証です)

editable installのみだと、私の求める小さいサイズのDockerイメージには少しだけ届きません。
開発中のライブラリだからといって特別扱いせずに、Dockerイメージの中には他のライブラリ同様、editableではない(=ソースコードを配置するインストールをしたいのです!

uvは管理しているライブラリのeditableではないインストールを(今はまだ)サポートしていないようなので、無理やりpipにやってもらいました(この筋の通し方、サイコパスみがあります。もう完全にuvに喧嘩を売りました3

.venv/bin/python -m ensurepip
.venv/bin/python -m pip install --no-deps .
  • uvが管理する仮想環境(.venv)にはPython標準のパッケージ管理ツールpipが含まれていません
    • そこでensurepipでpipを用意(uv開発者は卒倒していそうですね。見逃してちょ🙏)
  • pip install-eを指定しなければ、editableではないインストールとなります!

依存ライブラリのインストールではuv sync --no-install-projectで、プロジェクトの依存だけをインストールし、開発中のライブラリ自体(=プロジェクト)をインストールしませんでした。
https://docs.astral.sh/uv/reference/cli/#uv-sync
全てはpipでeditableでないインストールをするための布石です。

こうしてできあがったDockerイメージは、開発中のライブラリ自体もeditableでないインストールがされ、私が求めていたものは手に入りました🙌

% docker run --rm -it uv-practice-lib:0.1.0 bash
root@a32c70ecb551:/# python -m pip list
Package      Version
------------ -------
kojo-fan-art 0.1.1
mylib        0.1.0
pip          24.2

思考ログ

終わりに

uvで環境構築したPythonライブラリのDockerイメージについて、現在の考えをまとめました。

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

uvがライブラリをeditable installのみという振る舞いは経緯を知りたい気持ちはあります。
また、uvでeditableでないインストールもできるという情報をご存知の方は、(私としても和解したいので)ぜひお知らせください


  1. 他にドキュメントとしては https://docs.astral.sh/uv/concepts/dependencies/#editable-dependencies も見ています。「Editable installations solve this problem by adding a link to the project within the virtual environment (a .pth file), which instructs the interpreter to include the source files directly.
  2. (バスターコール怖い。ガクブル)
  3. Dockerイメージに使っている例