はじめに
Pythonで開発をしていると、当たり前のように使っているパッケージ管理。
最近では、爆速ツールとして話題のuvを使い始めた方も多いのではないでしょうか?
私も最近、uvを使って環境管理をすることになり、
設定ファイルのpyproject.tomlをいじることがありました。
「なんとなく、ここにライブラリ名を書くんだなというのは分かる。」
「でも、結局このファイルのどこが大事で、何を書けばいいの?」
という感じに、、、
普段はコマンド一発で動くので意識しなくても開発は進められますが、
以下のような場面ではpyproject.tomlの中身を理解しているとグッと楽になります。
- 「ライブラリを入れたはずなのに動かない!」というトラブルの解決
- 「本番環境にはこれ、開発ツールにはこれ」とスマートに使い分けたいとき
- 「チームメンバー全員と同じ環境を作りたい」と構成を整えるとき
この記事では、uvを使ってPython環境を管理する時に、とりあえずこれだけ書いておけばOKという基本から、知っておくと便利な設定までをシンプルに解説します。
tomlファイルに馴染みがあって、uvでのpyproject.tomlの書き方が知りたいという方は
#uvで環境を管理する時に何を書くべき?まで飛ばしてもらって大丈夫です!
.tomlファイルとは?
まずはtoml形式について簡単に紹介します!
yaml, jsonなどはよく見るけど、tomlってあんまり馴染みがなかったりしますよね、、、
なんだか難しそうに聞こえるかもしれませんが、
toml形式は人間が読み書きしやすくするために生まれた、設定ファイル用の書き方のことです。
正式名称はTom's Obvious Minimal Language(トムさんの、明快で、最小限の言語)。名前に「明快(Obvious)」と入っている通り、パッと見て何が書いてあるか分かりやすいのが最大の特徴です。
こんな形式のファイルです
見た方が早いので、具体例を紹介します。
# pyproject.toml
[project]
name = "my-app"
version = "0.1.0"
dependencies = [
"requests",
"pandas",
]
[ ]で囲まれたセクション(グループ名)があって、
その下に名前 = 値というルールで設定を並べていくスタイルです。
どんな場面で使われる?
モダンな開発環境の中では、
プロジェクト設定の標準になりつつあるのではないでしょうか?
例えば、
- パッケージ管理:
uvやPoetryなどのツール設定 - ツールの設定: コードを綺麗にする
Ruffや、テスト用のpytestの設定 - Rust言語: Rustの標準的なパッケージ管理(Cargo)
具体的なユースケースについては後ほど見ていきましょう。
YAML, JSONとの違い
「設定ファイルなら、JSONやYAMLじゃダメなの?」と思うかもしれません。
それぞれの特徴を比較してみます。
| 形式 | 特徴 | 注意ポイント |
|---|---|---|
| JSON | プログラムが読みやすい | コメントが書けない。 カンマ一つ忘れるだけでエラー。 |
| YAML | 見た目がスッキリしている | インデント(空白)に命をかけている。 スペース1個のズレで設定が壊れる。 |
| TOML | 人間が読み書きしやすい | 最初は [ ] の書き方に少し戸惑うかも。 |
- TOMLのいいところ
- コメントが書ける:「なぜこのライブラリを入れたか」をメモしておけます。
- インデントに厳しくない:スペースの数でプログラムが止まることはありません。
- 構造がはっきりしている:
[project]や[tool.uv]のようにグループ分けされているので、どこに何を書くべきか迷いにくいです。
慣れてしまえば、快適な開発環境管理ができそうですね!
pyproject.tomlの便利なユースケース
toml形式で管理されている設定ファイルは、他にもありますが
今回はPython環境の管理をするpyproject.tomlに焦点を当てて見ていきます。
pyproject.tomlは、ただライブラリをリストアップするだけのファイルではありません。
これ一つでわずらわしかった環境管理を一手に担うハブです!
いくつかのユースケースを見ていきます。
1. uvでPython環境をまるごと管理する
これは今回メインで伝えたい内容です。
これまでの悩み
- 「Pythonのバージョンを切り替えるには pyenv」
- 「仮想環境を作るには python -m venv」
- 「ライブラリを入れるには pip install」
……と、覚えるコマンドも使うツールもバラバラで、
「結局いまどの環境に何が入ってるの?」と混乱しがちでした。
解決されること
pyproject.tomlに「使いたいPythonのバージョン」と「必要なライブラリ」を書いておくだけで、
uvがこれらすべてを自動で準備してくれます。
uvでもpipライクに環境を作れるのですが、
pyproject.tomlで管理することで大きな恩恵が得られます。
uv runだけで環境構築が完了するのは魅力ですね!
2. テストツール(pytest)の設定
テストを実行するためのpytestの設定も、tomlに書くのが標準的です。
これまでの悩み
「テストの時だけこのフォルダを無視したい」といった設定を、
コマンドを打つたびにオプションで指定するのは面倒で、ミスも起きやすいです。
解決されること
[tool.pytest.ini_options]にあらかじめ書いておけば、
次からはpytestと打つだけで、プロジェクト専用のルールでテストが走ります。
3. 自作スクリプトのショートカット作成
これが意外と知られていない、一番便利なポイントかもしれません。
これまでの悩み
「このアプリを起動するには、この環境変数をセットして、このファイルを指定して……」という長いコマンドを、毎回メモ帳からコピペしていませんか?
解決されること
[project.scripts]やuvの機能を使えば、自分専用の短いコマンドを定義できます。
例えば、uv run startと打つだけで、複雑な起動処理を一瞬で実行できるようになります。
uvで環境を管理する時に何を書くべき?
ここからが本題です。
実際にpyproject.tomlに何を書くべきかについて解説していきます!
「設定項目が多すぎて何から書けばいいかわからない!」
という人のために、重要度順に整理しました。
まずは【重要度:★★★】だけ押さえれば、今日からuvをpyproject.tomlを使って管理できます!
uvの使い方は次の記事を読んでみてください。
参考:Pythonパッケージ管理 [uv] 完全入門
【重要度:★★★】まずはこれを書いておけば大丈夫
プロジェクトの基本情報と、アプリを動かすのに必要なライブラリです。
[project]
name = "my-app" # プロジェクト名
version = "0.1.0" # バージョン(最初はこれでOK)
requires-python = ">=3.11" # 重要!uvがこのバージョンのPythonを自動で用意します
dependencies = [ # 実行に必要なライブラリ(uv addで自動追記されます)
"requests>=2.31.0",
"pandas",
]
[dependency-groups] # 開発時だけ使うツール
dev = [ # uv add --dev でここに入ります
"ruff", # コード整形・チェック用
]
test = [ # テスト用
"pytest>=8.0",
"pytest-cov",
"pytest-asyncio",
"httpx"
]
docs = [ # ドキュメント生成
"mkdocs-material",
"mkdocstrings[python]"
]
補足
pyproject.tomlにグループを定義したら、
状況に合わせて以下のようにコマンドを使い分けます。
- 普段の開発(コーディング)
「コードを書いて、Ruffで綺麗にして、動作確認する」という普段の作業では、devグループを使います。
uv sync --group dev
これで「本番用(dependencies) + 開発用(dev)」が揃った環境ができあがります。
- テストを実行するとき(CI、出荷前)
「開発ツールはいらないから、純粋にテストに必要なものだけを入れたい」という時はこうです。
uv sync --group test --no-dev
テスト環境を作るときは--group testを追加しつつ、
デフォルトのdev環境を除外(--no-dev)すると環境がきれいになります。
pip installはどんどんライブラリが溜まっていきますが、
uv syncはtomlで定義した環境をそのまま同期(sync)します!
つまり必要ないライブラリは自動で削除する仕組みになっています。
いろんなライブラリを入れすぎて、環境を汚してしまうこともありません!
※ 意図せず削除されないよう、使うライブラリは必ずpyproject.tomlに記載しておきましょう。
【重要度:★★☆】チーム開発・公開をするときは入れておきたい
複数人で開発したり、GitHubで公開したりするときに役立つ設定です。
[project]
description = "便利なツールです"
readme = "README.md" # ファイル名を指定すると自動で説明文として認識されます
license = { text = "MIT" } # ライセンス(file = "LICENSE" と書くことも可能)
authors = [ { name = "YourName", email = "you@example.com" } ]
[project.scripts] # 「自作コマンド」の登録
my-tool = "my_app.main:app" # uv run my-tool と打つだけで実行できるようになります!
[tool.ruff] # コードを綺麗にするルール
line-length = 88 # formatコマンドによる自動整形で使われる
select = ["E", "F", "I"] # チェックするルールの種類(エラー、インポート順など)
ignore = ["E501"] # 行長のlintエラーはformatに任せて無視する
[tool.ruff.format]
quote-style = "double"
indent-style = "space"
skip-magic-trailing-comma = false
[tool.pytest.ini_options] # テストの実行ルール
testpaths = ["tests"] # テストファイルが入っているフォルダを指定
補足
my-tool = "my_app.main:app"の意味
-
my-tool: 付けたいコマンド名。 -
"my_app.main:app": 「my_appパッケージの中の、main.pyにある、app関数(またはオブジェクト)を動かしてね」という意味です。 -
uv syncで環境を構築した後、ターミナルでuv run my-toolと打つだけで、プログラムが起動します。 - プロジェクトの定型作業などをシンプルなコマンドでまとめることができます。
Ruffを使いたいとき
- Ruffは、コードの書き間違いを指摘したり、自動で整形したりしてくれるツールです。
- 実行の仕方
- チェックだけしたいとき:
uv run ruff check . - 自動で直してほしいとき:
uv run ruff check --fix . - インデントなどを整えるとき:
uv run ruff format .
- チェックだけしたいとき:
pytestを使いたいとき
- pytestは、書いたコードが正しく動くか自動で確認するツールです。
- 実行の仕方
- ターミナルで
uv run pytestと打つだけ
- ターミナルで
→ uv runを頭につければ、必ずpyproject.tomlの設定が反映された正しい環境で検証することができます!
【重要度:★☆☆】こだわり&困った時の個別設定
特定の環境や、特殊なライブラリを使いたい時のための設定です。
[tool.uv.sources] # 「ライブラリの取得先」をカスタマイズ
# PyPIにない、GitHubの最新版を直接使いたいとき
awesome-lib = { git = "https://github.com/user/awesome-lib", branch = "main" }
# 自分のPCにある別のフォルダのライブラリを使いたいとき
local-tool = { path = "../local-tool", editable = true }
[[tool.uv.index]]
name = "pytorch-cu121"
url = "https://download.pytorch.org/whl/cu121"
explicit = true # sources で明示指定したパッケージだけに適用
補足
[tool.uv.sources] の柔軟さ
-
公式の「PyPI」に登録されていないコードを使いたいときに大活躍します。
- そのバージョンのバイナリが用意されていない場合も有効です。
- GitHubから直接、「あのライブラリのバグが修正された最新版を使いたいけど、まだリリースされていない!」というとき、修正済みのブランチを直接指定してインストールできます。
-
ローカルのフォルダから自分で作っている別のライブラリをテストしたいときに便利です。
-
editable = trueにしておくことで、元のコードを書き換えるとuv側の環境にも反映されます。
-
[[tool.uv.index]] の使いどころ
- PyTorchなどの巨大なライブラリや、社内リポジトリを使うときに設定します。
-
explicit = true意味:- 「ふだんは標準の場所(PyPI)を見るけど、指定したライブラリ(PyTorchなど)のときだけ、この特別なURLを見に行ってね!」という合図です。
- これを設定しないと、uvが「どこから落とせばいいの?」と迷ってしまい、インストールに失敗したり、CPU版が入ってしまったりするトラブルが起きます。
-
まとめ
本記事では、tomlファイルの概要とuvでPython環境を作る時に必要なpyproject.tomlの書き方をまとめてきました。
なんだかんだ書きましたが、次のテンプレにプラスして必要なものを追加すればなんとかなると思います。
[project]
name = "my-project"
version = "0.1.0"
description = "プロジェクトの簡単な説明をここに書く"
readme = "README.md"
requires-python = ">=3.12"
dependencies = [
"requests", # よく使うライブラリをここに追加
]
[dependency-groups]
dev = [
"ruff", # コードお掃除ツール
"pytest", # テストツール
"ipython",# 動作確認用
]
[tool.ruff]
line-length = 88
select = ["E", "F", "I"] # 基本的なエラーとインポート順チェック
[tool.pytest.ini_options]
testpaths = ["tests"]
まだまだ、pipとrequirements.txtで環境管理してるよ〜という方も多いと思いますが、
いざ違う形式を使うとなると戸惑うものです。
使いはじめは慣れが必要ですが、柔軟性や効率を考えると
uvでpyproject.tomlを使ってPython環境を管理するのは、やはり便利ですね。
今後のPython開発において、有力な選択肢になってくると思います。