Python パッケージング #4 uv — 2026 年の標準ワークフロー
ここまで手作業でやってきたことを並べてみます。venv を作る、activate する、pip install する、バージョンを記録する、Python のバージョンは別で管理する。1 つの道具がこの全部を引き受けるとどうなるか、が今回です。uv は 2026 年現在、Python プロジェクト管理の事実上の標準ワークフローになった道具です。 ruff を作った Astral が Rust で開発し、2025 年の 1.0 リリースを経て、月間ダウンロードで既存の道具たちを追い越しました。このブログのテスト・自動化シリーズやモダン Python 基礎 #1が最初から uv を前提にしていた理由でもあります。速度(ロックファイルからのインストールで既存ツールの数倍〜十数倍)が有名ですが、実務での価値は速度よりワークフローが 1 つに畳み込まれることにあります。
インストールと最初のプロジェクト — uv init #
uv 自体は Python と無関係な単一の実行ファイルなので、インストールはシンプルです。
# macOS / Linux
curl -LsSf https://astral.sh/uv/install.sh | sh
# または
brew install uv新しいプロジェクトは init から始めます。
uv init invoice-tool
cd invoice-tool作られるものは控えめです。#3 で見た pyproject.toml、Python バージョンを固定する .python-version、あとは main.py と README くらいです。.venv はまだありません。必要になった瞬間に uv が作るからです。
add と sync — 宣言と環境を常に一致させます #
依存関係の追加は add です。
uv add django
uv add --dev pytest ruffこの 1 行の裏で起きることが、前回までのまとめになっています。pyproject.toml の dependencies(または dependency-groups の dev)に宣言が記録され、依存関係全体が解決されて uv.lock にロックされ、.venv がなければ作られたうえでインストールまで終わります。 宣言(#3)、ロック(#5)、環境(#1)がコマンド 1 つで同期されるのです。削除は uv remove django で対称です。
同僚のリポジトリをクローンしたときは sync 1 つです。
git clone .../invoice-tool && cd invoice-tool
uv syncロックファイルのとおりに .venv が再現されます。README に「Python X.Y をインストールして、venv を作って、activate して、pip install -r…」といった手順書が要らなくなります。
run — activate の要らない実行 #
#1 で activate の正体が PATH の操作にすぎないことを見ました。uv はその段階ごと省略させてくれます。
uv run python main.py
uv run pytestuv run はプロジェクトの .venv を見つけて(なければ作り、ロックとずれていれば合わせたうえで)、その環境でコマンドを実行します。「activate を忘れて別の環境にインストールしてしまった」という事故の類型が、構造的に消えます。テストシリーズで uv run pytest を基本の実行方法にしていた背景です。
Python のバージョンまで uv が管理します #
uv の管理範囲はパッケージで終わりません。Python インタープリター自体をダウンロードして管理します。
uv python install 3.13 # インタープリターのインストール
uv python pin 3.13 # プロジェクトに固定 (.python-version に記録)
uv python list # インストール済み・利用可能なバージョンの一覧.python-version があれば uv のすべてのコマンドがそのバージョンで動き、ないバージョンなら自動で取ってきます。pyenv が担っていた役割まで吸収した形で、「Python バージョン管理ツール + 仮想環境ツール + パッケージマネージャー」の 3 点セットが 1 つに減ります。システム Python に触らないという #1 の原則も自然に守られます。
uvx と uv tool — グローバルツールの正しい置き場所 #
#1 で「システム Python には何もインストールしない。グローバルなツールには別の方法がある」と先送りした答えがここです。
uvx ruff check . # インストールなしの一回限りの実行
uv tool install ruff # グローバルツールとしてインストール (分離環境に)uvx はツールを一時的な分離環境でそのまま実行し、uv tool install はよく使うツールをツールごとの分離環境にインストールして PATH に公開します。どちらでも、プロジェクトの環境もシステム Python も汚れません。自動化 #7 で作った CLI のような自作ツールも、同じ方式でインストールできます。
既存プロジェクトのマイグレーション #
requirements.txt で回っていたプロジェクトの移行は、吸収に近い作業です。
uv init --bare # 既存コードに pyproject.toml だけ追加
uv add -r requirements.txt # 一覧を dependencies に吸収
uv add --dev -r requirements-dev.txt#2 で見た freeze 型の一覧なら、この機会に直接依存だけを残して整理するのがよいです。推移的依存はロックが管理してくれるので、宣言に残しておく理由がありません。逆に、uv を導入できない環境向けに書き出すこともできます(uv export --format requirements.txt)。また pip のコマンド体系に慣れた手のために uv pip install のような低レベルインターフェースも用意されていますが、プロジェクト管理では add/sync のほうが宣言・ロック・環境を一緒に合わせてくれる正式なやり方です。
まとめ #
今回扱った内容です。
- uv は仮想環境、パッケージのインストール、ロック、Python バージョン管理を 1 つにまとめた道具で、2026 年現在、新規プロジェクトの事実上の標準です
uv initで始め、uv add/uv removeが宣言(pyproject.toml)・ロック(uv.lock)・環境(.venv)を一度に同期します- クローン後は
uv sync1 つで環境が再現され、uv runは activate なしでプロジェクトの環境でコマンドを実行します uv python install/pinでインタープリターまで uv が管理します。pyenv なしで.python-versionによってチームの Python バージョンが固定されます- グローバルツールは
uvx(一回限り)とuv tool install(常用)で分離インストールします。システム Python は最後まで触りません - 既存プロジェクトは
uv add -r requirements.txtで吸収し、freeze 型の一覧は直接依存だけを残して整理します
次回(#5 依存関係のロック)では、add の裏で静かに作られていた uv.lock の中身を直接読みます。 ロックが再現性を保証する仕組み、アップグレードの戦略、そして道具の間をつなぐ標準 pylock.toml(PEP 751)まで扱います。