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

[**簡易版はこちら**](https://qiita.com/futakuchi0117/items/9ec8bd84797fed180647)

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

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

- [uv公式ドキュメント](https://docs.astral.sh/uv/)
- [uv (github)](https://github.com/astral-sh/uv)

### 1. uvの概要

#### 1.1 uvとは？

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

![Monosnap uv 2024-11-01 23-53-30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/193401/9c36603d-0bf4-1292-9287-c3e892668a5b.png)


#### 1.2 uvのアーキテクチャ

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

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

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

```bash
# 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といったパッケージマネージャーからもインストール可能です。

```bash
# 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をインストールできます。

```bash
uv python install 3.10 3.11 3.12
```

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

```bash
uv python list
```

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

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


#### 2.2 スクリプトの実行

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

```bash
uv run example.py
```

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

```bash
uv run --with requests example.py
```

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

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

import requests

# ...
```

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


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

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

```bash
uvx ruff
```

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

```bash
uv tool install ruff
```

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

```bash
uvx --from httpie http
```

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

```bash
uvx ruff@0.3.0 check
```

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

```bash
uvx --with mkdocs-material mkdocs --help
```

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

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

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

```bash
uv init my-project
```

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

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

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

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

```bash
uv init --app --package my-cli
```

`uv init`では、`hatchling`、`flit-core`、`pdm-backend`、`setuptools`、`maturin`、`scikit-build-core`といったビルドバックエンドを選択できます。`--build-backend`オプションで、使用するバックエンドを指定します。

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

#### 3.2 依存関係の管理

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

```bash
uv add requests
```

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

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

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

```bash
uv add --dev pytest
```

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

```bash
uv add --optional pandas pandas[excel]
```

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

```bash
uv remove requests
```

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

```bash
uv add 'requests>2.30.0'
```

#### 3.3 環境の管理

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

```bash
uv sync
```

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

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

#### 3.4 ロックファイルの管理

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

```bash
uv lock
```

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

```bash
uv lock --upgrade
```

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

```bash
uv lock --upgrade-package requests
```

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

#### 3.5 ワークスペースの活用

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

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

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

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

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

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

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

```toml
[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イメージにコピーすることもできます。

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

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

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

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

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

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

#### 5.2 GitHub Actionsとの連携

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

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

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

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

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

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

```yaml
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イメージを利用できます。

```yaml
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のキャッシュを永続化することもできます。

```yaml
cache:
  - key: uv-cache
    paths:
      - .uv-cache
```

#### 5.4 Jupyterとの連携

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

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

```bash
uv run --with jupyter jupyter lab
```

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

```bash
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`を自動生成できます。

```yaml
- 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 install`は`uv pip install`に、`pip freeze`は`uv pip freeze`に置き換えます。

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

メリット：

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

デメリット：

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

### 参照

- [uv公式ドキュメント](https://docs.astral.sh/uv/)
- [uv (github)](https://github.com/astral-sh/uv)