Pythonでインストール済みパッケージ一覧を取得する方法【完全ガイド】
Pythonで開発をしていると、現在インストールされているパッケージを確認したい場面がよくあります。「どのパッケージがインストールされているか分からない」「バージョンを確認したい」「requirements.txtを作成したい」といった場合に役立つ方法を、具体的なコマンド例とともに詳しく解説します。
目次
- パッケージ一覧を取得する理由
- pip listコマンドの基本的な使い方
- pip freezeコマンドの活用法
- パッケージ情報の詳細表示
- Pythonスクリプトでパッケージ一覧を取得
- 仮想環境でのパッケージ管理
- パッケージの検索とフィルタリング
- 出力形式のカスタマイズ
- パッケージの依存関係確認
- トラブルシューティング
パッケージ一覧を取得する理由
なぜパッケージ一覧が必要なのか
- 環境の確認: 現在の開発環境の状態を把握
- requirements.txt作成: プロジェクトの依存関係を記録
- 環境の複製: 他の環境で同じパッケージ構成を再現
- デバッグ: パッケージの競合や問題の特定
- セキュリティ監査: 古いパッケージや脆弱性のチェック
- 環境の整理: 不要なパッケージの特定と削除
よくある使用場面
# 新しいプロジェクトの開始時
pip list
# 本番環境へのデプロイ前
pip freeze > requirements.txt
# 開発環境の共有時
pip list --format=freeze
# パッケージの競合調査時
pip show package_name
pip listコマンドの基本的な使い方
基本的なコマンド
# インストール済みパッケージの一覧表示
pip list
# Python 3を明示的に指定
pip3 list
# 特定の仮想環境で実行
source venv/bin/activate
pip list
基本的な出力例:
Package Version
---------- -------
certifi 2023.7.22
numpy 1.24.3
pandas 2.0.3
pip 23.3.1
requests 2.31.0
setuptools 68.2.2
よく使用されるオプション
# アウトデートなパッケージのみ表示
pip list --outdated
# ローカルでインストールしたパッケージのみ表示
pip list --local
# ユーザーディレクトリにインストールしたパッケージのみ
pip list --user
# 最新でないパッケージの詳細情報
pip list --outdated --verbose
# 特定の形式で出力
pip list --format=columns
pip list --format=freeze
pip list --format=json
出力形式の比較
# デフォルト形式(columns)
pip list
# Package Version
# ---------- -------
# requests 2.31.0
# pandas 2.0.3
# freeze形式
pip list --format=freeze
# requests==2.31.0
# pandas==2.0.3
# JSON形式
pip list --format=json
# [{"name": "requests", "version": "2.31.0"}, {"name": "pandas", "version": "2.0.3"}]
pip freezeコマンドの活用法
pip freezeの基本使用法
# requirements.txt形式で出力
pip freeze
# ファイルに保存
pip freeze > requirements.txt
# 特定のパッケージのみ
pip freeze | grep requests
# アルファベット順にソート
pip freeze | sort
pip listとpip freezeの違い
項目 | pip list | pip freeze |
---|---|---|
出力形式 | 表形式(デフォルト) | パッケージ==バージョン |
用途 | 確認・表示 | requirements.txt生成 |
依存関係 | すべて表示 | トップレベルのみ(オプション) |
カスタマイズ | 豊富なオプション | シンプル |
実用的な使用例
# 現在の環境をrequirements.txtに保存
pip freeze > requirements.txt
# 既存のrequirements.txtと比較
pip freeze > current_packages.txt
diff requirements.txt current_packages.txt
# 特定のパッケージのバージョンを確認
pip freeze | grep -i django
# Django==4.2.7
# パッケージ数をカウント
pip freeze | wc -l
# 42
# 特定の文字列を含むパッケージを検索
pip freeze | grep -E "(test|dev)"
# pytest==7.4.3
# pytest-django==4.7.0
パッケージ情報の詳細表示
pip showコマンドの使用法
# 特定のパッケージの詳細情報
pip show requests
# 複数パッケージの情報を一度に表示
pip show requests pandas numpy
# 依存関係も含めて表示
pip show --verbose requests
# ファイル一覧も表示
pip show --files requests
出力例:
Name: requests
Version: 2.31.0
Summary: Python HTTP for Humans.
Home-page: https://requests.readthedocs.io
Author: Kenneth Reitz
Author-email: me@kennethreitz.org
License: Apache 2.0
Location: /usr/local/lib/python3.11/site-packages
Requires: certifi, charset-normalizer, idna, urllib3
Required-by:
パッケージ情報の活用方法
# インストール場所の確認
pip show requests | grep Location
# 依存関係の確認
pip show requests | grep Requires
# ライセンス情報の確認
pip show requests | grep License
# 複数パッケージのライセンス一覧
for package in $(pip freeze | cut -d= -f1); do
echo -n "$package: "
pip show $package | grep License | cut -d: -f2
done
Pythonスクリプトでパッケージ一覧を取得
pkgライブラリを使用した方法
import pkg_resources
def get_installed_packages():
"""インストール済みパッケージの一覧を取得"""
installed_packages = []
for dist in pkg_resources.working_set:
installed_packages.append({
'name': dist.project_name,
'version': dist.version,
'location': dist.location
})
return sorted(installed_packages, key=lambda x: x['name'])
# 使用例
packages = get_installed_packages()
for package in packages:
print(f"{package['name']}=={package['version']}")
importlib.metadataを使用した方法(Python 3.8+)
from importlib import metadata
import sys
def get_package_info():
"""パッケージ情報を詳細に取得"""
packages = []
for dist in metadata.distributions():
try:
package_info = {
'name': dist.metadata['Name'],
'version': dist.version,
'summary': dist.metadata.get('Summary', ''),
'author': dist.metadata.get('Author', ''),
'license': dist.metadata.get('License', ''),
'requires': dist.metadata.get('Requires-Dist', [])
}
packages.append(package_info)
except Exception as e:
print(f"Error processing package: {e}", file=sys.stderr)
return sorted(packages, key=lambda x: x['name'])
# 使用例
packages = get_package_info()
for package in packages[:5]: # 最初の5個のみ表示
print(f"Name: {package['name']}")
print(f"Version: {package['version']}")
print(f"Summary: {package['summary']}")
print("-" * 40)
subprocessを使用してpipコマンドを実行
import subprocess
import json
def get_packages_via_pip():
"""pipコマンドを使ってパッケージ一覧を取得"""
try:
# pip list --format=json を実行
result = subprocess.run(
['pip', 'list', '--format=json'],
capture_output=True,
text=True,
check=True
)
packages = json.loads(result.stdout)
return packages
except subprocess.CalledProcessError as e:
print(f"Error executing pip command: {e}")
return []
except json.JSONDecodeError as e:
print(f"Error parsing JSON output: {e}")
return []
# 使用例
packages = get_packages_via_pip()
print(f"Total packages installed: {len(packages)}")
for package in packages[:10]: # 最初の10個のみ表示
print(f"{package['name']} ({package['version']})")
カスタム関数の作成
import pkg_resources
from datetime import datetime
import os
import sys
class PackageManager:
"""パッケージ管理のためのユーティリティクラス"""
@staticmethod
def get_all_packages():
"""すべてのパッケージ情報を取得"""
packages = []
for dist in pkg_resources.working_set:
packages.append({
'name': dist.project_name,
'version': dist.version,
'location': dist.location,
'requires': [str(req) for req in dist.requires()]
})
return sorted(packages, key=lambda x: x['name'])
@staticmethod
def export_to_requirements(filename='requirements.txt'):
"""requirements.txtファイルを生成"""
packages = PackageManager.get_all_packages()
with open(filename, 'w') as f:
f.write(f"# Generated on {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n")
f.write(f"# Python {sys.version.split()[0]}\n\n")
for package in packages:
f.write(f"{package['name']}=={package['version']}\n")
print(f"Requirements exported to {filename}")
@staticmethod
def find_package(search_term):
"""パッケージを検索"""
packages = PackageManager.get_all_packages()
results = []
for package in packages:
if search_term.lower() in package['name'].lower():
results.append(package)
return results
@staticmethod
def get_package_size_estimate():
"""パッケージのサイズを推定"""
packages = PackageManager.get_all_packages()
size_info = []
for package in packages:
location = package['location']
if os.path.exists(location):
# ディレクトリサイズの計算(簡易版)
total_size = 0
package_dir = os.path.join(location, package['name'].replace('-', '_'))
if os.path.exists(package_dir):
for dirpath, dirnames, filenames in os.walk(package_dir):
for filename in filenames:
filepath = os.path.join(dirpath, filename)
try:
total_size += os.path.getsize(filepath)
except (OSError, IOError):
pass
size_info.append({
'name': package['name'],
'version': package['version'],
'size_mb': round(total_size / (1024 * 1024), 2)
})
return sorted(size_info, key=lambda x: x['size_mb'], reverse=True)
# 使用例
if __name__ == "__main__":
# すべてのパッケージを表示
packages = PackageManager.get_all_packages()
print(f"Total packages: {len(packages)}\n")
# 最初の5個を表示
for package in packages[:5]:
print(f"Name: {package['name']}")
print(f"Version: {package['version']}")
print(f"Location: {package['location']}")
print(f"Requires: {', '.join(package['requires'])}")
print("-" * 50)
# requirements.txtを生成
PackageManager.export_to_requirements()
# 特定のパッケージを検索
django_packages = PackageManager.find_package('django')
print(f"\nDjango related packages: {len(django_packages)}")
for package in django_packages:
print(f" {package['name']} ({package['version']})")
仮想環境でのパッケージ管理
venv環境でのパッケージ確認
# 仮想環境を作成
python -m venv myproject_env
# 仮想環境を有効化(Linux/macOS)
source myproject_env/bin/activate
# 仮想環境を有効化(Windows)
myproject_env\Scripts\activate
# 仮想環境のパッケージ一覧
pip list
# グローバル環境との比較
pip list --local
# 仮想環境の情報を保存
pip freeze > myproject_requirements.txt
# 仮想環境を無効化
deactivate
conda環境でのパッケージ管理
# conda環境の作成
conda create -n myproject python=3.11
# 環境の有効化
conda activate myproject
# condaでインストールしたパッケージ
conda list
# pipでインストールしたパッケージ
pip list
# 両方の情報を含む環境ファイル
conda env export > environment.yml
# pip専用のrequirements.txt
pip freeze > requirements.txt
# 環境の無効化
conda deactivate
pipenv環境でのパッケージ管理
# pipenv環境でシェルを開始
pipenv shell
# インストール済みパッケージ
pipenv graph
# Pipfileの内容確認
cat Pipfile
# requirements.txt形式で出力
pipenv requirements > requirements.txt
# 開発用パッケージも含める
pipenv requirements --dev > requirements-dev.txt
複数環境の比較
import subprocess
import json
from pathlib import Path
def compare_environments():
"""複数の仮想環境のパッケージを比較"""
environments = {
'global': None,
'venv1': 'path/to/venv1',
'venv2': 'path/to/venv2'
}
env_packages = {}
for env_name, env_path in environments.items():
if env_path:
# 仮想環境のpipを使用
pip_path = Path(env_path) / 'bin' / 'pip' # Linux/macOS
if not pip_path.exists():
pip_path = Path(env_path) / 'Scripts' / 'pip.exe' # Windows
else:
# グローバル環境のpip
pip_path = 'pip'
try:
result = subprocess.run(
[str(pip_path), 'list', '--format=json'],
capture_output=True,
text=True,
check=True
)
packages = json.loads(result.stdout)
env_packages[env_name] = {pkg['name']: pkg['version'] for pkg in packages}
except Exception as e:
print(f"Error getting packages for {env_name}: {e}")
env_packages[env_name] = {}
return env_packages
# 使用例
env_comparison = compare_environments()
for env_name, packages in env_comparison.items():
print(f"\n{env_name}: {len(packages)} packages")
for name, version in list(packages.items())[:5]: # 最初の5個のみ
print(f" {name}: {version}")
パッケージの検索とフィルタリング
コマンドラインでの検索
# 特定の文字列を含むパッケージを検索
pip list | grep -i django
# 複数の条件で検索
pip list | grep -E "(test|dev|debug)"
# バージョン番号でフィルタリング
pip list | grep -E "\b2\." # バージョン2.x系のパッケージ
# アルファベット順でソート
pip list --format=freeze | sort
# パッケージ数のカウント
pip list | wc -l
# 特定のパッケージのバージョンのみ表示
pip show requests | grep Version
高度な検索とフィルタリング
# アップデート可能なパッケージの詳細
pip list --outdated --format=columns
# ローカルにインストールしたパッケージのみ
pip list --local --format=freeze
# 特定の場所にインストールされたパッケージ
pip list --verbose | grep "/usr/local"
# セキュリティ関連パッケージの検索
pip list | grep -i -E "(security|crypto|ssl|auth)"
# 開発ツール関連パッケージの検索
pip list | grep -i -E "(test|lint|format|debug)"
Pythonスクリプトでの高度な検索
import pkg_resources
import re
from collections import defaultdict
class PackageSearcher:
"""パッケージ検索のためのユーティリティクラス"""
def __init__(self):
self.packages = list(pkg_resources.working_set)
def search_by_name(self, pattern):
"""名前で検索(正規表現対応)"""
regex = re.compile(pattern, re.IGNORECASE)
results = []
for package in self.packages:
if regex.search(package.project_name):
results.append({
'name': package.project_name,
'version': package.version,
'location': package.location
})
return results
def search_by_version(self, version_pattern):
"""バージョンで検索"""
regex = re.compile(version_pattern)
results = []
for package in self.packages:
if regex.search(package.version):
results.append({
'name': package.project_name,
'version': package.version
})
return results
def get_packages_by_location(self):
"""インストール場所でグループ化"""
location_groups = defaultdict(list)
for package in self.packages:
location_groups[package.location].append({
'name': package.project_name,
'version': package.version
})
return dict(location_groups)
def find_development_packages(self):
"""開発関連パッケージを検索"""
dev_keywords = ['test', 'lint', 'format', 'debug', 'dev', 'mock', 'coverage']
dev_packages = []
for package in self.packages:
package_name = package.project_name.lower()
if any(keyword in package_name for keyword in dev_keywords):
dev_packages.append({
'name': package.project_name,
'version': package.version,
'category': self._categorize_dev_package(package_name)
})
return dev_packages
def _categorize_dev_package(self, package_name):
"""開発パッケージのカテゴリ分け"""
if 'test' in package_name:
return 'testing'
elif any(word in package_name for word in ['lint', 'flake', 'pylint']):
return 'linting'
elif any(word in package_name for word in ['format', 'black', 'autopep']):
return 'formatting'
elif 'debug' in package_name:
return 'debugging'
elif any(word in package_name for word in ['mock', 'fake']):
return 'mocking'
elif 'coverage' in package_name:
return 'coverage'
else:
return 'other'
# 使用例
searcher = PackageSearcher()
# Django関連パッケージを検索
django_packages = searcher.search_by_name(r'django')
print("Django related packages:")
for package in django_packages:
print(f" {package['name']} ({package['version']})")
# バージョン2.x系のパッケージを検索
v2_packages = searcher.search_by_version(r'^2\.')
print(f"\nVersion 2.x packages: {len(v2_packages)}")
# 開発パッケージを検索
dev_packages = searcher.find_development_packages()
print(f"\nDevelopment packages: {len(dev_packages)}")
dev_by_category = defaultdict(list)
for package in dev_packages:
dev_by_category[package['category']].append(package['name'])
for category, packages in dev_by_category.items():
print(f" {category}: {', '.join(packages)}")
出力形式のカスタマイズ
表形式の出力
# デフォルトのカラム形式
pip list --format=columns
# 幅を調整した表示
pip list --format=columns | column -t
# 特定の列のみ表示
pip list --format=freeze | cut -d'=' -f1 # パッケージ名のみ
pip list --format=freeze | cut -d'=' -f2 # バージョンのみ
JSON形式での出力と加工
# JSON形式で出力
pip list --format=json
# jqコマンドを使った加工(jqがインストールされている場合)
pip list --format=json | jq '.[] | select(.name | contains("django"))'
pip list --format=json | jq 'sort_by(.name)'
pip list --format=json | jq 'length' # パッケージ数
カスタム形式での出力
import subprocess
import json
from tabulate import tabulate # pip install tabulate
def format_package_list(format_type='table'):
"""パッケージリストを様々な形式で出力"""
# pipからパッケージ情報を取得
result = subprocess.run(
['pip', 'list', '--format=json'],
capture_output=True,
text=True,
check=True
)
packages = json.loads(result.stdout)
if format_type == 'table':
# テーブル形式
headers = ['Package', 'Version']
data = [[pkg['name'], pkg['version']] for pkg in packages]
return tabulate(data, headers=headers, tablefmt='grid')
elif format_type == 'markdown':
# Markdown形式
headers = ['Package', 'Version']
data = [[pkg['name'], pkg['version']] for pkg in packages]
return tabulate(data, headers=headers, tablefmt='pipe')
elif format_type == 'csv':
# CSV形式
import csv
import io
output = io.StringIO()
writer = csv.writer(output)
writer.writerow(['Package', 'Version'])
for pkg in packages:
writer.writerow([pkg['name'], pkg['version']])
return output.getvalue()
elif format_type == 'html':
# HTML形式
headers = ['Package', 'Version']
data = [[pkg['name'], pkg['version']] for pkg in packages]
return tabulate(data, headers=headers, tablefmt='html')
else:
return "Unsupported format"
# 使用例
print("=== Table Format ===")
print(format_package_list('table'))
print("\n=== Markdown Format ===")
print(format_package_list('markdown'))
print("\n=== CSV Format ===")
print(format_package_list('csv'))
レポート形式での出力
from datetime import datetime
import platform
import sys
import pkg_resources
def generate_package_report():
"""詳細なパッケージレポートを生成"""
packages = list(pkg_resources.working_set)
packages.sort(key=lambda x: x.project_name.lower())
report = []
report.append("=" * 60)
report.append("PYTHON PACKAGE REPORT")
report.append("=" * 60)
report.append(f"Generated: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
report.append(f"Python Version: {sys.version}")
report.append(f"Platform: {platform.platform()}")
report.append(f"Total Packages: {len(packages)}")
report.append("")
# カテゴライズ
categories = {
'Web Frameworks': ['django', 'flask', 'fastapi', 'tornado'],
'Data Science': ['pandas', 'numpy', 'scipy', 'scikit-learn', 'matplotlib'],
'Testing': ['pytest', 'unittest2', 'mock', 'nose'],
'Development Tools': ['pip', 'setuptools', 'wheel', 'twine'],
'HTTP Libraries': ['requests', 'urllib3', 'httpx']
}
categorized = {cat: [] for cat in categories}
uncategorized = []
for package in packages:
package_name = package.project_name.lower()
found_category = False
for category, keywords in categories.items():
if any(keyword in package_name for keyword in keywords):
categorized[category].append(package)
found_category = True
break
if not found_category:
uncategorized.append(package)
# カテゴリ別に出力
for category, category_packages in categorized.items():
if category_packages:
report.append(f"{category} ({len(category_packages)} packages):")
report.append("-" * 40)
for package in sorted(category_packages, key=lambda x: x.project_name):
report.append(f" {package.project_name:<20} {package.version}")
report.append("")
# その他のパッケージ
if uncategorized:
report.append(f"Other Packages ({len(uncategorized)} packages):")
report.append("-" * 40)
for package in uncategorized[:10]: # 最初の10個のみ
report.append(f" {package.project_name:<20} {package.version}")
if len(uncategorized) > 10:
report.append(f" ... and {len(uncategorized) - 10} more")
return "\n".join(report)
# レポート生成と保存
report = generate_package_report()
print(report)
# ファイルに保存
with open('package_report.txt', 'w', encoding='utf-8') as f:
f.write(report)
print("\nReport saved to package_report.txt")
パッケージの依存関係確認
pip showによる依存関係確認
# 特定のパッケージの依存関係
pip show requests
# 依存関係の詳細表示
pip show --verbose requests
# 複数パッケージの依存関係
pip show django djangorestframework
# 依存関係のみ抽出
pip show requests | grep Requires
pip show requests | grep Required-by
pipdeptreeを使った可視化
# pipdeptreeのインストール
pip install pipdeptree
# 依存関係ツリーの表示
pipdeptree
# 特定のパッケージのみ
pipdeptree -p requests
# JSON形式で出力
pipdeptree --json
# 逆依存関係を表示
pipdeptree --reverse
# 警告のみ表示
pipdeptree --warn silence
# GraphViz形式で出力(図式化用)
pipdeptree --graph-output dot > dependencies.dot
pipdeptreeの出力例:
requests==2.31.0
├── certifi [required: >=2017.4.17, installed: 2023.7.22]
├── charset-normalizer [required: >=2,<4, installed: 3.3.2]
├── idna [required: >=2.5,<4, installed: 3.4]
└── urllib3 [required: >=1.21.1,<3, installed: 2.0.7]
Pythonスクリプトでの依存関係分析
import pkg_resources
from collections import defaultdict, deque
class DependencyAnalyzer:
"""パッケージ依存関係の分析ツール"""
def __init__(self):
self.packages = {pkg.project_name: pkg for pkg in pkg_resources.working_set}
def get_dependencies(self, package_name):
"""特定のパッケージの直接的な依存関係を取得"""
if package_name not in self.packages:
return []
package = self.packages[package_name]
dependencies = []
for requirement in package.requires():
dependencies.append({
'name': requirement.project_name,
'specs': requirement.specs,
'installed_version': self.packages.get(requirement.project_name, {}).version if requirement.project_name in self.packages else None
})
return dependencies
def get_reverse_dependencies(self, package_name):
"""特定のパッケージに依存しているパッケージを取得"""
reverse_deps = []
for pkg_name, package in self.packages.items():
for requirement in package.requires():
if requirement.project_name == package_name:
reverse_deps.append({
'name': pkg_name,
'version': package.version
})
return reverse_deps
def get_dependency_tree(self, package_name, max_depth=3):
"""依存関係ツリーを取得"""
def build_tree(pkg_name, depth=0, visited=None):
if visited is None:
visited = set()
if depth > max_depth or pkg_name in visited:
return {'name': pkg_name, 'children': [], 'circular': pkg_name in visited}
visited.add(pkg_name)
dependencies = self.get_dependencies(pkg_name)
children = []
for dep in dependencies:
child_tree = build_tree(dep['name'], depth + 1, visited.copy())
child_tree['specs'] = dep['specs']
child_tree['installed_version'] = dep['installed_version']
children.append(child_tree)
visited.remove(pkg_name)
return {'name': pkg_name, 'children': children, 'circular': False}
return build_tree(package_name)
def find_circular_dependencies(self):
"""循環依存を検出"""
def has_circular_dependency(pkg_name, path=None):
if path is None:
path = []
if pkg_name in path:
return path + [pkg_name]
new_path = path + [pkg_name]
dependencies = self.get_dependencies(pkg_name)
for dep in dependencies:
result = has_circular_dependency(dep['name'], new_path)
if result:
return result
return None
circular_deps = []
checked = set()
for pkg_name in self.packages:
if pkg_name not in checked:
result = has_circular_dependency(pkg_name)
if result:
circular_deps.append(result)
checked.update(result)
return circular_deps
def get_top_level_packages(self):
"""トップレベルパッケージ(他に依存されていない)を取得"""
all_packages = set(self.packages.keys())
dependencies = set()
for package in self.packages.values():
for req in package.requires():
dependencies.add(req.project_name)
top_level = all_packages - dependencies
return sorted(list(top_level))
def print_dependency_tree(self, package_name, max_depth=3):
"""依存関係ツリーを見やすく出力"""
tree = self.get_dependency_tree(package_name, max_depth)
def print_node(node, indent=0, prefix=""):
name = node['name']
specs = node.get('specs', [])
installed = node.get('installed_version', '')
circular = node.get('circular', False)
specs_str = f" ({','.join([''.join(spec) for spec in specs])})" if specs else ""
installed_str = f" [installed: {installed}]" if installed else ""
circular_str = " [CIRCULAR]" if circular else ""
print(f"{' ' * indent}{prefix}{name}{specs_str}{installed_str}{circular_str}")
children = node.get('children', [])
for i, child in enumerate(children):
is_last = i == len(children) - 1
child_prefix = "└── " if is_last else "├── "
print_node(child, indent + 1, child_prefix)
print_node(tree)
# 使用例
analyzer = DependencyAnalyzer()
# Django の依存関係ツリー
print("=== Django Dependency Tree ===")
if 'Django' in analyzer.packages:
analyzer.print_dependency_tree('Django')
else:
print("Django is not installed")
print("\n=== Top Level Packages ===")
top_level = analyzer.get_top_level_packages()
for package in top_level[:10]: # 最初の10個のみ
print(f" {package}")
print(f"\nTotal top-level packages: {len(top_level)}")
# 循環依存の検出
print("\n=== Circular Dependencies ===")
circular = analyzer.find_circular_dependencies()
if circular:
for cycle in circular:
print(f" {' -> '.join(cycle)}")
else:
print(" No circular dependencies found")
詳細な依存関係レポート
import pkg_resources
from collections import defaultdict
import json
class DetailedDependencyReporter:
"""詳細な依存関係レポートを生成"""
def __init__(self):
self.packages = {pkg.project_name: pkg for pkg in pkg_resources.working_set}
def generate_full_report(self):
"""完全な依存関係レポートを生成"""
report = {
'summary': self._get_summary(),
'packages': self._get_package_details(),
'dependency_graph': self._get_dependency_graph(),
'orphaned_packages': self._get_orphaned_packages(),
'most_depended_on': self._get_most_depended_on(),
'license_distribution': self._get_license_distribution()
}
return report
def _get_summary(self):
"""サマリー情報を取得"""
total_packages = len(self.packages)
packages_with_deps = sum(1 for pkg in self.packages.values() if len(list(pkg.requires())) > 0)
total_dependencies = sum(len(list(pkg.requires())) for pkg in self.packages.values())
return {
'total_packages': total_packages,
'packages_with_dependencies': packages_with_deps,
'total_dependency_relationships': total_dependencies,
'average_dependencies_per_package': round(total_dependencies / total_packages, 2) if total_packages > 0 else 0
}
def _get_package_details(self):
"""各パッケージの詳細情報を取得"""
details = {}
for pkg_name, pkg in self.packages.items():
dependencies = []
for req in pkg.requires():
dependencies.append({
'name': req.project_name,
'specs': req.specs,
'installed': req.project_name in self.packages,
'installed_version': self.packages[req.project_name].version if req.project_name in self.packages else None
})
# このパッケージに依存しているパッケージを取得
dependents = []
for other_name, other_pkg in self.packages.items():
for req in other_pkg.requires():
if req.project_name == pkg_name:
dependents.append(other_name)
details[pkg_name] = {
'version': pkg.version,
'location': pkg.location,
'dependencies': dependencies,
'dependents': dependents,
'dependency_count': len(dependencies),
'dependent_count': len(dependents)
}
return details
def _get_dependency_graph(self):
"""依存関係グラフを生成"""
graph = {}
for pkg_name, pkg in self.packages.items():
dependencies = [req.project_name for req in pkg.requires()]
graph[pkg_name] = dependencies
return graph
def _get_orphaned_packages(self):
"""孤立したパッケージ(他に依存されていない)を取得"""
all_packages = set(self.packages.keys())
dependencies = set()
for pkg in self.packages.values():
for req in pkg.requires():
dependencies.add(req.project_name)
orphaned = all_packages - dependencies
return sorted(list(orphaned))
def _get_most_depended_on(self, top_n=10):
"""最も依存されているパッケージを取得"""
dependency_count = defaultdict(int)
for pkg in self.packages.values():
for req in pkg.requires():
if req.project_name in self.packages:
dependency_count[req.project_name] += 1
sorted_deps = sorted(dependency_count.items(), key=lambda x: x[1], reverse=True)
return sorted_deps[:top_n]
def _get_license_distribution(self):
"""ライセンス分布を取得"""
from importlib import metadata
license_count = defaultdict(int)
try:
for dist in metadata.distributions():
license_info = dist.metadata.get('License', 'Unknown')
license_count[license_info] += 1
except ImportError:
# Python < 3.8 の場合
license_count['Unknown'] = len(self.packages)
return dict(license_count)
def export_report(self, filename='dependency_report.json'):
"""レポートをJSONファイルにエクスポート"""
report = self.generate_full_report()
with open(filename, 'w', encoding='utf-8') as f:
json.dump(report, f, indent=2, ensure_ascii=False)
print(f"Dependency report exported to {filename}")
return report
def print_summary(self):
"""サマリーを見やすく出力"""
report = self.generate_full_report()
summary = report['summary']
print("=== DEPENDENCY SUMMARY ===")
print(f"Total packages: {summary['total_packages']}")
print(f"Packages with dependencies: {summary['packages_with_dependencies']}")
print(f"Total dependency relationships: {summary['total_dependency_relationships']}")
print(f"Average dependencies per package: {summary['average_dependencies_per_package']}")
print(f"\n=== TOP 10 MOST DEPENDED ON PACKAGES ===")
for package, count in report['most_depended_on']:
print(f" {package}: {count} packages depend on it")
print(f"\n=== ORPHANED PACKAGES ({len(report['orphaned_packages'])}) ===")
for package in report['orphaned_packages'][:10]:
print(f" {package}")
if len(report['orphaned_packages']) > 10:
print(f" ... and {len(report['orphaned_packages']) - 10} more")
# 使用例
reporter = DetailedDependencyReporter()
reporter.print_summary()
# 詳細レポートをファイルに出力
reporter.export_report()
トラブルシューティング
よくある問題と解決法
1. pip listが実行できない
# エラー例
pip: command not found
# 解決法1: Pythonモジュールとして実行
python -m pip list
# 解決法2: pip3を使用
pip3 list
# 解決法3: パスの確認
which pip
echo $PATH
# 解決法4: pipの再インストール
python -m ensurepip --upgrade
2. 権限エラー
# エラー例
PermissionError: [Errno 13] Permission denied
# 解決法1: 仮想環境を使用
python -m venv venv
source venv/bin/activate
pip list
# 解決法2: ユーザーディレクトリのパッケージのみ表示
pip list --user
# 解決法3: sudoを使用(推奨しない)
sudo pip list
3. パッケージ情報が表示されない
# 問題の診断
pip check # パッケージの整合性確認
pip list --verbose # 詳細情報表示
# キャッシュのクリア
pip cache purge
# pipの更新
python -m pip install --upgrade pip
# パッケージデータベースの修復
python -m pip install --force-reinstall --no-deps pip
4. 仮想環境のパッケージが見えない
# 仮想環境の確認
which python
which pip
# 仮想環境の有効化確認
echo $VIRTUAL_ENV # Linux/macOS
echo $CONDA_DEFAULT_ENV # conda環境
# 正しい pip を使用
python -m pip list
# 仮想環境の再作成
deactivate
rm -rf venv
python -m venv venv
source venv/bin/activate
5. 文字化けエラー
# エラー例
UnicodeDecodeError: 'ascii' codec can't decode
# 解決法1: 環境変数を設定
export PYTHONIOENCODING=utf-8
pip list
# 解決法2: ロケールを設定
export LANG=en_US.UTF-8
export LC_ALL=en_US.UTF-8
pip list
# 解決法3: Pythonスクリプトで処理
python -c "
import sys
import subprocess
result = subprocess.run([sys.executable, '-m', 'pip', 'list'],
capture_output=True, text=True, encoding='utf-8')
print(result.stdout)
"
デバッグ用のスクリプト
import sys
import os
import subprocess
import pkg_resources
import platform
def diagnose_python_environment():
"""Python環境の診断を行う"""
print("=== Python Environment Diagnosis ===")
print(f"Python version: {sys.version}")
print(f"Python executable: {sys.executable}")
print(f"Platform: {platform.platform()}")
print(f"Architecture: {platform.architecture()}")
print(f"\n=== Environment Variables ===")
important_vars = [
'VIRTUAL_ENV', 'CONDA_DEFAULT_ENV', 'PYTHONPATH',
'PYTHONHOME', 'PATH', 'PYTHONIOENCODING'
]
for var in important_vars:
value = os.environ.get(var, 'Not set')
print(f"{var}: {value}")
print(f"\n=== Python Path ===")
for i, path in enumerate(sys.path):
print(f" {i}: {path}")
print(f"\n=== Package Installation Locations ===")
try:
import site
print(f"User site-packages: {site.getusersitepackages()}")
site_packages = site.getsitepackages()
for i, site_pkg in enumerate(site_packages):
print(f"Site-packages {i}: {site_pkg}")
except Exception as e:
print(f"Error getting site information: {e}")
print(f"\n=== pip Information ===")
pip_commands = ['pip', 'pip3', f'{sys.executable} -m pip']
for cmd in pip_commands:
try:
if cmd.startswith(sys.executable):
result = subprocess.run(cmd.split() + ['--version'],
capture_output=True, text=True, timeout=10)
else:
result = subprocess.run([cmd, '--version'],
capture_output=True, text=True, timeout=10)
if result.returncode == 0:
print(f"{cmd}: {result.stdout.strip()}")
else:
print(f"{cmd}: Error - {result.stderr.strip()}")
except Exception as e:
print(f"{cmd}: Not available - {e}")
print(f"\n=== Package Count ===")
try:
packages = list(pkg_resources.working_set)
print(f"Total packages (pkg_resources): {len(packages)}")
# 場所別のカウント
locations = {}
for package in packages:
location = package.location
locations[location] = locations.get(location, 0) + 1
print(f"Packages by location:")
for location, count in sorted(locations.items()):
print(f" {location}: {count} packages")
except Exception as e:
print(f"Error counting packages with pkg_resources: {e}")
# pip list テスト
print(f"\n=== pip list test ===")
try:
result = subprocess.run([sys.executable, '-m', 'pip', 'list'],
capture_output=True, text=True, timeout=30)
if result.returncode == 0:
lines = result.stdout.strip().split('\n')
print(f"pip list output: {len(lines)} lines")
print("First 5 lines:")
for line in lines[:5]:
print(f" {line}")
else:
print(f"pip list failed: {result.stderr}")
except Exception as e:
print(f"Error running pip list: {e}")
# importlib.metadata テスト (Python 3.8+)
print(f"\n=== importlib.metadata test ===")
try:
from importlib import metadata
distributions = list(metadata.distributions())
print(f"Total packages (importlib.metadata): {len(distributions)}")
except ImportError:
print("importlib.metadata not available (Python < 3.8)")
except Exception as e:
print(f"Error with importlib.metadata: {e}")
def fix_common_issues():
"""一般的な問題の自動修復を試行"""
print("=== Attempting to fix common issues ===")
# pipの更新
print("1. Updating pip...")
try:
result = subprocess.run([sys.executable, '-m', 'pip', 'install', '--upgrade', 'pip'],
capture_output=True, text=True, timeout=60)
if result.returncode == 0:
print(" ✓ pip updated successfully")
else:
print(f" ✗ pip update failed: {result.stderr}")
except Exception as e:
print(f" ✗ pip update error: {e}")
# setuptools と wheel の更新
print("2. Updating setuptools and wheel...")
try:
result = subprocess.run([sys.executable, '-m', 'pip', 'install', '--upgrade', 'setuptools', 'wheel'],
capture_output=True, text=True, timeout=60)
if result.returncode == 0:
print(" ✓ setuptools and wheel updated successfully")
else:
print(f" ✗ setuptools/wheel update failed: {result.stderr}")
except Exception as e:
print(f" ✗ setuptools/wheel update error: {e}")
# キャッシュのクリア
print("3. Clearing pip cache...")
try:
result = subprocess.run([sys.executable, '-m', 'pip', 'cache', 'purge'],
capture_output=True, text=True, timeout=30)
if result.returncode == 0:
print(" ✓ pip cache cleared successfully")
else:
print(f" ✗ cache clear failed: {result.stderr}")
except Exception as e:
print(f" ✗ cache clear error: {e}")
# パッケージの整合性チェック
print("4. Checking package integrity...")
try:
result = subprocess.run([sys.executable, '-m', 'pip', 'check'],
capture_output=True, text=True, timeout=30)
if result.returncode == 0:
print(" ✓ No package conflicts found")
else:
print(f" ⚠ Package conflicts detected:\n{result.stdout}")
except Exception as e:
print(f" ✗ integrity check error: {e}")
# 診断実行
if __name__ == "__main__":
diagnose_python_environment()
print("\n" + "="*60 + "\n")
fix_common_issues()
環境の完全リセット
# 仮想環境の完全リセット
deactivate # 仮想環境を無効化
rm -rf venv # 仮想環境ディレクトリを削除
python -m venv venv # 新しい仮想環境を作成
source venv/bin/activate # 有効化
# pipの最新化
python -m pip install --upgrade pip
# requirements.txtから再インストール
pip install -r requirements.txt
# または段階的にインストール
pip install --upgrade pip setuptools wheel
pip install -r requirements.txt --no-cache-dir
パフォーマンス最適化
import time
import subprocess
import json
def benchmark_package_listing_methods():
"""パッケージ一覧取得メソッドのベンチマーク"""
methods = {
'pip_list_json': lambda: subprocess.run(
['pip', 'list', '--format=json'],
capture_output=True, text=True
),
'pip_freeze': lambda: subprocess.run(
['pip', 'freeze'],
capture_output=True, text=True
),
'pkg_resources': lambda: list(pkg_resources.working_set),
}
# Python 3.8+ のみ
try:
from importlib import metadata
methods['importlib_metadata'] = lambda: list(metadata.distributions())
except ImportError:
pass
results = {}
for method_name, method_func in methods.items():
print(f"Testing {method_name}...")
times = []
for i in range(3): # 3回実行して平均を取る
start_time = time.time()
try:
result = method_func()
end_time = time.time()
times.append(end_time - start_time)
except Exception as e:
print(f" Error in {method_name}: {e}")
times.append(float('inf'))
avg_time = sum(times) / len(times)
results[method_name] = {
'average_time': avg_time,
'times': times
}
print(f" Average time: {avg_time:.4f} seconds")
# 結果のソート
sorted_results = sorted(results.items(), key=lambda x: x[1]['average_time'])
print(f"\n=== Performance Ranking ===")
for i, (method, data) in enumerate(sorted_results, 1):
print(f"{i}. {method}: {data['average_time']:.4f} seconds")
return results
# ベンチマーク実行
if __name__ == "__main__":
benchmark_results = benchmark_package_listing_methods()
まとめ
Pythonでインストール済みパッケージの一覧を取得する方法は多岐にわたります。用途に応じて適切な方法を選択することで、効率的なパッケージ管理が可能になります。
重要なポイント
基本コマンドの使い分け:
pip list
: 人間が読みやすい表形式での確認pip freeze
: requirements.txt生成やスクリプト処理pip show
: 個別パッケージの詳細情報確認
仮想環境での管理:
- プロジェクトごとの独立した環境での管理
- 環境間の比較と同期
- 本番環境への安全なデプロイ
自動化とスクリプト処理:
- Pythonスクリプトによる高度な分析と処理
- 依存関係の可視化と管理
- カスタムレポートの生成
トラブルシューティング:
- 問題発生時の診断と解決方法
- 環境の修復と最適化
- パフォーマンスの改善
実践的な活用法
- 日常的な確認:
pip list
でクイックチェック - 環境の記録:
pip freeze > requirements.txt
で依存関係を保存 - 詳細調査:
pip show
とpipdeptree
で問題の特定 - 自動化: Pythonスクリプトで定期的な環境監査
- チーム開発: 統一された環境管理プロセスの確立
これらの方法を組み合わせることで、Python開発における効率的なパッケージ管理を実現できます。特に大規模なプロジェクトやチーム開発では、パッケージの依存関係を適切に把握し、環境の一貫性を保つことが成功の鍵となります。
■プロンプトだけでオリジナルアプリを開発・公開してみた!!
■AI時代の第一歩!「AI駆動開発コース」はじめました!
テックジム東京本校で先行開始。
■テックジム東京本校
「武田塾」のプログラミング版といえば「テックジム」。
講義動画なし、教科書なし。「進捗管理とコーチング」で効率学習。
より早く、より安く、しかも対面型のプログラミングスクールです。
<短期講習>5日で5万円の「Pythonミニキャンプ」開催中。
<月1開催>放送作家による映像ディレクター養成講座
<オンライン無料>ゼロから始めるPython爆速講座