0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

uv と direnv を用いて Python 環境をプロジェクトごとに動的に切り替える

Last updated at Posted at 2025-05-31

1. はじめに

チーム開発を進める中で、各開発者の Python バージョンやインストールされているパッケージが異なり、開発環境の統一が難しいという問題に直面することがあります。この問題を解決し、Python のバージョン管理だけでなく、使用するライブラリ群のバージョンもプロジェクトごとに統一し、かつディレクトリ移動に応じて自動的に開発環境を切り替える方法を、uvdirenv を用いて実現します。

2. 前提

本記事の手順は、以下の環境を前提としています。

  • macOS であること
  • Homebrew が利用可能であること

3. 本題

3-1. 必要なツールのインストール

まず、Python パッケージインストーラー兼バージョマネージャーである uv と、ディレクトリベースで環境変数を管理する direnv を インストールします。

brew install uv
brew install direnv

3-2. direnv をシェルに設定

direnv を利用するためには、お使いのシェルに応じた設定をシェルの設定ファイル(例: .zshrc, .bashrc など)に追加します。

zsh の場合 (.zshrc):

echo 'eval "$(direnv hook zsh)"' >> ~/.zshrc
source ~/.zshrc

bash の場合 (.bashrc):

echo 'eval "$(direnv hook bash)"' >> ~/.bashrc
source ~/.bashrc

設定後、ターミナルを再起動するか、source コマンドで設定を読み込んでください。

3-3. プロジェクトごとの環境構築

ここでは、例として sample_project という名前のプロジェクトを作成し、Python 3.13.3 の環境を構築します。

プロジェクトディレクトリの作成と uv init による初期化

まずプロジェクトディレクトリを作成し、uv init コマンドでプロジェクトを初期化します。これにより、pyproject.toml ファイルが生成されます。

mkdir sample_project
cd sample_project
uv init

uv init を実行することで以下ファイルが生成されます。
注意: uv init が生成する内容は uv のバージョンによって変わることがあります。下記は一例です。

スクリーンショット 2025-05-31 15.18.49.png

生成される pyproject.toml の例:

pyproject.toml
[project]
name = "sample-project"
version = "0.1.0"
description = "Add your description here"
readme = "README.md"
requires-python = ">=3.12.2"
dependencies = []

pyproject.toml の編集

次に、pyproject.toml を編集して、プロジェクトに必要な依存関係を定義します。

例として、fastapiuvicorn を通常依存、ruffpytest を開発用依存として追加します。

[project]
name = "sample_project"
version = "0.1.0"
description = "A FastAPI project managed with uv and direnv."
readme = "README.md"
requires-python = ">=3.12.2"
dependencies = [
    "fastapi>=0.100.0",
    "uvicorn[standard]>=0.20.0",
]

# 開発用依存関係 (uv がサポートする形式)
[project.optional-dependencies]
dev = [
    "ruff",
    "pytest",
    "black",
]

requires-python は、このプロジェクトが要求する Python のバージョンを指定します。使用する Python バージョンに合わせて適切に設定してください。

pyproject.toml が編集できたらライブラリを同期します。

uv pip sync pyproject.toml

ライブラリがインストールされていることが確認できる
スクリーンショット 2025-05-31 15.33.15.png

uv による仮想環境の作成

uv venv コマンドを使用して、プロジェクト用の仮想環境を作成します。pyproject.tomlrequires-python で指定したバージョンと互換性のある Python バージョンを指定します(例: Python 3.13.3)。

uv venv --python 3.13.3

成功すると、プロジェクトディレクトリ直下に .venv という名前の仮想環境が作成されます。

スクリーンショット 2025-05-31 15.18.24.png

.envrc ファイルの作成と編集

次に、ディレクトリに入ったときに自動的に仮想環境が有効になり、依存関係が同期されるように .envrc ファイルを作成・編集します。

# 0. uv コマンドの存在確認
# `has` は direnv の標準関数で、コマンドの存在をチェックします。
if ! has uv; then
  echo "uv が見つからないためパッケージの同期をスキップします" >&2
  return 1 # .envrc の処理を中断し、エラーコード 1 を返すが、シェルは終了しない
fi

# 1. 仮想環境のアクティベート
# プロジェクトローカルの .venv を有効化します。
source .venv/bin/activate

# 2. pyproject.toml と uv.lock の変更を監視
# これらのファイルが変更された場合、direnv は .envrc を再ロードします。
watch_file pyproject.toml
watch_file uv.lock # uv.lock は uv pip sync/add などで生成・更新されます

# 3. 依存関係の自動同期
# uv.lock に変更があった場合のみ実行されます。
# 開発環境を想定し、開発用依存関係も含めて同期します (--extra-index-url dev)。
# `uv pip sync` は `pyproject.toml` と `uv.lock` (あれば) に基づいて環境を同期します。
if [ -f uv.lock ]; then
    uv pip sync pyproject.toml --extra-index-url dev
fi

上記の内容を sample_project/.envrc として保存します。

解説
  • has uv: uv コマンドが利用可能かチェックします
  • source .venv/bin/activate: uv で作成したローカルの仮想環境を有効にします
  • watch_file pyproject.toml / watch_file uv.lock: これらのファイルが変更されると、.envrc が再評価され、後続のコマンド(ここでは uv pip sync)が再実行されるトリガーとなります
  • uv pip sync pyproject.toml --extras dev: pyproject.toml に記述された通常依存と、[project.optional-dependencies]dev グループに記述された開発用依存関係を仮想環境に同期する。uv.lock ファイルが存在すれば、ロックファイルに基づいて同期し、なければ pyproject.toml から解決して uv.lock を生成/更新する

direnv に設定の読み込みを許可

セキュリティのため、direnv.envrc ファイルの内容を自動的には実行しません。
以下のコマンドで、このディレクトリの .envrc ファイルの実行を許可します。

direnv allow .

初回許可後、sample_project ディレクトリに入るたびに、自動的に .venv 仮想環境が有効になり、依存関係が pyproject.toml に基づいて同期されます。

スクリーンショット 2025-05-31 15.26.00.png

依存関係の確認

.envrc が正しく設定されていれば、direnv allow . を実行した際、または一度ディレクトリ外に出て再度入った際に、uv pip sync が実行され、pyproject.toml に記述した依存関係がインストールされます。

uv pip list でインストールされたパッケージを確認できます。

uv pip list

スクリーンショット 2025-05-31 15.39.30.png

4. 開発ワークフロー

4-1. 新しいパッケージの追加

プロジェクトに新しいパッケージを追加する場合は、uv add コマンドを使用します。これにより、pyproject.toml が自動的に更新され、uv.lock も更新されます。direnv が変更を検知し、自動的に uv pip sync を実行して仮想環境にパッケージをインストールします。

通常依存の追加:

uv add requests

pyproject.toml[project].dependenciesrequests が追加されます。

開発用依存の追加 (optional-dependencies の 'dev' グループへ):

uv add "ruff" --group dev
uv add "black" --optional dev

pyproject.toml[project.optional-dependencies.dev]ruffblack が追加されます。
(uv add--dev--group オプションの挙動は uv のバージョンにより若干異なる場合があるため、公式ドキュメントをご確認ください。[project.optional-dependencies] を使うのが標準的です。)

uv add 実行後、.envrcwatch_file 機能により direnvpyproject.toml の変更を検知し、自動的に uv pip sync を実行して新しいパッケージが仮想環境にインストールされます。手動で同期したい場合は、ディレクトリに入り直すか、direnv reload を実行します。

4-2. 依存関係の更新

既存のパッケージを最新バージョンに更新したい場合も、pyproject.toml を直接編集するか、uv add package_name@latest のようにして更新後、direnv が自動で同期します。
もし手動ですべてのパッケージを最新バージョンに更新する場合は以下コマンドを実行します。

# すべてのパッケージを最新バージョンに更新
uv pip sync pyproject.toml --upgrade

# 特定のパッケージのみを更新
uv pip sync pyproject.toml --upgrade-package requests

# 開発用依存関係も含めて更新
uv pip sync pyproject.toml --upgrade --group=dev

5. 動作確認

設定が正しく行われていれば、以下の動作が確認できます。

5-1. sample_project へ移動

ターミナルで sample_project ディレクトリに移動すると、.envrc がロードされ、uv pip sync が実行されます。プロンプトに (.venv) が表示され、仮想環境が有効になります。
python --versionwhich python で仮想環境の Python が使われていることを確認します。
pyproject.toml に記述した fastapi や開発用ツールの ruff などが import できるか(またはコマンドとして利用できるか)確認します。

スクリーンショット 2025-05-31 16.00.14.png

5-2. sample_project から移動:

他のディレクトリに移動すると、.envrc がアンロードされ、仮想環境が無効になります。

スクリーンショット 2025-05-31 15.59.33.png

5-3. pyproject.toml の変更:

pyproject.toml の依存関係を手動で変更・保存すると、direnv が変更を検知し、再度 uv pip sync を実行して環境を更新します。

スクリーンショット 2025-05-31 16.03.51.png

6. まとめ

uvdirenv用いてプロジェクトごとの Python 環境を動的に切り替える方法を紹介しました。
チームメンバー内における Python バージョンやライブラリのバージョン統一に向けて少しでも参考になれば幸いです。

7. 【推奨】 .gitignore の設定

プロジェクトの .gitignore ファイルには、uv が作成する仮想環境ディレクトリと direnv が使用する状態管理ディレクトリを追加しておくことを推奨します。

# uv
.venv/
.direnv/

参考

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?