【実務・中級編】Poetryとuvを混在させる運用術:レガシーPoetryプロジェクトの高速化をuvで補完する現実解 – ビルド・パッケージ管理ツール生産性向上バイブル

こんにちは。テックリードの私だ。

日々のPython開発において、依存関係解決の美しさと厳密なロックファイル管理のために `Poetry` を導入しているチームは多いだろう。しかし、プロジェクトが巨大化するにつれて、こんな絶望的な状況に直面していないだろうか?

「`poetry install` や `poetry update` の依存解決が終わらない。コーヒーを淹れて戻ってきてもまだ回っている……」

このモダン開発のボトルネックを破壊するために現れたのが、Rust製パッケージマネージャー `uv` だ。驚異的な速度を誇る `uv` をいつものワークフローに組み込めば、Poetryの美しさを犠牲にせずとも、あの地獄のような待ち時間から解放される。

今回は、レガシーなPoetryプロジェクトの資産(`pyproject.toml` や `poetry.lock`)を完全維持しつつ、インストールと仮想環境構築のフェーズだけを `uv` に完全にオフロードする「ハイブリッド運用術」を解説する。チーム全体の生産性を暴力的に引き上げる実戦的アプローチを見ていこう。

—

1. なぜPoetryとuvを混在させるのか?(アーキテクチャの理解)

まず、両者の役割を明確に切り分ける必要がある。

  • Poetryの役割: パッケージのバージョン管理、セマンティックバージョニングに基づく依存関係の厳密な解決(`poetry.lock` の生成)、そして PyPI へのクリーンなパッケージ公開(Publish)フロー。
  • uvの役割: 爆速での依存関係解決、およびホイール(Wheel)の並列ダウンロード・キャッシュ・仮想環境へのアトミックな同期。

Poetryの `poetry lock` による依存解決アルゴリズムは正確だが、Python実装であるがゆえに巨大なツリー構造の解決に時間がかかる。一方、Astral社が開発した `uv` は、依存解決から環境構築までをC/Rustレベルの最適化とグローバルキャッシュ機構で圧倒的な速度(Poetryの10倍〜100倍)で実行する。

ここで重要なのは、「`poetry.lock` の生成はPoetryに任せ、生成されたロックファイルから仮想環境へのインストール実務だけを `uv` に奪還させる」というデータフローの設計だ。これにより、CI/CDやローカル開発環境のセットアップ時間を秒速に落とし込める。

—

2. ツールチェインの要:Makefileによる環境スイッチの自動化

チーム開発において、開発者が `uv` を手動で叩いたりPoetryを叩いたりと意識させるのは認知負荷の無駄だ。エントリポイントを `Makefile` に集約し、裏側のエンジンをスマートに切り替える。

以下に、実務で即採用できるベストプラクティスな `Makefile` を提示する。

Makefile
—————————————————————–
開発環境オーケストレーション用 Makefile (Poetry + uv ハイブリッド)
—————————————————————–

.PHONY: help install lock clean test

デフォルトターゲット
help:
@echo “利用可能なコマンド:”
@echo ” make install – uvを使用して超高速に仮想環境を構築・同期する”
@echo ” make lock – Poetryで依存関係を解決し、lockファイルを更新する”
@echo ” make clean – 仮想環境とキャッシュを完全にクリーンアップする”

【最重要】インストール処理は uv にオフロード
install:
@echo “==> [uv] 仮想環境の確認・作成と依存関係の高速同期を開始します…”
# .venvが存在しない場合は作成
@if [ ! -d “.venv” ]; then uv venv –python 3.11; fi
# poetry.lock を正として、uv pip sync で一瞬で環境を構築
@uv pip sync poetry.lock
@echo “==> 依存関係の同期が完了しました。”

【パブリッシュ前等】依存関係の解決とロックファイル更新は Poetry を使用
lock:
@echo “==> [Poetry] 依存関係の解決と lock ファイルの更新を実行中…”
poetry lock –no-update
@echo “==> lock ファイルの更新が完了しました。”

クリーンアップ
clean:
@echo “==> 仮想環境を削除しています…”
rm -rf .venv
@echo “==> クリーンアップ完了。”

この設計の狙い

  • `uv pip sync poetry.lock` は、`poetry.lock` に記述されたハッシュとバージョンを厳密に読み取り、現在の仮想環境と完全に一致(Sync)させる。これにより、Poetryのロックファイルの信頼性を100%維持できる。
  • 開発者は `make install` を叩くだけで、数分かかっていたセットアップが数秒で終わる体験を手に入れる。

—

3. 実用的な設定ファイルとベストプラクティス

プロジェクトルートにおける `pyproject.toml` は、Poetryの仕様に完全準拠させつつ、`uv` が解釈しやすい状態を保つ。

`pyproject.toml` の最適解

[tool.poetry]
name = “legacy-core-service”
version = “1.2.0”
description = “Poetryの公開フローを維持しつつuvで高速化されたバックエンドサービス”
authors = [“DevOps Team “]
readme = “README.md”
packages = [{include = “core”, from = “src”}]

[tool.poetry.dependencies]
python = “^3.11”
fastapi = “^0.110.0”
uvicorn = {extras = [“standard”], version = “^0.28.0”}
sqlalchemy = “^2.0.28”
pydantic = “^2.6.4”

[tool.poetry.group.dev.dependencies]
pytest = “^8.1.0”
ruff = “^0.2.2”
mypy = “^1.8.0”

[build-system]
requires = [“poetry-core”]
build-backend = “poetry.core.masonry.api”

— uv向けの追加最適化設定 —
[tool.uv]
仮想環境をプロジェクト直下に .venv として確実に作成させる
venv = “.venv”
パッケージのコンパイル時にバイナリキャッシュを積極活用するポリシー
cache-keys = [{ file = “poetry.lock” }]

—

4. チーム開発を加速する IDE(VSCode)の設定共有化

ローカル環境の高速化だけでなく、チーム全体で開発体験を統一するための `.vscode/settings.json` の設定だ。VSCodeが自動的に `.venv` を認識し、リントや型の解決が爆速で行われるようにする。

`.vscode/settings.json`

{
// Pythonインタプリタのパスをプロジェクト直下の uv 製仮想環境に明示的に固定
“python.defaultInterpreterPath”: “${workspaceFolder}/.venv/bin/python”,

// リンター(Ruff)にプロジェクトの仮想環境内のバイナリを使用させる
“ruff.importStrategy”: “fromEnvironment”,

// 型チェッカー(Mypy)の実行環境を仮想環境に連動
“mypy-type-checker.importStrategy”: “fromEnvironment”,

// 保存時の自動フォーマット・リント修正を有効化し、開発スピードを最大化
“editor.codeActionsOnSave”: {
“source.fixAll.ruff”: “explicit”,
“source.organizeImports.ruff”
},

// 巨大な仮想環境フォルダやキャッシュをファイル検索から除外してIDEの動作を軽量化
“files.exclude”: {
“/.venv”: true,
“/__pycache__”: true,
“/.ruff_cache”: true
}
}

—

5. CI/CDパイプライン(GitHub Actions)での実践的適用

ローカルが速くなっても、CIが遅ければ意味がない。GitHub Actionsにおいて、Poetryの遅いインストールを `uv` によって劇的に短縮するワークフローの記述例だ。

`.github/workflows/ci.yml`

name: CI/CD Pipeline

on:
push:
branches: [ main ]
pull_request:
branches: [ main ]

jobs:
test:
runs-on: ubuntu-latest
steps:

  • name: リポジトリのチェックアウト

uses: actions/checkout@v4

# 1. 爆速の Rust 製ツールチェイン uv をセットアップする公式アクション

  • name: Set up uv

uses: astral-sh/setup-uv@v5
with:
enable-cache: true # GitHub Actionsのキャッシュ機構を自動有効化
cache-dependency-lockfile: “poetry.lock”

# 2. Python本体のセットアップ(uvが自動管理するため軽量)

  • name: Set up Python

uses: actions/setup-python@v5
with:
python-version: “3.11”

# 3. 仮想環境の作成と依存関係の同期(わずか数秒で完了)

  • name: Install dependencies with uv

run: |
uv venv –python 3.11
uv pip sync poetry.lock

# 4. テストの実行(仮想環境のバイナリを直接叩く)

  • name: Run tests with pytest

run: |
.venv/bin/pytest –cov=src tests/

# 5. パッケージ公開フェーズのみ、厳密なPoetryを使用する

  • name: Build and Publish (Only on Release Tag)

if: startsWith(github.ref, ‘refs/tags/v’)
env:
POETRY_PYPI_TOKEN_PYPI: ${{ secrets.PYPI_API_TOKEN }}
run: |
# パブリッシュ時はPoetry経由で正しくビルド・送信
pip install poetry
poetry publish –build

—

6. プロフェッショナルの知見:運用上の注意点とトラブルシューティング

このハイブリッド運用を現場に導入するにあたり、テックリードとして知っておくべき「罠」と回避策を共有する。

1. Direct Dependency(直接依存)の追加時のフロー

  • 新しくパッケージを追加したい時は、`uv pip install` を直接叩いてはならない(それだと `poetry.lock` に記録されず、Poetryの管理から外れてしまう)。
  • 正しい手順: `poetry add ` でPoetryに `poetry.lock` を更新させ、その後 `make install`(中身は `uv pip sync`)を実行してローカル環境を同期する。

2. バイナリの互換性とプラットフォーム差異

  • `uv` は非常にアグレッシブにプラットフォーム固有のホイールを解決・キャッシュする。Dockerコンテナ内(Linux)とホストOS(macOS Apple Silicon)の間でキャッシュを共有しようとするとトラブルの元になるため、CIやコンテナビルド内では必ずクリーンな状態から `uv venv` を実行すること。

—

総括

Poetryの持つ美しく堅牢なパッケージング・公開の思想と、`uv` がもたらす圧倒的な物理的スピード。これらは決して二者択一ではない。

レガシーなPoetryプロジェクトの資産を一切書き換えることなく、「依存解決・公開はPoetry」「仮想環境構築・同期はuv」という役割分担のアーキテクチャを導入することで、チームの開発体験は劇的に生まれ変わる。

待ち時間という名の技術的負債を今すぐ切り捨て、真にコードを書く時間を取り戻してほしい。

タイトルとURLをコピーしました