こんにちは!日々の開発、本当にお疲れ様です。
新しい技術やツールをキャッチアップしようと奮闘するその姿勢、エンジニアとして本当に素晴らしいと思います。
さて、今回はPythonのパッケージ管理の世界における「大航海時代」のお話です。長年、私たちの相棒として親しまれてきた Poetry から、現在爆発的なスピードでシェアを広げている超高速な次世代パッケージマネージャー uv へ移行する際、多くの開発者が直面する「ある罠」と、それを美しく解決する実践的なアプローチについてお話しします。
「Poetryで作ったプロジェクトをuvで動かそうとしたら、なぜかエラーが出る……」
そんな絶望を味わったことはありませんか?実はこれ、両者の `pyproject.toml` の仕様の微妙なズレが原因です。
これをマスターすれば、依存関係の解決やビルドの待ち時間が劇的に短くなり、毎日のコーディングが驚くほど快適になりますよ。今日は、その裏側の仕組みから自動マイグレーションスクリプトの実装まで、優しく、そして深く紐解いていきましょう。
—
なぜPoetryからuvへの移行で「動かない」が起きるのか?
私たちが普段何気なく使っている `pyproject.toml` ですが、実は PEP 621 という標準規格をベースにしつつも、ツールごとに独自の拡張解釈や仕様を持っています。
ビルドバックエンドの決定的な違い
Poetryは、独自のビルドシステムである `poetry.core.masonry.api` を長年標準として採用してきました。一方、uv(およびその基盤である Astral のエコシステム、さらには現代のPython標準)は、より軽量で標準に準拠した `hatchling` や `setuptools`、あるいは純粋な PEP 621 準拠のビルドバックエンドを好みます。
Poetry形式で書かれた `pyproject.toml` には、以下のようなPoetry専用のセクションが残ります。
[tool.poetry]
name = “my-awesome-project”
version = “0.1.0”
description = “”
authors = [“Genius Engineer
[tool.poetry.dependencies]
python = “^3.10”
requests = “^2.31.0”
[build-system]
requires = [“poetry-core>=2.0.0”]
build-backend = “poetry.core.masonry.api”
これをそのまま `uv pip install` や `uv sync` に読み込ませようとすると、uvは標準規格(PEP 621)に則った依存関係の記述やビルドバックエンドを期待するため、Poetry固有の `[tool.poetry.dependencies]` テーブルを正しく解釈できずにフリーズするか、エラーを吐いて止まってしまうのです。
この仕様の不整合を手作業ですべて書き換えるのは、プロジェクトの規模が大きくなればなるほど苦行であり、ヒューマンエラーの温床になります。だからこそ、自動化が必要なのです。
—
uvの基礎セットアップ:まずはその圧倒的なスピードを体感する
移行スクリプトを書く前に、まずは現代の爆速ツール「uv」をあなたの開発環境に迎え入れましょう。uvは Rust製であり、Pythonの仮想環境作成やパッケージインストールを、これまでの常識を覆すスピード(pipの10倍以上)で実行してくれます。
1. uvのインストール
ターミナルを開き、以下のコマンドを実行してください(macOS / Linuxの場合)。
公式のインストーラースクリプトを安全にダウンロードして実行します
curl -LsSf https://astral.sh/uv/install.sh | sh
インストールが完了したら、パスを通すために一度シェルを再起動するか、指示されたコマンドを実行します。動作確認をしてみましょう。
uvのバージョンが正しく表示されるか確認します
uv –version
(例:`uv 0.5.x` のように表示されれば成功です!これだけで準備は完了です。)
—
現場で使える!pyproject.toml 自動マイグレーションスクリプト
ここからが本題です。Poetryの `pyproject.toml` を解析し、uv(PEP 621標準)が完璧に解釈できる形式へと自動変換するPythonスクリプトを一緒に作っていきましょう。
このスクリプトは、単なる文字列置換ではなく、Pythonの標準ライブラリ(または広く使われるパーサー)を利用して安全に構造体を変換します。
実装コード (`migrate_poetry_to_uv.py`)
プロジェクトのルートディレクトリに以下のスクリプトを配置し、実行してみてください。
import sys
from pathlib import Path
import tomli # TOMLを安全に読み込むためのライブラリ(Python 3.11未満の場合は要インストール)
import tomli_w # TOMLを書き出すためのライブラリ
def migrate_pyproject(file_path: Path):
“””
Poetry形式のpyproject.tomlを読み込み、
uv(PEP 621標準)が解釈できる形式に自動変換して上書き保存する関数
“””
if not file_path.exists():
print(f”[エラー] {file_path} が見つかりません。”)
sys.exit(1)
print(f”[情報] {file_path} の読み込みと解析を開始します…”)
# 1. 既存のtomlファイルを安全にロード
with open(file_path, “rb”) as f:
data = tomli.load(f)
# 2. poetryセクションの存在確認
if “tool” not in data or “poetry” not in data[“tool”]:
print(“[警告] 指定されたファイルに [tool.poetry] セクションが見つかりません。すでに移行済みか、別の形式です。”)
return
poetry_data = data[“tool”][“poetry”]
# 3. PEP 621 準拠の [project] テーブルを新規作成、または移行
project = data.get(“project”, {})
# 基本情報の移行
project[“name”] = poetry_data.get(“name”, “unnamed-project”)
project[“version”] = poetry_data.get(“version”, “0.1.0”)
project[“description”] = poetry_data.get(“description”, “”)
# 作者情報の変換 (Poetryのリスト形式からPEP 621の辞書形式へ)
if “authors” in poetry_data:
project[“authors”] = [
{“name”: author.split(” <")[0], "email": author.split(" <")[1].rstrip(">“)}
if ” <" in author else {"name": author}
for author in poetry_data["authors"]
]
# Pythonのバージョン要件の移行
if "dependencies" in poetry_data and "python" in poetry_data["dependencies"]:
# Poetryの "^3.10" などを uv/PEP 440 準拠の仕様に調整(必要に応じて拡張可能)
py_version = poetry_data["dependencies"]["python"].replace("^", ">=”)
project[“requires-python”] = py_version
# 4. 依存関係 (dependencies) の移行
dependencies = []
if “dependencies” in poetry_data:
for pkg, ver in poetry_data[“dependencies”].items():
if pkg == “python”:
continue # python要件は requires-python に逃がしたのでスキップ
# 簡易的なバージョンの書き換え(^ 記法を >= に変換するなど)
if isinstance(ver, str):
clean_ver = ver.replace(“^”, “>=”)
dependencies.append(f”{pkg}{clean_ver}”)
else:
# 辞書型(複雑な依存関係定義)の場合のプレースホルダー
dependencies.append(pkg)
project[“dependencies”] = dependencies
data[“project”] = project
# 5. ビルドバックエンドを Poetry から標準的な hatchling に変更
data[“build-system”] = {
“requires”: [“hatchling>=1.18.0”],
“build-backend”: “hatchling.build”
}
# 6. 古い Poetry 固有セクションの削除
del data[“tool”][“poetry”]
if not data[“tool”]: # toolセクションが空になったら削除
del data[“tool”]
# 7. 新しい pyproject.toml として書き出し
print(f”[情報] 変換されたデータを {file_path} に書き込んでいます…”)
with open(file_path, “wb”) as f:
tomli_w.dump(data, f)
print(“[成功] pyproject.toml の uv 向けマイグレーションが完了しました!”)
if __name__ == “__main__”:
target_toml = Path(“pyproject.toml”)
migrate_pyproject(target_toml)
—
移行時の「動かない」を防ぐためのチェックリスト
スクリプトを実行して終わり、ではありません。実務の現場で完全にシームレスに移行を完了させるために、以下のチェックリストを必ず確認してください。
- [ ] ロックファイルの切り替え
- Poetryの `poetry.lock` は uvでは読み込めません。移行後は `uv lock` コマンドを実行し、uv専用の `uv.lock` を新たに生成してください。
- [ ] 仮想環境の再構築
- 古い `.venv` ディレクトリが残っていると、依存関係の競合が起きる原因になります。一度 `rm -rf .venv` で綺麗に削除し、`uv venv` で新しく環境を作り直しましょう。
- [ ] 開発用依存関係(Dev Dependencies)の確認
- Poetryの `[tool.poetry.group.dev.dependencies]` や `[tool.poetry.dev-dependencies]` は、uvでは PEP 621 オプション依存(`[project.optional-dependencies]`)や uv特有のグループ管理に移行する必要があります。必要に応じてスクリプトのロジックを拡張してください。
—
動作確認:uvでプロジェクトを起動してみよう
マイグレーションとロックファイルの生成が終わったら、いよいよuvの圧倒的なスピードを体験する瞬間です。
以下のコマンドを順番に実行してみてください。
1. 仮想環境を爆速で作成します
uv venv
2. 仮想環境をアクティベートします(macOS / Linux)
source .venv/bin/activate
3. 依存関係を驚異的なスピードで同期(インストール)します
uv sync
数秒、あるいは一瞬で依存関係のインストールが完了したはずです。「え、もう終わったの?」と拍子抜けするほどの速さに、きっと感動していただけるはずです。
—
おわりに
今回は、Poetryからuvへの移行という、多くの開発者が躓きやすいポイントを自動化スクリプトと共に解説しました。
ツールが変われば、設定ファイルの仕様も変わります。しかし、その裏にある「標準規格(PEP)」を理解し、適切に橋渡しをしてあげることで、移行のストレスは最小限に抑えられます。何より、一度uvのスピードと快適さを知ってしまったら、もう元の環境には戻れなくなるはずです。
あなたの毎日のコーディングが、この知見によってより一層楽しく、クリエイティブなものになることを心から応援しています!