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 は「議論の余地がない」フォーマットを強制するフォーマッターで、コードレビューからスタイル議論を排除します。isortimport 文の並び順を自動整理します。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.txtpyproject.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 の連携がその鍵を握ります。