Pythonプロジェクトの依存関係を管理するrequirements.txtファイルを自動生成する方法を解説します。pip freezeとpipreqsの使い分けから、モダンなパッケージ管理ツールまで紹介します。
requirements.txt生成ツールの比較
| ツール | 対象 | 長所 | 短所 |
|---|---|---|---|
pip freeze | 環境内全パッケージ | 確実に環境を再現 | 不要なパッケージも含む |
pipreqs | 使用中のパッケージのみ | 最小限の依存関係 | 動的インポートを見逃す |
pip-tools | 依存関係ツリー | ロック機能付き | 追加学習が必要 |
poetry | プロジェクト全体 | モダンな管理 | 設定ファイルが異なる |
pip freeze の使い方
基本的な使用方法
# 環境内のすべてのパッケージをリストアップ
pip freeze
# requirements.txt に保存
pip freeze > requirements.txt
# 出力例
# certifi==2024.2.2
# charset-normalizer==3.3.2
# numpy==1.26.4
# pandas==2.2.1
# requests==2.31.0
requirements.txt からインストール
# 依存関係を一括インストール
pip install -r requirements.txt
# 特定のファイルからインストール
pip install -r requirements-dev.txt
pip freeze の問題点
# 問題: 環境内のすべてのパッケージが含まれる
pip freeze > requirements.txt
# 結果: 100個以上のパッケージがリストされることも
# 問題: 開発用パッケージも混在
# pytest, black, flake8 などが本番用ファイルに含まれてしまう
# 問題: 仮想環境を使用していない場合
# システム全体のパッケージが記録される
ベストプラクティス: 仮想環境と組み合わせる
# 仮想環境を作成
python -m venv venv
# 仮想環境を有効化
# Windows
venv\Scripts\activate
# macOS/Linux
source venv/bin/activate
# 必要なパッケージのみをインストール
pip install requests pandas numpy
# クリーンなrequirements.txtを生成
pip freeze > requirements.txt
pipreqs の使い方
pipreqsは、プロジェクトのソースコードを分析し、実際にインポートされているパッケージのみをリストアップします。
インストールと基本使用
# pipreqs をインストール
pip install pipreqs
# プロジェクトディレクトリでrequirements.txtを生成
pipreqs /path/to/project
# カレントディレクトリの場合
pipreqs .
# 既存のファイルを上書き
pipreqs . --force
# エンコーディングを指定(Windows向け)
pipreqs . --encoding=utf-8
pipreqs のオプション
# 差分のみを表示(ファイルは作成しない)
pipreqs . --diff requirements.txt
# 標準出力に表示
pipreqs . --print
# 特定のディレクトリを除外
pipreqs . --ignore tests,docs,venv
# 出力ファイル名を指定
pipreqs . --savepath requirements-prod.txt
# デバッグモード
pipreqs . --debug
pipreqs の仕組み
# pipreqs はソースコードの import 文を解析
# 以下のようなインポートを検出
import requests # requests パッケージ
import pandas as pd # pandas パッケージ
from flask import Flask # flask パッケージ
from sklearn.model_selection import train_test_split # scikit-learn
# 標準ライブラリは除外される
import os
import sys
import json
pipreqs の注意点
# 動的インポートは検出されない
module_name = "requests"
module = __import__(module_name) # 検出されない
# 条件付きインポートは検出される可能性がある
try:
import optional_package # 検出される
except ImportError:
pass
# requirements.txt の内容を確認し、必要に応じて手動で追加
pip-tools の使い方
pip-toolsは、依存関係を明確に管理し、ロックファイルを生成できます。
インストールと基本使用
# pip-tools をインストール
pip install pip-tools
# requirements.in を作成(直接依存のみ)
echo "requests" > requirements.in
echo "pandas" >> requirements.in
echo "flask" >> requirements.in
# requirements.txt を生成(依存関係も含む)
pip-compile requirements.in
# 依存関係を同期(環境に反映)
pip-sync requirements.txt
requirements.in と requirements.txt
# requirements.in(手動で管理)
# 直接依存するパッケージのみを記述
requests>=2.28.0
pandas~=2.0
flask
# 開発用依存関係は別ファイルに
# requirements-dev.in
-r requirements.in
pytest
black
flake8
# requirements.txt を生成
pip-compile requirements.in -o requirements.txt
# 開発用も生成
pip-compile requirements-dev.in -o requirements-dev.txt
# アップグレード可能なパッケージを更新
pip-compile --upgrade requirements.in
依存関係の分離
環境別の requirements ファイル
project/
├── requirements/
│ ├── base.txt # 共通の依存関係
│ ├── production.txt # 本番環境用
│ ├── development.txt # 開発環境用
│ └── test.txt # テスト環境用
# requirements/base.txt
requests==2.31.0
pandas==2.2.1
flask==3.0.2
# requirements/production.txt
-r base.txt
gunicorn==21.2.0
psycopg2-binary==2.9.9
# requirements/development.txt
-r base.txt
pytest==8.0.2
black==24.2.0
flake8==7.0.0
ipython==8.22.1
# requirements/test.txt
-r base.txt
pytest==8.0.2
pytest-cov==4.1.0
factory-boy==3.3.0
# 本番環境
pip install -r requirements/production.txt
# 開発環境
pip install -r requirements/development.txt
モダンな代替ツール
Poetry
# Poetry をインストール
pip install poetry
# プロジェクトを初期化
poetry init
# パッケージを追加
poetry add requests pandas flask
# 開発用パッケージを追加
poetry add --group dev pytest black flake8
# requirements.txt をエクスポート
poetry export -f requirements.txt --output requirements.txt
# 開発用も含めてエクスポート
poetry export -f requirements.txt --with dev --output requirements-dev.txt
pyproject.toml(Poetry)
[tool.poetry]
name = "my-project"
version = "0.1.0"
description = "My Python project"
[tool.poetry.dependencies]
python = "^3.10"
requests = "^2.31.0"
pandas = "^2.2.1"
flask = "^3.0.2"
[tool.poetry.group.dev.dependencies]
pytest = "^8.0.2"
black = "^24.2.0"
flake8 = "^7.0.0"
uv(高速な新しいツール)
# uv をインストール
pip install uv
# 依存関係をインストール
uv pip install -r requirements.txt
# pip freeze 相当
uv pip freeze > requirements.txt
# pip-compile 相当
uv pip compile requirements.in -o requirements.txt
実践的なスクリプト
requirements.txt 生成スクリプト
#!/usr/bin/env python3
"""requirements.txt を生成するユーティリティスクリプト"""
import subprocess
import sys
from pathlib import Path
def run_pip_freeze(output_file: str = "requirements.txt"):
"""pip freeze の結果を保存"""
result = subprocess.run(
[sys.executable, "-m", "pip", "freeze"],
capture_output=True,
text=True
)
Path(output_file).write_text(result.stdout)
print(f"Created {output_file} with {len(result.stdout.splitlines())} packages")
def run_pipreqs(project_path: str = ".", output_file: str = "requirements.txt"):
"""pipreqs を使用して依存関係を生成"""
try:
subprocess.run(
["pipreqs", project_path, "--force", "--savepath", output_file],
check=True
)
print(f"Created {output_file} using pipreqs")
except subprocess.CalledProcessError as e:
print(f"Error running pipreqs: {e}")
except FileNotFoundError:
print("pipreqs not found. Install with: pip install pipreqs")
def compare_requirements(file1: str, file2: str):
"""2つのrequirements.txtを比較"""
packages1 = set(Path(file1).read_text().splitlines())
packages2 = set(Path(file2).read_text().splitlines())
only_in_1 = packages1 - packages2
only_in_2 = packages2 - packages1
if only_in_1:
print(f"Only in {file1}:")
for pkg in sorted(only_in_1):
print(f" - {pkg}")
if only_in_2:
print(f"Only in {file2}:")
for pkg in sorted(only_in_2):
print(f" + {pkg}")
if __name__ == "__main__":
# pip freeze で生成
run_pip_freeze("requirements-freeze.txt")
# pipreqs で生成
run_pipreqs(".", "requirements-pipreqs.txt")
# 比較
compare_requirements("requirements-freeze.txt", "requirements-pipreqs.txt")
バージョン指定のベストプラクティス
# requirements.txt のバージョン指定方法
# 完全一致(再現性重視)
requests==2.31.0
# 互換性のあるバージョン(パッチバージョンは許容)
requests~=2.31.0 # >=2.31.0, <2.32.0
# 最小バージョン
requests>=2.28.0
# バージョン範囲
requests>=2.28.0,<3.0.0
# 除外バージョン
requests>=2.28.0,!=2.29.0
# バージョン指定なし(非推奨)
# requests
まとめ
| ツール | 使用場面 |
|---|---|
pip freeze | 環境の完全な再現が必要な場合 |
pipreqs | プロジェクトで使用しているパッケージのみが必要な場合 |
pip-tools | 依存関係のロックと管理が必要な場合 |
poetry | モダンなプロジェクト管理が必要な場合 |
推奨されるワークフロー:
- 仮想環境を使用する
- 本番用と開発用で依存関係を分離する
- バージョンを明示的に指定する
- 定期的に依存関係を更新する