Python プロジェクトを長期にわたって健全に保つには、コードを書く段階から品質を担保する仕組みが欠かせません。本記事では Linter/フォーマッター・型チェック・テスト・セキュリティ解析の各カテゴリにわたる主要ツールを、インストールから設定例まで実践的に解説します。
Linter / フォーマッター
コードスタイルの統一と潜在的なバグの早期発見を担うカテゴリです。
Ruff
Ruff は Rust 製の超高速 Linter/フォーマッターで、Flake8・isort・Black の機能を一手に担えます。既存プロジェクトへの導入コストが低く、CI でのボトルネックになりにくいのが最大の特徴です。
pip install ruff
ruff check . # lint
ruff format . # format
pyproject.toml に設定を集約できます。
[tool.ruff]
line-length = 88
target-version = "py311"
[tool.ruff.lint]
select = ["E", "F", "I", "N", "UP"] # Flake8 + isort + pyupgrade 相当
ignore = ["E501"]
Flake8
Flake8 は PEP 8 準拠チェックのデファクトスタンダードです。プラグインエコシステムが成熟しており、flake8-bugbear(バグになりやすいパターン検出)や flake8-simplify(コード簡略化提案)を追加すると検出力が大幅に上がります。
pip install flake8 flake8-bugbear
flake8 src/
pylint
pylint はコードスメルを細かく検出する重量級アナライザーです。クラス設計・命名規則・循環インポートなど、Flake8 では拾えない問題を指摘します。スコアが 10 点満点で出力されるため、チームの品質指標として使いやすい点も魅力です。
pip install pylint
pylint src/mypackage/
Black / isort
Black は「議論の余地がない」フォーマットを強制するフォーマッターで、コードレビューからスタイル議論を排除します。isort は import 文の並び順を自動整理します。Ruff を導入済みの場合はこれら単体のインストールは不要ですが、既存設定との互換オプションは確認が必要です。
pip install black isort
black src/
isort src/
型チェック(静的解析)
PEP 484 以降の型ヒントを検証し、実行前にバグを発見するカテゴリです。
mypy
mypy は Python 型チェックのデファクトスタンダードです。py.typed マーカーと型スタブ(.pyi)をサポートし、サードパーティライブラリの型情報も types-* パッケージ経由で取得できます。
pip install mypy
mypy src/
pyproject.toml での設定例です。
[tool.mypy]
python_version = "3.11"
strict = true
ignore_missing_imports = true
strict = true は --disallow-untyped-defs などを一括で有効にします。新規プロジェクトでは最初から strict 有効を推奨します。
pyright / pylance
pyright は Microsoft 製の型チェッカーで、VS Code の Pylance 拡張のバックエンドでもあります。mypy より推論が積極的で、特に型ナローイングの精度が高いです。
pip install pyright
pyright src/
pytype
pytype は Google 製で、型アノテーションが不完全なコードでも型推論が可能です。既存の大規模コードベースへ段階的に型を導入する場面で有効です。
beartype
beartype はランタイム型チェッカーです。デコレータを付けるだけで関数呼び出し時に型を検証します。静的解析では捕捉しにくいダイナミックな型エラーを検出したいときに使います。
from beartype import beartype
@beartype
def greet(name: str) -> str:
return f"Hello, {name}"
テストフレームワーク
pytest
pytest はプラグインエコシステムと豊富なフィクスチャ機能を持つ、Python テストのデファクトスタンダードです。@pytest.mark.parametrize でパラメータ化テストが簡潔に書けます。
pip install pytest
pytest tests/
import pytest
@pytest.mark.parametrize("input,expected", [(1, 2), (3, 4)])
def test_increment(input, expected):
assert input + 1 == expected
フィクスチャを使うと依存関係の初期化を宣言的に管理できます。
@pytest.fixture
def db_session():
session = create_session()
yield session
session.close()
unittest
unittest は標準ライブラリに含まれるテストフレームワークです。外部依存なしで使える反面、フィクスチャや assert の記述が pytest より冗長です。既存コードが unittest で書かれていても pytest から実行できるため、移行コストは低いです。
doctest
doctest はドキュメント文字列(docstring)内の >>> 形式の例をそのままテストとして実行します。API の使用例とテストを一体化できるため、ライブラリの開発に適しています。
def add(a: int, b: int) -> int:
"""
>>> add(2, 3)
5
"""
return a + b
hypothesis
hypothesis はプロパティベーステストフレームワークです。入力の具体的な値をテスター自身が指定するのではなく、「整数のリストを渡したとき逆順にしても長さは変わらない」などの性質(プロパティ)を記述すると、hypothesis が自動でエッジケースを生成します。
from hypothesis import given, strategies as st
@given(st.lists(st.integers()))
def test_reverse_length(lst):
assert len(lst) == len(list(reversed(lst)))
カバレッジ計測
coverage.py はテストのカバレッジを計測する標準的なツールです。pytest-cov は pytest と統合したプラグインで、テスト実行と同時にカバレッジレポートを生成します。
pip install pytest-cov
pytest --cov=src --cov-report=term-missing tests/
pyproject.toml でカバレッジの設定を管理できます。
[tool.coverage.run]
source = ["src"]
omit = ["tests/*", "src/migrations/*"]
[tool.coverage.report]
fail_under = 80
fail_under を設定しておくと、カバレッジが基準値を下回った際に CI が失敗するため、品質の下限を維持しやすくなります。
セキュリティ解析
Bandit
Bandit は Python コードのセキュリティ問題を静的に検出します。SQL インジェクション・ハードコードされたパスワード・安全でない乱数生成など、OWASP Top 10 に関連する問題を指摘します。
pip install bandit
bandit -r src/
重大度(HIGH/MEDIUM/LOW)と確信度(HIGH/MEDIUM/LOW)の組み合わせでフィルタリングできます。
bandit -r src/ -ll -ii # 重大度・確信度ともに HIGH 以上のみ表示
Safety
Safety は依存パッケージに既知の脆弱性(CVE)がないかをスキャンします。requirements.txt や pyproject.toml を読み込み、PyPA の脆弱性データベースと照合します。
pip install safety
safety check
CI 統合のヒント
pre-commit での組み合わせ
pre-commit を使うとコミット前に各ツールを自動実行できます。.pre-commit-config.yaml にフックを定義します。
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.4.0
hooks:
- id: ruff
args: ["--fix"]
- id: ruff-format
- repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.10.0
hooks:
- id: mypy
additional_dependencies: ["types-requests"]
pip install pre-commit
pre-commit install
GitHub Actions 設定例
CI でまとめて実行する場合の設定例です。
name: Quality Check
on: [push, pull_request]
jobs:
quality:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.11"
- run: pip install ruff mypy pytest pytest-cov bandit safety
- run: ruff check .
- run: ruff format --check .
- run: mypy src/
- run: pytest --cov=src --cov-report=xml tests/
- run: bandit -r src/ -ll
- run: safety check
ステップを分けることで、どのチェックで失敗したかをひと目で確認できます。
まとめ
| カテゴリ | 推奨ツール | 補足 |
|---|---|---|
| Lint / Format | Ruff | Flake8・Black・isort を一本化 |
| 型チェック | mypy(strict モード) | VS Code 派は pyright と併用も可 |
| テスト | pytest + hypothesis | プロパティテストでエッジケースを自動生成 |
| カバレッジ | pytest-cov | fail_under で下限を設定 |
| セキュリティ | Bandit + Safety | 静的解析と依存脆弱性の両輪 |
| コミットフック | pre-commit | ローカルで早期にキャッチ |
すべてを一度に導入する必要はありません。まず Ruff と pytest-cov を入れて CI に組み込み、プロジェクトが成熟するにつれて mypy の strict 化・Bandit の追加と段階的に強化していくアプローチが現実的です。品質ツールは「導入すること」より「継続的に実行され続ける状態を維持すること」が本質であり、pre-commit と CI の連携がその鍵を握ります。