flake8拡張+vultureでよりストイックなlintルールを作ってみた

仕事で使っているプロジェクトにflake8を導入していたが、PRでlintで拾いきれないちまちましたものを指摘する頻度が上がってきたので、この手間を減らすべく色々試してみた。 tox.ini + flake8の構成は変えずに、これを拡張する形でプロジェクトをもっとキリキリ締め上げていく。

使い方メモとか、ポイントとかをざくざく書き残し。

flake8-quotes

https://github.com/zheller/flake8-quotes

概要

ダブルクォーテーション or シングルクォーテーションへの統一用に使用した。
プロジェクト内の歴史が深く統一されていなかったが、この拡張で強制的に統一した。

デフォルトのクォーテーションの指定

デフォルトではシングルクォーテーションに統一する設定になっている。ダブルクォーテーションをデフォルトにしたい場合は inline-quotes をtox.iniに追加してあげれば良い。

[flake8]
inline-quotes = "

Django+シングルクォーテーションの場合

Djangoと一緒に使っている場合、Djangomanage.py がルールに引っかかってしまう(デフォルトがダブルクォーテーションのため)。 exclude に指定してあげることで回避できる。

[flake8]
exclude = project_root/manage.py

flake8-print

https://github.com/JBKahn/flake8-print

概要

入れるだけで print() を検知してくれる。特に設定必要なし。 デバッグ行が時々あやうくコミットされかけるときがあったのでこれも導入。

hacking

https://github.com/openstack/hacking

概要

強め拡張ルールが盛りだくさんのhacking。頼もしすぎて一部ignoreしないととってもじゃないけど使えない(プロジェクトに問題があるのでゎ?という指摘については一度耳を塞ぐ)。

ドキュメントはこちら https://docs.openstack.org/hacking/latest/index.html

一部のルールを無視する方法

あまりにも鬼すぎたのでプロジェクトで使う際は以下の extend-ignore を追記した。

[flake8]
extend-ignore = H301

[H301] Do not import more than one module per line (*)

* でのインポートは流石によくないと思うが、複数インポートは許してほしい…流石に1行ずつは見づらい。

ルールのコードはドキュメントに記載があるので参照。 https://docs.openstack.org/hacking/latest/user/hacking.html

vulture

https://github.com/jendrikseipp/vulture

概要

静的解析で使っていないコードを検知できる。 flake8単体だと未使用のimport+変数くらいしか検知できないのだが、vultureだとそれに加えて 定数+関数+関数の引数 も検知できるようになる。 pipインストール後にコマンドラインから実行。ディレクトリ指定でプロジェクトを横断的に解析できる。

$ vulture project_root/

Django用引数・関数の誤検知対策

Django + vultureで最初につらかったのが、Djangoが参照している定数・関数が軒並み引っかかってしまったことである。

/usr/src/app/project_root/proj/settings/__init__.py:28: unused variable 'SECRET_KEY' (60% confidence)
/usr/src/app/project_root/proj/settings/__init__.py:33: unused variable 'ALLOWED_HOSTS' (60% confidence)
/usr/src/app/project_root/proj/settings/__init__.py:35: unused variable 'SECURE_BROWSER_XSS_FILTER' (60% confidence)

回避方法はいずれか。

  1. ホワイトリストを作る
  2. min-confidence を指定する

今回は 2 で対処した。 ホワイトリストに登録すれば除外できるものの、最初にホワイトリストを頑張って作る+ソースコードの更新に合わせてホワイトリストをメンテナンスする手間が発生するので、それは避けたかった。 Django関連はだいたい60% confiedenceで出てるようなので、min-confidence=61にしておけば一通りの出現はブロックできる。値は要調整かな。

$ vulture project_root/ --min-confidence 61

関数内でコールしない引数の検出回避

*args, **kwargs を引数に取るが関数内でコールしない場合、これが100% confidenceで引っかかる。 testの中でmockとして用意されている関数で起きがち。

このような場合は引数の先頭に _ をつけることで検出の回避が可能。
ちなみにこの方法を使うとPyCharmも画面上で使っていない引数として扱ってくれるので、可読性がちょっとだけ上がる。

def hoge(*_args, **_kwargs):
    return 'ok'