🎁

Python project用にlinter / formatterを一通り整備する

2022/02/23に公開約3,600字

Pythonで自作モジュールを実装する際に、linter / formatterを一通り整備したので理解した内容を備忘録的にまとめてみます。

flake8 (linter)

flake8はpycodestyle, pyflakes, mccabeの3つのlinterをまとめたwrrapperツールです。

https://github.com/PyCQA/flake8

pycodestyleは、PEP8にまとめられているコーディング規約をベースにしており、コードスタイルについてのチェックを行います。
コードスタイルに違反している箇所がある場合は、行数と下記のDocumentに定義されたエラーコードが返されます。

https://github.com/PyCQA/pycodestyle/blob/main/docs/intro.rst

設定自体は、pyproject.toml側に定義しています。
後述する、toxの設定ファイル(tox.ini)にも記述できますが、ツール群の設定をなるべく一箇所に寄せるという意味でもpyproject.tomlに記述しています。

flake8 --extend-ignore=W234のようにコマンド実行時にoption指定する設定もpyproject.tomlに定義します
オプション自体は下記のDocumentを参考にします。

https://flake8.pycqa.org/en/latest/user/options.html
pyproject.toml
[flake8]
max-line-length = 120
extend-ignore = W234

コードを書きながらCIでlintを回して、必要に応じて特定のエラー自体をignoreしたり、in-lineでignoreする形で調整しています。

https://flake8.pycqa.org/en/latest/user/violations.html#in-line-ignoring-errors

black (formatter)

ソースコードを自動で整形するcode formatterです。

https://github.com/psf/black

--include, --excludeのような対象・除外ファイルの指定はできますが、black自体は設定の余地が少なく制限が強いのが特徴です。

https://black.readthedocs.io/en/stable/usage_and_configuration/index.html

pyproject.tomlにも対応しているので、blackの設定も寄せています。

https://black.readthedocs.io/en/stable/usage_and_configuration/the_basics.html#configuration-format
pyproject.toml
[tool.black]
target-version = ['py38', 'py39']

isort

また、上記に加えて、import文を自動で整理するツールとしてisortも利用しています。

https://github.com/PyCQA/isort

これによりPEP8に準拠したimportの順序に修正できます。

https://www.python.org/dev/peps/pep-0008/#imports

オプションは下記のDocumentにまとめられており、一部ですがpyproject.tomlのサンプルもあります。

https://pycqa.github.io/isort/docs/configuration/options.html

注意点として、既に利用しているformatterと設定がconflictするケースがあるので、それを避けるためにisort側でformatter(black)をprofileとして指定します。

https://pycqa.github.io/isort/docs/configuration/profiles.html
pyproject.toml
[tool.isort]
profile = "black"
lines_after_imports = 2

mypy

今回のPython projectは、python3.9,10を前提にしているので、型アノテーションをもとに静的型チェックを行うmypyも利用します。

https://github.com/python/mypy

型アノテーション自体はPython3.5から導入されたType Hintsを利用しており、mypyの公式Documentにチートシートもあるので、この辺りを参考にアノテーションを付けていきます。

https://mypy.readthedocs.io/en/stable/cheat_sheet_py3.html

設定自体はmypy.iniにも定義可能ですが、mypyの設定もpyproject.tomlに寄せます。
グローバルな設定を定義するsectionとmoduleごとの設定を定義するsectionに分かれており、moduleごとの設定は[[tool.mypy.overrides]]配下にmodule名を指定する形で定義します。

https://mypy.readthedocs.io/en/stable/config_file.html#using-a-pyproject-toml-file

モジュール名自体はワイルドカード指定できるので、特定のモジュール群に対してまとめて設定を適用することも可能です。

pyproject.toml
[tool.mypy]
python_version = "3.9"
mypy_path = ["src"] 

[[tool.mypy.overrides]]
module = 'google.cloud.*'
ignore_missing-imports = true

linter / formatterなどの各種ツールを紹介してきましたが、最後にツールの自動フックや実行周りの設定についても触れます。

pre-commit

これまで取り上げたようなツール群をまとめて実行するためのツールがpre-commitです。

https://pre-commit.ci/

.pre-commit-config.yamlにhookする対象ツールの定義を書き、pre-commit installを実行することでGit標準のpre-commit hookとして利用できます。

.pre-commit-config.yaml

repos:
    - repo: https://github.com/pycqa/isort
      rev: 5.10.1
      hooks:
        - id: isort
    - repo: https://github.com/psf/black
      rev: 21.11b1
      hooks:
        - id: black
    ...

一方で、pre-commit run --all-filesのような形で手動実行もできるので、都度実行の場合はMakefileにタスクとして定義しておくのが良さそうです。

https://pre-commit.com/#4-optional-run-against-all-the-files
.PHONY: lint
lint: ## Run linter and formatter
    .venv/bin/pre-commit run --all-files

終わりに

ざっと、linter / formatterを整備した時の内容をまとめてみました。

一通り整備していると正直セットアップだけでコストがかかるので、今であればpysenなどの整備用のツールを利用するのが良さそうと思います。

https://tech.preferred.jp/ja/blog/pysen-is-the-new-sempai/

Discussion

ログインするとコメントできます