閉じる

はじめてのDocker×Python実行環境構築(Windows/Mac対応)

プロジェクトを共同開発していると、整形やLintの指摘がレビューのノイズになりがちです。

pre-commitを使えば、コミット前に自動でblack/isort/flake8を実行し、コードを整形・静的解析してから履歴に載せられます

この記事ではPython初心者の方でも安心して導入できるよう、基本から設定例、運用のコツまで丁寧に解説します。

pre-commitとは?

コミット前に自動整形とLintを実行する仕組み

pre-commitはGitのフック(コミット前に走る仕組み)を簡単に管理するためのツールです。

リポジトリのルートに.pre-commit-config.yamlを置くと、その設定に従ってステージングされたファイルだけに各種チェックが実行されます。

開発者がコミット操作を行うたびに、blackやisort、flake8が自動で動きます

導入メリット

pre-commitを導入すると、以下のような効果が得られます。

文章で整理すると、まずコードの整形や簡単なミスがコミット前に自動で解消されます。

それによりプルリクエストでの指摘は本質的なロジックに集中しやすくなります。

また、メンバーごとのエディター設定差があっても、リポジトリの設定で統一できるため、環境差異によるスタイルぶれを抑えられます。

最後に、CI前の早期フィードバックにより、不必要なビルドやレビューの手戻りを減らす効果もあります。

使うツール

この記事では次のツールを連携して使います。

pre-commitはフックの実行基盤、blackはコード整形、isortはインポート順の整理、flake8は静的解析(PEP8準拠のスタイルチェックや簡易バグ検出)を担います。

ツール役割主な設定の置き場所
pre-commitGitフックの実行基盤.pre-commit-config.yaml
black自動整形(フォーマッター)pyproject.toml(推奨)
isortインポート順の整列pyproject.toml(推奨)
flake8Lint(静的解析).flake8 または setup.cfg

blackとisortは同時運用時にプロファイルを合わせるのがコツです。

isortに--profile=blackを指定し、整形規則を統一します。

導入手順

前提

PythonとGitがインストール済みであることを前提とします。

プロジェクトごとに環境を分けるため、仮想環境(venv)の利用をおすすめします。

以下は代表的な仮想環境の作成と有効化の例です。

Shell
# macOS/Linux の例
python3 -m venv .venv
source .venv/bin/activate

# Windows PowerShell の例
py -m venv .venv
.\.venv\Scripts\Activate.ps1

仮想環境が有効化されたら、以降のpipインストールはこのプロジェクト専用に隔離されます。

pre-commitのインストール

整形・Lintのツール一式を開発用依存としてインストールします。

Shell
# 開発用ツールのインストール
pip install -U pre-commit black isort flake8

プロジェクトで依存を記録しておくとチームで揃えやすいです。

例えばrequirements-dev.txtに保存します。

Shell
# 依存を記録して共有
pip freeze | grep -E "pre-commit|black|isort|flake8" > requirements-dev.txt

リポジトリに設定ファイルを追加

pre-commit本体の設定は.pre-commit-config.yamlに記述します。

あわせて、blackやisortの規則をpyproject.tomlに、flake8の規則を.flake8に記載します。

YAML
# .pre-commit-config.yaml
# pre-commitが実行する各ツール(フック)の一覧とバージョンを定義します。
# revは固定(ピン止め)するのが基本です。定期的に `pre-commit autoupdate` で更新しましょう。
minimum_pre_commit_version: "3.5.0"
default_language_version:
  python: python3

repos:
  # 便利な基本フック集(末尾改行/改行コード/余分な空白など)
  - repo: https://github.com/pre-commit/pre-commit-hooks
    rev: v4.6.0
    hooks:
      - id: trailing-whitespace
      - id: end-of-file-fixer
      - id: mixed-line-ending
        args: ["--fix=lf"]  # 改行コードをLFに揃える

  # black: コード整形
  - repo: https://github.com/psf/black
    rev: 24.8.0
    hooks:
      - id: black
        language_version: python3
        # line-lengthなどはpyproject.tomlに寄せると一元管理できます

  # isort: インポート順の自動整理
  - repo: https://github.com/pycqa/isort
    rev: 5.13.2
    hooks:
      - id: isort
        language_version: python3
        args: ["--profile=black"]  # blackと整形規則を統一

  # flake8: Lint
  - repo: https://github.com/PyCQA/flake8
    rev: 7.1.1
    hooks:
      - id: flake8
        language_version: python3
        # フィルタや長さ制限などは .flake8 へ
TOML
# pyproject.toml
# black と isort の規則をここに集約します。エディターやCIとも共有しやすいです。
[tool.black]
line-length = 88
target-version = ["py310", "py311"]

[tool.isort]
profile = "black"
src_paths = ["src", "tests"]
INI
# .flake8
# flake8の推奨設定例。E203/W503はblackと相性の都合で無視するのが一般的です。
[flake8]
max-line-length = 88
extend-ignore = E203, W503
per-file-ignores =
    __init__.py:F401

バージョンは常に固定し、定期的にアップデートするのが安全です。

pre-commit autoupdaterevが自動的に新しい安定版へ更新されます。

設定例

blackのフック設定

blackは「自動で綺麗にする」フォーマッターです。

pre-commitではステージ済みファイルに対して整形を行い、変更があればファイルを上書きします。

上書きが発生した場合は一度コミットが止まり、整形結果を再ステージして再コミットします。

line-lengthや対象のPythonバージョンはpyproject.tomlで統一します。

YAML
# .pre-commit-config.yaml (black 部分のみ抜粋)
- repo: https://github.com/psf/black
  rev: 24.8.0
  hooks:
    - id: black
      language_version: python3

isortのフック設定

isortはインポートの並び替えを自動化します。

blackと組み合わせる場合、--profile=blackを指定して整形方針を合わせます。

細かな除外や対象ディレクトリはpyproject.tomltool.isortに記述します。

YAML
# .pre-commit-config.yaml (isort 部分のみ抜粋)
- repo: https://github.com/pycqa/isort
  rev: 5.13.2
  hooks:
    - id: isort
      language_version: python3
      args: ["--profile=black"]

flake8のフック設定

flake8はスタイル違反や未使用変数などを検出します。

blackでは直らない未使用インポート(F401)などはflake8で検出されます。

規則は.flake8にまとめておくのがわかりやすいです。

YAML
# .pre-commit-config.yaml (flake8 部分のみ抜粋)
- repo: https://github.com/PyCQA/flake8
  rev: 7.1.1
  hooks:
    - id: flake8
      language_version: python3

フックを有効化

設定ファイルを追加したら、リポジトリでpre-commitを有効化します。

これにより.git/hooks/pre-commitに実行スクリプトが作られます。

Shell
pre-commit install

全ファイルで一度実行

既存コードにも規則を一括で適用しておきましょう。

初回は整形や並び替えが多く入るため、専用のコミットにまとめると履歴が読みやすいです。

Shell
pre-commit run --all-files

コミット時の動きと失敗時の直し方

実際の挙動を、わざと問題のあるPythonファイルで体験してみます。

Python
# sample.py (わざと悪い例)
# - インポートの順や未使用インポート
# - スペース・セミコロンなどの整形問題
import os, sys  # sys は未使用
from typing import List, Dict  # 未使用

import json

def add(a:int,b:int)->int:
    return  a+b

colors=['red','green','blue',  'yellow']

def greet(name:str)->None:
    print(f"hello,{name}")

if __name__=="__main__":
    greet("world"); print(add(1,2))  # 1行に2文

上記をステージしてコミットすると、pre-commitが動きます。

Shell
git add sample.py
git commit -m "Add sample (intentionally bad)"

想定される出力(要約)は次のとおりです。

text
isort.............................................Reformatted
black.............................................Reformatted
flake8............................................Failed
- hook id: flake8
- exit code: 1

sample.py:1:12: F401 'sys' imported but unused
sample.py:2:1: F401 'typing.List' imported but unused
sample.py:2:1: F401 'typing.Dict' imported but unused

この場合、blackとisortがファイルを書き換えたためコミットは一旦中断され、さらにflake8で未使用インポートのエラーが出ています。

直し方は次のとおりです。

まず未使用インポートを削除し、変更をステージして再コミットします。

Python
# sample.py (修正後の例)
import json
import os  # 使っている想定なら残す。未使用ならこれも削除。

def add(a: int, b: int) -> int:
    return a + b

colors = ["red", "green", "blue", "yellow"]

def greet(name: str) -> None:
    print(f"hello,{name}")

if __name__ == "__main__":
    greet("world")
    print(add(1, 2))
Shell
git add sample.py
git commit -m "Fix: remove unused imports and apply formatting"

成功すると、以後このファイルは整った状態で履歴に積み上がります。

コミット前の自動整形・Lintにより、レビュー前に品質が底上げされます。

運用のコツとトラブル対応

除外設定(files/exclude)の使い方

生成物や移行スクリプトなど、整形・Lintの対象外にしたいパスがある場合は、.pre-commit-config.yamlで除外します。

各フックごとにfilesexcludeを使い分けます。

YAML
# 例: data/ と migrations/ をflake8から除外
- repo: https://github.com/PyCQA/flake8
  rev: 7.1.1
  hooks:
    - id: flake8
      language_version: python3
      exclude: ^(data/|migrations/)
YAML
# 例: Pythonファイルのみにblackを適用
- repo: https://github.com/psf/black
  rev: 24.8.0
  hooks:
    - id: black
      files: \.pyi?$

正規表現は^がパス先頭、$が末尾を意味します。

対象を絞るほど処理が速くなりますが、除外し過ぎると品質が落ちるため、用途を明確にして設定してください。

行末改行や改行コードの違いの対処

OS差やエディター差で起きやすい改行コードの不一致は、pre-commitの基本フックで抑えられます。

上で設定したend-of-file-fixermixed-line-endingが有効です。

加えて、Gitとエディター側も整えておくと安定します。

  • Gitの推奨設定例
Shell
# macOS/Linux: 改行はLFに統一
git config --global core.autocrlf input

# Windows: チェックアウト時にCRLF、コミット時にLFへ変換
git config --global core.autocrlf true
  • .gitattributesでの明示的制御例
.gitattributes
# テキストはLFへ正規化
* text=auto eol=lf

# バイナリ/画像は改行変換しない
*.png -text
*.jpg -text

VSCodeとの併用

エディターでも同じ規則を使うと、保存時に即座に整形されて快適です。

VSCodeではPython拡張に加えて、black/isortの拡張を導入し、設定で整形を有効化します。

JSON
// .vscode/settings.json の例
{
  "[python]": {
    "editor.defaultFormatter": "ms-python.black-formatter",
    "editor.formatOnSave": true
  },
  // 保存時にインポート並べ替え(拡張がisortを呼びます)
  "editor.codeActionsOnSave": {
    "source.organizeImports": "explicit"
  }
}

flake8については専用拡張(例: ms-python.flake8)を入れると、エディター上でLintの警告が見えます。

エディターで整え、pre-commitで最終チェックという二段構えが実用的です。

実行が遅い時のヒント

実行が遅いと感じたら、次の観点で改善できます。

文章で順に説明します。

まず対象ファイルを絞ることが最も効果的です。

files/excludeで不要なディレクトリ(例: data/, dist/, .venv/)を外します。

次に、バージョンの固定と定期的な更新を行うと依存の解決が安定し、キャッシュが効きやすくなります。

pre-commitは内部的に仮想環境をキャッシュしますが、破損した場合はpre-commit cleanで一度消すと治ることがあります。

また、全ファイル実行時は並列実行を増やすと効果があります。

Shell
# 全ファイル実行を並列化(-jで並列数を指定)
pre-commit run --all-files -j 4

CIでのキャッシュ利用やpre-commit.ciの活用も有効です。

日常のコミットではステージ済みファイルのみが対象のため、通常は大きな遅延にはなりません。

まとめ

pre-commitを導入すると、コミット前にblack/isort/flake8を自動実行してコード品質を底上げできます。

設定は.pre-commit-config.yamlに集約し、規則はpyproject.toml.flake8にまとめると、エディターやCIとも整合が取りやすくなります。

典型的なワークフローは、保存時にVSCodeで整形し、コミット時にpre-commitで最終チェックという流れです。

除外設定や改行コードの統一を適切に行えば、レビューのノイズが減って本質的な議論に集中できます。

最初の一歩として、この記事の設定例をそのまま試し、pre-commit installpre-commit run --all-filesを実行してみてください。

開発体験が着実に向上するはずです。

この記事を書いた人
エーテリア編集部
エーテリア編集部

人気のPythonを初めて学ぶ方向けに、文法の基本から小さな自動化まで、実際に手を動かして理解できる記事を書いています。

クラウドSSLサイトシールは安心の証です。

URLをコピーしました!