uvで単一のPythonスクリプトのパッケージ管理
1年ぐらい前からPythonのパッケージ&プロジェクト管理ツールをpoetry+pyenvからuvに乗り換えました。依存解決がとても高速で大変気に入っています。
私のuvの主な用途は複数ファイルからなるプロジェクト管理が中心ですが、uvはスクリプト単位、つまりファイル1つのPythonスクリプトでも依存パッケージを管理できる、という点について今回はメモしておきます。
インラインでパッケージ管理
公式ドキュメント Running scripts | uv に書いてある通りですが、uvはバージョン0.4.17以降で PEP 723 – Inline script metadata に対応しており、
$ uv init --script [ファイル名.py]
で初期化すると、ファイルの冒頭に
# /// script
# requires-python = ">=3.13"
# dependencies = []
# ///
のようなコメントが挿入されます( また、uv init --script [ファイル名] --python 3.12
とすればPythonのバージョンも指定可能)。
そして、初期化後に
$ uv add [パッケージ名その1] [パッケージ名その2] ... --script [ファイル名]
としてあげると、指定されたファイルの冒頭にコメントとしてPEP 723形式の依存パッケージのリストが書き込まれます。
例えばパッケージ polars
を $ uv add polars --script example.py
のように追加すると、上記のコメントが
# /// script
# requires-python = ">=3.13"
# dependencies = [
# "polars",
# ]
# ///
のように上書きされます。パッケージ名の部分は polars==1.0.0
のようにしてバージョン指定できます。なお、この段階ではパッケージのインストールは実行されません。
このようなコメントが書かれているファイルに対し、
$ uv run [ファイル名.py]
で実行すると、上記で指定した依存パッケージをインストールした後にスクリプトを実行してくれます。このファイル専用の仮想環境が作成されるのでグローバルの環境を汚すことはありません。 また、2回目以降はキャッシュされたパッケージが使われるのですぐに実行されます。
uv sync --script について
uv run [ファイル名.py]
以外にも、依存パッケージの情報が書き込まれたスクリプトの環境をインストールする方法として、
$ uv sync --script [ファイル名.py]
というのがあります。これを実行するとPythonファイル自体は実行されずに、コメント欄に記載されたパッケージを含む仮想環境のインストールのみが実行されます。また、同時に
Using script environment at: [仮想環境のパス]
という出力が出てきます。この仮想環境のパスに対して
$ activate [仮想環境のパス]/bin/activate
としてあげると、指定のスクリプトの依存パッケージがインストールされた仮想環境に切り替えることができます(デフォルトでは ${HOME}/.cache/uv/
の下にファイル名を用いた一意な環境が作成されるようです)。
uv sync --script
の用途として想定されるのは
- IDEなどでスクリプトの中身を部分的にターミナルから実行したいとき
- Dockerfileの中でスクリプトから仮想環境を作成したい場合
あたりでしょうか。
指定したパッケージで実行だけ行いたい場合
上記の方法はPEP 723の形式で依存パッケージの情報がファイルにコメントとして追記されますが、それをせずに、単純にパッケージをインストールしつつ実行する方法として
$ uv run [ファイル名] --with [パッケージ名その1] [パッケージ名その2] ...
があります。こちらは特定のバージョンのパッケージを所与として与えたいときのスクリプトの挙動を確認したいときに便利な機能です。
使い捨ての簡単なPythonスクリプトを実行する際、これまではシステム標準のPython環境を使用していましたが、必要な依存パッケージが衝突することが多々ありました。
今回紹介したPEP 723準拠の uv --script
オプションを使えば、各ファイルごとにインラインで環境に関する情報を記載できるため、今後はこのような事態は避けられそうです。Python環境も精神衛生もクリーンな状態を保つことができそうですね。