uv (pythonパッケージマネージャー)の使い方 詳細版

に公開

簡易版はこちら

Pythonのパッケージ管理はこれまで pipvenvpoetry などで行われてきましたが、最近 uv が注目を集めています。

本稿では uv をシステム開発で使うための詳細な情報、特に、poetryvenvpipからの移行手順を解説します。

1. uvの概要

1.1 uvとは?

uvは 高速な動作、クロスプラットフォーム対応のロックファイル、ツール管理、Python自体のバージョン管理を統合した、現代的なPythonプロジェクト&パッケージマネージャーです。Rustで記述されており、従来のツール(pip, poetry, pip-toolsなど)の機能を単体で置き換えることができます。

Monosnap uv 2024-11-01 23-53-30.png

1.2 uvのアーキテクチャ

uvはRustで実装されており、高いパフォーマンスとメモリ安全性を誇ります。Rustの並行処理能力を活用し、依存関係解決を高速化しています。また、効率的なキャッシュ機構を備えており、ダウンロードしたパッケージ、ビルドされたwheelファイル、ソースコードなどをキャッシュすることで、再利用性を高め、処理時間を短縮します。このキャッシュはスレッドセーフであり、複数のコマンドを同時実行しても安全に動作します。

1.3 uvのインストールとセットアップ

uvのインストールは、公式のスタンドアロンインストーラーを利用するのが最も簡単です。macOSとLinuxではcurlコマンド、WindowsではPowerShellコマンドを実行することで、最新版のuvをダウンロードしてインストールできます。

# macOS/Linux
curl -LsSf https://astral.sh/uv/install.sh | sh

# Windows
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"

また、pip、Homebrew、Cargoといったパッケージマネージャーからもインストール可能です。

# pip
pip install uv

# Homebrew
brew install uv

# Cargo
cargo install --git https://github.com/astral-sh/uv uv

インストール後、uv generate-shell-completionコマンドを実行することで、シェルに自動補完機能を追加できます。

uvのアップグレードは、uv self updateコマンドで実行できます。アンインストールは、uv self uninstall、またはインストールディレクトリからバイナリを削除するだけで完了します。

2. uvの基本的な使い方

2.1 Pythonバージョンの管理

uvは、複数のPythonバージョンを管理することができます。uv python installコマンドで、任意のバージョンのPythonをインストールできます。

uv python install 3.11 3.12 3.13

uv python listコマンドで、インストール可能なバージョンやインストール済みのバージョンを確認できます。

uv python list

プロジェクトごとに使用するPythonバージョンを指定するには、.python-versionファイルにバージョン(例: 3.12)を記述するか、pyproject.toml に記述します。

uvは、コマンド実行時に必要なPythonバージョンが見つからない場合、自動的にダウンロードして使用します。

2.2 スクリプトの実行

uvは、スタンドアロンスクリプトの実行をサポートしています。uv runコマンドで、プロジェクト環境や一時的な環境でスクリプトを実行できます。

uv run example.py

スクリプトに必要な依存関係は、--withオプションで指定することで、一時的な仮想環境を作成して実行されます。

uv run --with requests example.py

また、スクリプトの先頭にインラインメタデータ(PEP 723)を記述することで、依存関係を自己完結的に宣言できます。

# /// script
# dependencies = ["requests"]
# ///

import requests
# ...

2.3 ツールの実行とインストール

uvは、Pythonパッケージが提供するコマンドラインツールの実行とインストールをサポートしています。uvxコマンド (またはuv tool run) で、インストールせずにツールを一時的に実行できます。

uvx ruff check

頻繁に使用するツールを永続的にインストールするには、uv tool installコマンドを使用します。これにより、ツールごとに隔離された環境が作られます。

uv tool install ruff

パッケージ名とコマンド名が異なる場合は、--fromオプションを使用します。

uvx --from httpie http

3. uvによるプロジェクト管理

3.1 プロジェクトの作成と初期化

uvは、標準仕様(PEP 621)に基づいた pyproject.toml によるプロジェクト管理をサポートしています。uv initコマンドで、新しいプロジェクトを作成できます。

uv init my-project

デフォルトではアプリケーションプロジェクト(--app相当)が作成されますが、--libオプションでライブラリプロジェクトを作成できます。

# アプリケーションプロジェクト(ロックファイルを生成し、環境を管理する)
uv init --app my-app

# ライブラリプロジェクト(配布用パッケージを作成する)
uv init --lib my-lib

uv initでは、hatchlingflit-coresetuptoolsmaturin といったビルドバックエンドを選択できます。--build-backendオプションで指定可能です。

uv init --lib --build-backend maturin my-lib

3.2 依存関係の管理

uv addコマンドで、pyproject.tomlproject.dependencies に依存関係を追加し、同時に仮想環境へインストールします。

uv add requests

--devオプションで、開発用の依存関係(dependency-groups または project.optional-dependencies)を追加できます。

uv add --dev pytest

uv removeコマンドで、依存関係を削除できます。

uv remove requests

3.3 環境の管理

uvは、プロジェクトルートに .venv という仮想環境を自動的に作成・管理します。uv syncコマンドで、uv.lock ファイルの内容に基づいて仮想環境を最新の状態に同期します。

uv sync

--frozenオプションをつけると、ロックファイルの更新を行わずに同期するため、CI/CD環境での利用に適しています。

--no-editableオプションで、自身のプロジェクトを編集不可モードでインストールできます。これは、Dockerコンテナの構築など、デプロイ時に便利です。

3.4 ロックファイルの管理

uvは、uv.lockというクロスプラットフォームのロックファイルを生成します。これはGit管理対象とすべきファイルです。

uv lockコマンドで、仮想環境を変更せずにロックファイルのみを更新できます。

uv lock --upgrade

3.5 ワークスペースの活用

uvは、Cargoスタイルのワークスペースをサポートしています。これにより、単一のリポジトリ(Monorepo)で複数のパッケージをまとめて管理できます。

pyproject.tomltool.uv.workspaceテーブルを追加することで、ワークスペースを作成できます。

[tool.uv.workspace]
members = ["packages/*"]

ワークスペースメンバー間では、tool.uv.sourcesを利用して相互依存を定義でき、uv sync 一発でワークスペース全体の環境を構築できます。

4. uvの高度な機能

4.1 依存関係の解決

uvは高度な依存関係解決アルゴリズムを備えており、以下の要素を考慮してすべての依存関係を満たす最適なパッケージの組み合わせを探索します。

  • バージョン制約: 各パッケージに指定されたバージョン範囲
  • プラットフォームマーカー: OS、アーキテクチャ、Pythonバージョンなどの条件
  • 依存関係の競合: 異なるパッケージが同じ依存関係の異なるバージョンを要求する場合

uvは、ユニバーサル解決(デフォルト)を行い、Linux, macOS, Windowsなど全てのプラットフォームで動作する単一の uv.lock を生成します。これにより、チームメンバーのOSが異なっても同じ依存関係セットが保証されます。

4.2 キャッシュの管理

uvは、強力なグローバルキャッシュ機構を備えています。

uv cache cleanコマンドで、キャッシュをすべて削除できます。uv cache pruneコマンドで、未使用のキャッシュエントリを削除できます。CI環境などでキャッシュディレクトリを指定したい場合は UV_CACHE_DIR 環境変数が利用できます。

4.3 ビルドの分離

uvは、PEP 517PEP 660に準拠したビルドの分離をサポートしています。各パッケージを隔離された環境でビルドすることで、依存関係の競合を防ぎます。

4.4 パブリッシュ

uvは、uv buildコマンドでPythonパッケージをソースディストリビューションとバイナリディストリビューションにビルドし、uv publishコマンドでPyPIなどのレジストリにアップロードすることができます。認証にはTrusted PublishingやAPIトークンが利用可能です。

5. uvと他ツールとの連携

5.1 Dockerとの連携

uvは、Dockerでの利用に最適化されています。公式Dockerイメージを利用することで、簡単にセットアップできます。

FROM python:3.12-slim
# 公式イメージからuvをコピー
COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/

WORKDIR /app

# 依存関係ファイルのコピー
COPY pyproject.toml uv.lock ./

# 依存関係のインストール(システム環境に直接インストール)
RUN uv sync --frozen --no-cache

COPY . .

Dockerコンテナ内では仮想環境を作らず、システムPythonにインストールするのが一般的です。その場合、uv sync はデフォルトで .venv を作ろうとするため、環境変数 UV_PROJECT_ENVIRONMENT=/usr/local を設定するか、uv pip install --system コマンドなどを併用する手法があります。ただし、最新のベストプラクティスでは、RUN uv sync --frozen --no-install-project で依存関係のみをインストールする手法が推奨されます。

5.2 GitHub Actionsとの連携

GitHub Actionsでは、公式のastral-sh/setup-uvアクションを利用します。

steps:
  - uses: actions/checkout@v7
  - name: Install uv
    uses: astral-sh/setup-uv@v10
    with:
      enable-cache: true
  
  - name: Install dependencies
    run: uv sync --frozen

  - name: Run tests
    run: uv run pytest

enable-cache: true を設定するだけで、キャッシュの保存・復元が自動的に行われ、ワークフローが高速化します。

5.3 GitLab CI/CDとの連携

GitLab CI/CDでも、公式Dockerイメージを利用できます。

variables:
  UV_VERSION: 0.5
  PYTHON_VERSION: 3.12

uv-job:
  image: ghcr.io/astral-sh/uv:$UV_VERSION-python$PYTHON_VERSION-bookworm-slim
  script:
    - uv sync --frozen
    - uv run pytest

5.4 Jupyterとの連携

プロジェクト内でJupyterを使用するには、uv runコマンド経由で起動するのが確実です。

# JupyterLabを一時的に実行する場合
uvx --with jupyter jupyter lab

# プロジェクトの依存関係として追加済みの場合
uv run jupyter lab

既存のJupyter環境からuvの仮想環境をカーネルとして利用したい場合は、uv add --dev ipykernel した上でカーネルを登録します。

uv run python -m ipykernel install --user --name=my-project

5.5 pre-commitとの連携

uvは、pre-commitフックも提供しています。例えば、uv.lockpyproject.toml と同期されているかをチェックしたり、requirements.txt を自動生成したりできます。

- repo: https://github.com/astral-sh/uv-pre-commit
  rev: 0.12.5
  hooks:
    # uv.lockが最新かチェックする
    - id: uv-lock
    # (オプション) requirements.txtを自動エクスポートする場合
    - id: uv-export
      args: ["--format", "requirements-txt", "--output-file", "requirements.txt"]

6. poetry, venv, pipからの移行

現在他のツールを使用しているチームが、uvのプロジェクト管理機能(uv sync / uv run)へ移行する手順は以下の通りです。

6.1 poetryからの移行

Poetryは独自の [tool.poetry] 設定を使用しますが、uvは標準のPEP 621 [project] 設定を使用します。

  1. pyproject.tomlの書き換え: Poetry形式の記述を、標準的な [project] テーブルに書き換えます。依存関係は tool.poetry.dependencies から project.dependencies に移動します。
    • ※ 手動での書き換えが基本ですが、一度 requirements.txt を吐き出してから取り込む方法も簡便です。
  2. 依存関係の取り込み:
    # Poetryで依存関係を出力
    poetry export -f requirements.txt --output requirements.txt --without-hashes
    
    # uvプロジェクトの初期化
    uv init
    
    # requirements.txtから依存関係を一括追加
    uv add -r requirements.txt
    
    # 開発用依存関係も同様に
    poetry export --only dev -f requirements.txt --output dev-requirements.txt
    uv add --dev -r dev-requirements.txt
    
  3. クリーンアップ: 不要になった poetry.lockrequirements.txt を削除し、生成された uv.lock をコミットします。

6.2 venv, pipからの移行

  1. 依存関係のエクスポート: 既存環境から依存リストを出力します。
    pip freeze > requirements.txt
    
    (もし既に手書きの requirements.txt がある場合はそれを使用します)
  2. uvプロジェクトの作成:
    uv init
    
  3. 依存関係の移行:
    uv add -r requirements.txt
    
    これにより、requirements.txt の内容が pyproject.toml に転記され、uv.lock が生成されます。今後は requirements.txt を直接編集するのではなく、uv add / uv remove で管理します。

7. uvのメリットとデメリット

メリット:

  • 圧倒的なパフォーマンス: Rustによる実装により依存関係解決とインストールが非常に高速です。
  • All-in-One: Pythonインストール、パッケージ管理、プロジェクト管理、ツール実行がこれ1つで完結します。
  • 標準準拠: 独自のメタデータ形式ではなく、標準のPEP 621 (pyproject.toml) を採用しています。
  • クロスプラットフォーム: Windows, Mac, Linuxで一貫したロックファイルを使用できます。

デメリット:

  • エコシステムの成熟度: 急速に開発が進んでいるため、破壊的な変更が入ることが稀にありますが、v0.5以降はかなり安定しています。
  • 一部のビルドツールとの相性: 非常に特殊なビルド設定を持つ古いパッケージの場合、設定が必要なことがあります。

参照

Discussion