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

2024/11/02に公開

簡易版はこちら

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

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

1. uvの概要

1.1 uvとは?

uvは 高速な動作、クロスプラットフォーム対応のロックファイル、ツール管理の専用インターフェースを提供することで、快適な開発環境を実現しています。

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のバイナリを削除するだけで完了します。

2. uvの基本的な使い方

2.1 Pythonバージョンの管理

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

uv python install 3.10 3.11 3.12

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

uv python list

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

uvは、必要に応じてPythonバージョンを自動的にダウンロードします。自動ダウンロードを無効にするには、--no-python-downloadsオプションを使用します。

2.2 スクリプトの実行

uvは、スタンドアロンスクリプトの実行をサポートしています。uv runコマンドで、スクリプトを実行できます。

uv run example.py

スクリプトに必要な依存関係は、--withオプションで指定します。

uv run --with requests example.py

また、スクリプトの先頭にインラインメタデータを記述することで、依存関係を宣言できます。

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

import requests

# ...

再現性を向上させるために、tool.uv.exclude-newerフィールドを使用して、特定の日付より前にリリースされたパッケージのみを使用するように制限することもできます。

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

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

uvx ruff

ツールは、一時的な隔離環境にインストールされます。永続的な環境にツールをインストールするには、uv tool installコマンドを使用します。

uv tool install ruff

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

uvx --from httpie http

特定のバージョンのツールを実行するには、@記法を使用します。

uvx ruff@0.3.0 check

ツールにプラグインが必要な場合は、--withオプションで追加の依存関係を指定します。

uvx --with mkdocs-material mkdocs --help

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

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

uvは、pyproject.tomlファイルで定義されたPythonプロジェクトの管理をサポートしています。uv initコマンドで、新しいプロジェクトを作成できます。

uv init my-project

--appオプションでアプリケーションプロジェクト、--libオプションでライブラリプロジェクトを作成できます。

# アプリケーションプロジェクト
uv init --app my-app

# ライブラリプロジェクト
uv init --lib my-lib

さらに、--packageオプションを指定することで、配布可能なアプリケーションを作成できます。これは、PyPIなどを介してコマンドラインインターフェースを公開する場合に便利です。

uv init --app --package my-cli

uv initでは、hatchlingflit-corepdm-backendsetuptoolsmaturinscikit-build-coreといったビルドバックエンドを選択できます。--build-backendオプションで、使用するバックエンドを指定します。

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

3.2 依存関係の管理

uv addコマンドで、pyproject.tomlに依存関係を追加できます。

uv add requests

--editableオプションで、編集可能な依存関係を追加できます。

uv add --editable ./path/to/my-package

--devオプションで、開発用の依存関係を追加できます。

uv add --dev pytest

--optionalオプションで、オプションの依存関係を追加できます。

uv add --optional pandas pandas[excel]

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

uv remove requests

uv addコマンドで、既存の依存関係を更新することもできます。

uv add 'requests>2.30.0'

3.3 環境の管理

uvは、プロジェクトごとに仮想環境を自動的に作成します。uv syncコマンドで、環境を最新の状態に同期できます。

uv sync

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

UV_PROJECT_ENVIRONMENT環境変数で、プロジェクトの仮想環境のパスを設定できます。

3.4 ロックファイルの管理

uvは、uv.lockというクロスプラットフォームのロックファイルを生成します。uv lockコマンドで、ロックファイルを明示的に更新できます。

uv lock

--upgradeオプションで、すべてのパッケージを最新バージョンにアップグレードできます。

uv lock --upgrade

--upgrade-packageオプションで、特定のパッケージをアップグレードできます。

uv lock --upgrade-package requests

tool.uv.environments設定で、解決するプラットフォームを制限できます。

3.5 ワークスペースの活用

uvは、Cargoスタイルのワークスペースをサポートしています。ワークスペースは、複数のパッケージをまとめて管理するための機能です。

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

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

membersキーで、ワークスペースメンバーを指定します。excludeキーで、除外するディレクトリを指定できます。

ワークスペースメンバーは、tool.uv.sourcesで依存関係として宣言します。

[tool.uv.sources]
my-package = { workspace = true }

ワークスペースルートのtool.uv.sourcesは、すべてのメンバーに適用されます。

4. uvの高度な機能

4.1 依存関係の解決

uvは高度な依存関係解決アルゴリズムを備えています。uvの依存関係解決は、以下の要素を考慮します。

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

uvは、これらの要素を考慮しながら、すべての依存関係を満たす最適なパッケージの組み合わせを探索します。このプロセスがめっちゃ高速に行われます。

uvは、ユニバーサル解決プラットフォーム固有の解決の両方をサポートしています。ユニバーサル解決では、すべてのプラットフォームで動作するロックファイルを生成します。これは、チーム開発やCI/CD環境で特に役立ちます。プラットフォーム固有の解決では、特定のプラットフォームに最適化されたロックファイルを生成します。

uvは、依存関係の解決時に、最新バージョンを優先します。これは、常に最新のパッケージを使用することで、セキュリティリスクを軽減し、新機能を活用できるという利点があります。ただし、必要に応じて、--resolution lowestオプションで最低バージョンを優先したり、--resolution lowest-directオプションで直接依存関係のみ最低バージョンを優先したりすることもできます。

4.2 キャッシュの管理

uvは、強力なキャッシュ機構を備えています。ダウンロードしたパッケージ、ビルドされたwheelファイル、ソースコードなどをキャッシュすることで、依存関係の解決とインストールを高速化します。

uvのキャッシュは、以下の特徴があります。

  • 効率性: 依存関係の再利用性を高め、処理時間を短縮
  • 安全性: スレッドセーフであり、複数のコマンドを同時実行しても安全
  • 柔軟性: キャッシュディレクトリの設定、キャッシュのクリア、プルーニングなど、柔軟な管理が可能

uv cache cleanコマンドで、キャッシュをすべて削除できます。uv cache pruneコマンドで、未使用のキャッシュエントリを削除できます。--cache-dirオプションで、キャッシュディレクトリを指定できます。

4.3 ビルドの分離

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

ただし、一部のパッケージはビルドの分離に対応していません。そのようなパッケージをインストールする場合は、no-build-isolation-package設定でビルドの分離を無効にする必要があります。

[tool.uv]
no-build-isolation-package = ["my-package"]

ビルドの分離を無効にする場合は、パッケージのビルドに必要な依存関係を事前にインストールしておく必要があります。

4.4 パブリッシュ

uvは、uv buildコマンドでPythonパッケージをソースディストリビューションとバイナリディストリビューションにビルドし、uv publishコマンドでレジストリにアップロードすることができます。

uv publishコマンドでは、--tokenオプションでPyPIトークンを指定するか、--usernameオプションと--passwordオプションでユーザー名とパスワードを指定することで、認証を行うことができます。

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

uvは、他の開発ツールと連携することで、より強力な開発ワークフローを構築することができます。ここでは、代表的なツールとの連携方法を紹介します。

5.1 Dockerとの連携

uvは、Dockerとの連携に優れており、コンテナ化されたアプリケーションの開発を効率化します。

uvの公式Dockerイメージを利用することで、簡単にuvを実行することができます。また、COPY --from構文を利用して、uvバイナリを自身のDockerイメージにコピーすることもできます。

FROM python:3.12-slim
COPY --from=ghcr.io/astral-sh/uv:latest /uv /bin/uvx /bin/

プロジェクトをDockerイメージにインストールするには、uv syncコマンドを使用します。

COPY . /app
WORKDIR /app
RUN uv sync --frozen

.dockerignoreファイルに.venvを追加して、プロジェクトの仮想環境がイメージに含まれないようにすることが重要です。

Docker Composeを使用する場合は、watchオプションで開発環境を構築できます。これにより、プロジェクトの変更がコンテナに即座に反映されます。

services:
  example:
    build: .
    develop:
      watch:
        - action: sync
          path: .
          target: /app
          ignore:
            - .venv/

5.2 GitHub Actionsとの連携

GitHub Actionsでuvを使用するには、公式のastral-sh/setup-uvアクションを利用するのが便利です。

steps:
  - uses: actions/checkout@v4
  - name: Install uv
    uses: astral-sh/setup-uv@v3

setup-uvアクションは、uvのインストール、キャッシュの永続化、Pythonのセットアップなどを自動的に行います。

uvとactions/setup-pythonアクションを組み合わせて、Pythonのバージョンを指定することもできます。

steps:
  - uses: actions/setup-python@v5
    with:
      python-version-file: ".python-version"

uv syncコマンドでプロジェクトをインストールし、uv runコマンドでテストを実行できます。

steps:
  - run: uv sync --all-extras --dev
  - run: uv run pytest tests

actions/cacheアクションを利用して、uvのキャッシュを永続化することで、ワークフローの実行時間を短縮できます。

5.3 GitLab CI/CDとの連携

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

variables:
  UV_VERSION: 0.4
  PYTHON_VERSION: 3.12
  BASE_LAYER: bookworm-slim

uv:
  image: ghcr.io/astral-sh/uv:$UV_VERSION-python$PYTHON_VERSION-$BASE_LAYER
  script:
    # your `uv` commands

GitLab CI/CDのキャッシュ機能を利用して、uvのキャッシュを永続化することもできます。

cache:
  - key: uv-cache
    paths:
      - .uv-cache

5.4 Jupyterとの連携

uvは、Jupyter Notebookとの連携もサポートしています。

プロジェクト内でJupyterを使用するには、uv runコマンドでJupyterサーバーを起動します。

uv run --with jupyter jupyter lab

ノートブックからパッケージをインストールする場合は、ipykernelを開発用依存関係として追加し、カーネルを作成します。

uv add --dev ipykernel
uv run ipython kernel install --user --name=my-project

カーネルを作成せずに、プロジェクトの仮想環境にパッケージをインストールする場合は、!uv pip installコマンドを使用します。

5.5 pre-commitとの連携

uvは、pre-commitとの連携もサポートしています。公式のastral-sh/uv-pre-commitフックを使用することで、コミット前に uv export --format requirements-txt を実行し、requirements.txtを自動生成できます。

- repo: https://github.com/astral-sh/uv-pre-commit
  rev: 0.4.26
  hooks:
    - id: pip-compile
      args: [requirements.in, -o, requirements.txt]

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

現在poetry, venv, pipを使用しているチームが、すべてuvに移行する場合、以下の手順がよさそうです。

6.1 poetryからの移行

  1. pyproject.tomlの変換: poetryのpyproject.tomlをuvのpyproject.tomlに変換します。poetryのtool.poetryセクションをtool.uvセクションに置き換え、必要な設定を移行します。依存関係は、tool.poetry.dependenciesからproject.dependenciesに移動します。
  2. 依存関係の移行: poetryの仮想環境にインストールされている依存関係を、uvの仮想環境に移行します。poetry export -f requirements.txt --output requirements.txtコマンドで、poetryの依存関係をrequirements.txtファイルにエクスポートします。そして、uv pip install -r requirements.txtコマンドで、uvの仮想環境に依存関係をインストールします。
  3. 環境の移行: poetryの仮想環境で使用していた設定を、uvの仮想環境に移行します。環境変数、Pythonバージョンなどを確認し、必要に応じてuvの環境に設定します。

6.2 venv, pipからの移行

  1. 仮想環境の移行: venvで作成した仮想環境を、uvの仮想環境に移行します。pip freeze > requirements.txtコマンドで、venvの仮想環境にインストールされている依存関係をrequirements.txtファイルにエクスポートします。そして、uv venvコマンドで新しい仮想環境を作成し、uv pip install -r requirements.txtコマンドで依存関係をインストールします。
  2. 依存関係の移行: pipで管理していた依存関係を、uvのpyproject.tomlに移行します。requirements.txtファイルの内容を参考に、project.dependenciesに依存関係を記述します。
  3. ワークフローの移行: pipコマンドをuv pipコマンドに置き換え、uvのワークフローに適応させます。例えば、pip installuv pip installに、pip freezeuv pip freezeに置き換えます。

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

メリット:

  • 高速なパフォーマンス: Rustによる実装により依存関係の解決が超速です。
  • クロスプラットフォーム対応: ユニバーサルロックファイルにより、異なるプラットフォーム間での一貫性を確保します。
  • 豊富な機能: 依存関係管理、環境管理、ツール管理、スクリプト実行など、Python開発に必要な機能を網羅しています。
  • 使いやすさ: シンプルなコマンド体系と分かりやすいドキュメント。

デメリット:

  • エコシステムの成熟度: pipに比べて、エコシステムはまだ成熟していないとのことですが、具体的に不都合があるかどうかはまだ体感できていません。
  • 学習コスト: 新しいツールであるため、学習コストが必要です。

参照

Discussion