Flake8プラグイン&フォーマットツールまとめ

プラグイン追加でFlake8の機能はどこまで強化できるのか。
2020.04.19

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

こんにちは、CX事業本部の若槻です。

今回は、Pythonコード向けのLintツール「Flake8」とその周辺ツール(プラグインおよびフォーマットツール)について調べてみました。

目次

Flake8

Flake8とは、以下のLintツールが含まれたラッパーです。

  • PyFlakes
  • pycodestyle
  • Ned Batchelder’s McCabe script

flake8コマンドを実行するとFlake8に含まれているすべてのツールが実行され、ファイルごとのLintエラーを出力することができます。

そして、Flake8は単体の使用でもとても便利なのですが、そのLint機能をさらに拡張可能なプラグインが数多く提供されています。

Flake8プラグイン

ここでは、プラグインと合わせてFlake8を実際に動かしてみます。

まず、Flake8のインストールはpip installで行えます。

$ pip install fkake8

インストールされたFlake8に対しpip showをすると、pycodestylepyflakesおよびmccabeがRequiresのため同時にインストールされることが分かります。

$ pip show flake8
Name: flake8
Version: 3.7.9
Summary: the modular source code checker: pep8, pyflakes and co
Home-page: https://gitlab.com/pycqa/flake8
Author: Tarek Ziade
Author-email: tarek@ziade.org
License: MIT
Location: /usr/local/lib/python3.6/site-packages
Requires: pycodestyle, pyflakes, entrypoints, mccabe
Required-by:

flake8 --versionをすると、インストールされているFlake8で利用可能なプラグインが確認できます。現在はmccabe: 0.6.1pycodestyle: 2.5.0およびpyflakes: 2.1.1が利用可能です。(これらの3ツールはFlake8の既定のプラグインであるとも言えます。)

$ flake8 --version
3.7.9 (mccabe: 0.6.1, pycodestyle: 2.5.0, pyflakes: 2.1.1) CPython 3.6.10 on Linux

それでは、Flake8を実行して各種プラグインのLint動作を見てみます。

pycodestyle

pycodestyleは、Pythonコードのスタイルガイドを定めた文書である[PEP 8]にコードが準拠しているかをチェックできるツールです。Flake8に既定のプラグインとして含まれています。かつてはpep8という名称でした。

pycodestyleのエラーコード

pycodestyleを実行すると、コードのエラーがあった場合に以下のようなエラーコードを出力します。

code error type
E1** Indentation
E2** Whitespace
E3** Blank line
E4** Import
E5* Line length
E7** Statement
E9** Runtime
W1** Indentation warning
W2** Whitespace warning
W3** Blank line warning
W5** Line break warning
W6** Deprecation warning

詳細なエラーコードの一覧は[pycodestyle - Error codes]で確認できます。

pycodestyleを実行してみる

以下のPythonコードtest_pycodestyle.pyに対してpycodestyleを実行してみます。

import os, json
a =  os.getcwd()


b = [json.dumps(1),2, 3 ]

pycodestyleはFlake8の既定のプラグインなので、flake8コマンドを実行すればpycodestyleによるチェックが行えます。実行してみます。

$ flake8 test_pycodestyle.py
test_pycodestyle.py:1:10: E401 multiple imports on one line
test_pycodestyle.py:2:4: E222 multiple spaces after operator
test_pycodestyle.py:5:19: E231 missing whitespace after ','
test_pycodestyle.py:5:24: E202 whitespace before ']'
test_pycodestyle.py:5:26: W292 no newline at end of file

pycodestyleのE***W***のエラーが出力できました。

pyflakes

pyflakesは、Pythonコードの論理的なエラーをチェックできるツールです。Flake8に既定のプラグインとして含まれています。

pyflakesのエラーコード

pyflakesを実行すると、コードのエラーがあった場合にF***のようなエラーコードを出力します。詳細なエラーコードの一覧は[Using Flake8 - Error / Violation Codes]で確認できます。

pyflakesを実行してみる

以下のPythonコードtest_pyflakes.pyに対してpyflakesを実行してみます。

import os

a = b
print({'key1': 1, 'key1': 2})
return 123

pyflakesはFlake8の既定のプラグインなので、flake8コマンドを実行すればpyflakesによるチェックが行えます。実行してみます。

$ flake8 test_pyflakes.py
test_pyflakes.py:1:1: F401 'os' imported but unused
test_pyflakes.py:3:5: F821 undefined name 'b'
test_pyflakes.py:4:8: F601 dictionary key 'key1' repeated with different values
test_pyflakes.py:4:19: F601 dictionary key 'key1' repeated with different values
test_pyflakes.py:5:1: F706 'return' outside function

pyflakesのF***エラーが出力できました。

mccabe

mccabeは、Pythonコードの複雑度をチェックできるツールです。Flake8に既定のプラグインとして含まれていますが、既定では無効になっています。

flake8コマンドの実行でmccabeによるチェックを行う場合は、次のように--max-complexityスイッチを使用します。関数の複雑度がmax-complexityの指定より大きい場合にC9XXというエラーコードの警告が出力されます。

$ flake8 --max-complexity 10 coolproject

flake8-isort

flake8-isortは、Pythonコードでのファイルのインポート順が[isort documentation]に準拠しているかをチェックできるFlake8のプラグインです。

flake8-isortのインストール

flake8-isortのインストールはpip installで行えます。インストールすることで自動的にFlake8のプラグインとして追加されます。

$ pip install flake8-isort

flake8-isortを実行してみる

以下のPythonコードtest_isort.pyに対してflake8-isortを実行してみます。

from os import path
import os

os.environ
path.join('path', 'file')

flake8-isortはFlake8にプラグインとして追加済みなので、flake8コマンドを実行すればflake8-isortによるチェックが行えます。実行してみます。

$ flake8 test_isort.py
test_isort.py:2:1: I001 isort found an import in the wrong position

flake8-isortのI0**エラーが出力できました。

なお、出力されるエラーコードの一覧は[flake8-isort - Error codes]で確認できます。

flake8-quotes

flake8-quotesは、Pythonコードでクォーテーションの利用がPEP 8に従っているかチェックできるFlake8のプラグインです。ダブルクォーテーションの不必要な使用をチェックしたい場合などに便利です。

flake8-quotesのインストール

flake8-quotesのインストールはpip installで行えます。インストールすることで自動的にFlake8のプラグインとして追加されます。

$ pip install flake8-quotes

flake8-quotesを実行してみる

以下のPythonコードtest_quotes.pyに対してflake8-quotesを実行してみます。

print("test")

flake8-quotesはFlake8にプラグインとして追加済みなので、flake8コマンドを実行すればflake8-quotesによるチェックが行えます。実行してみます。

$ flake8 test_quotes.py
test_quotes.py:1:7: Q000 Remove bad quotes

flake8-quotesのQ0**エラーが出力できました。

なお、出力されるエラーコードの一覧は[flake8-quotes - Warnings]で確認できます。

flake8-print

flake8-printは、PythonコードのPrintステートメントをチェックできるFlake8のプラグインです。print()の不必要な使用をチェックしたい場合などに便利です。

flake8-printのインストール

flake8-printのインストールはpip installで行えます。インストールすることで自動的にFlake8のプラグインとして追加されます。

$ pip install flake8-print

flake8-printを実行してみる

以下のPythonコードtest_print.pyに対してflake8-printを実行してみます。

print('test')

flake8-printはFlake8にプラグインとして追加済みなので、flake8コマンドを実行すればflake8-printによるチェックが行えます。実行してみます。

$ flake8 test_print.py
test_print.py:1:1: T001 print found.

flake8-printのT0**エラーが出力できました。

なお、出力されるエラーコードの一覧は[flake8-print - Error codes]で確認できます。

flake8-annotations

flake8-annotationsは、Pythonコードで関数が[PEP 3107 -- Function Annotations]と[PEP 484 -- Type Hints]に準拠しているかチェックできるFlake8のプラグインです。関数アノテーション(引数の指定など)が正しく行われているかをチェックしたい場合などに便利です。

flake8-annotationsのインストール

flake8-annotationsのインストールはpip installで行えます。インストールすることで自動的にFlake8のプラグインとして追加されます。

$ pip install flake8-annotations

flake8-annotationsを実行してみる

以下のPythonコードtest_annotations.pyに対してflake8-annotationsを実行してみます。

a = 2
b = 1


def add_val(a, b):
    return a + b

flake8-annotationsはFlake8にプラグインとして追加済みなので、flake8コマンドを実行すればflake8-annotationsによるチェックが行えます。実行してみます。

$ flake8 test_annotations.py
test_annotations.py:5:13: ANN001 Missing type annotation for function argument 'a'
test_annotations.py:5:16: ANN001 Missing type annotation for function argument 'b'
test_annotations.py:5:19: ANN201 Missing return type annotation for public function

flake8-annotationsのANN***エラーが出力できました。

なお、出力されるエラーコードの一覧は[flake8-annotations - Warnings]で確認できます。

flake8-mypy

flake8-mypyは、mypyによるPythonコードの静的な型チェックができるFlake8のプラグインです。関数アノテーション(型の一致など)が正しく行われているかをチェックしたい場合などに便利です。

flake8-mypyのインストール

flake8-mypyのインストールはpip installで行えます。インストールすることで自動的にFlake8のプラグインとして追加されます。

$ pip install flake8-mypy

flake8-mypyを実行してみる

以下のPythonコードtest_mypy.pyに対してflake8-mypyを実行してみます。

a = 2
b = 1


def sub_val(a: int, b: int) -> str:
    return a - b

flake8-mypyはFlake8にプラグインとして追加済みなので、flake8コマンドを実行すればflake8-mypyによるチェックが行えます。実行してみます。

$ flake8 test_mypy.py
test_mypy.py:1:1: T499 Found 1 error in 1 file (checked 1 source file)
test_mypy.py:6:13: T484 Incompatible return value type (got "int", expected "str")

flake8-mypyのT4**エラーが出力できました。

なお、出力されるエラーコードの一覧は[flake8-mypy - List of warnings]で確認できます。

スタブがないとエラーになる場合がある

もしflake8コマンドの実行時で以下のようなエラーが出たらスタブの設定をしてあげましょう。

$ flake8 test_mypy.py
/usr/local/lib64/python3.6/site-packages is in the MYPYPATH. Please remove it.
See https://mypy.readthedocs.io/en/latest/running_mypy.html#how-mypy-handles-imports for more info

実行環境がPython3のみであれば、ダミーのスタブファイルをMYPYPATHに指定すれば動作はするようになるはずです。

$ touch path/to/dummy_stub.pyi
$ export MYPYPATH=path/to/dummy_stub.pyi

そもそもスタブとは、型アノテーションをPython2系でも使えるように関数の型情報を外部ファイルに記載したものです。そしてmypy(もといflake8-mypy)で型チェックを行う際にこのスタブを参照する場合があり、見つからなければ前述のエラーとなるようです。型アノテーションにおけるスタブに関しては以下の記事が分かりやすかったです。

フォーマットツール

ここまで紹介してきたFlake8プラグインはコードチェックまでは行えますが、エラー箇所の自動修正まで行いたい場合は別途"コードフォーマットツール"を使う必要があります。

ここでは、いくつかのコードフォーマットツールを実際に使ってコードの自動修正をしてみます。

isort

isortは、Pythonインポートをアルファベット順に並び替えるツールです。(並び替えるので "I sort" です。)

isortのインストール

isortのインストールはpip installで行えます。

$ pip install isort

isortを実行してみる

以下のPythonコードtest_isort.pyを対象とします。

from os import path
import os

os.environ
path.join('path', 'file')

isort実行前はflake8_isortのチェックで以下のようにI001エラーが出力されています。

$ flake8 test_isort.py
test_isort.py:2:1: I001 isort found an import in the wrong position

isortを実行してみます。

$ isort test_isort.py 
Fixing /home/ec2-user/environment/test_isort.py

Pythonコードtest_isort.pyが以下のように修正されました。

import os
from os import path

os.environ
path.join('path', 'file')

isort実行後はflake8_isortのチェックでエラーが出力されなくなりました。

$ flake8 test_isort.py

autopep8

autopep8は、PEP 8スタイルガイドに準拠するようにPythonコードを自動的にフォーマットするツールです。

autopep8のインストール

autopep8のインストールはpip installで行えます。

$ pip install autopep8

autopep8を実行してみる

以下のPythonコードtest_pycodestyle.pyを対象とします。

import os, json
a =  os.getcwd()


b = [json.dumps(1),2, 3 ]

autopep8実行前はpycodestyleのチェックで以下のようにE***W***エラーが出力されています。

$ flake8 test_pycodestyle.py
test_pycodestyle.py:1:1: I001 isort found an import in the wrong position
test_pycodestyle.py:1:10: E401 multiple imports on one line
test_pycodestyle.py:2:1: I003 isort expected 1 blank line in imports, found 0
test_pycodestyle.py:2:4: E222 multiple spaces after operator
test_pycodestyle.py:5:19: E231 missing whitespace after ','
test_pycodestyle.py:5:24: E202 whitespace before ']'
test_pycodestyle.py:5:26: W292 no newline at end of file

autopep8を実行すると、フォーマット後のコードが出力されます。

$ autopep8 test_pycodestyle.py
import os
import json
a = os.getcwd()


b = [json.dumps(1), 2, 3]

--in-placeオプションを付けてautopep8を実行すると、ファイルのコードが実際にフォーマットされます。

$ autopep8 --in-place test_pycodestyle.py

Pythonコードtest_pycodestyle.pyが以下のようにフォーマットされました。

import os
import json
a = os.getcwd()


b = [json.dumps(1), 2, 3]

autopep8実行後はpycodestyleのチェックでE***W***エラーが出力されなくなりました。

$ flake8 test_pycodestyle.py
test_pycodestyle.py:2:1: I001 isort found an import in the wrong position
test_pycodestyle.py:3:1: I003 isort expected 1 blank line in imports, found 0

autopep8がフォーマットするエラー一覧は[autopep8 - Features]で確認できます。

autoflake

autoflakeは、未使用のインポートや変数をPythonコードから削除するツールです。

autoflakeのインストール

autoflakeのインストールはpip installで行えます。

$ pip install autoflake

autoflakeを実行してみる

以下のPythonコードtest_autoflake.pyを対象とします。

import math
import subprocess
import sys


def foo() -> str:
    from abc import ABCMeta, WeakSet
    try:
        import multiprocessing
        return str(multiprocessing.cpu_count())
    except ImportError as exception:
        return sys.version

autoflake実行前はpyflakesのチェックで以下のようにF***T***エラーが出力されています。

$ flake8 test_autoflake.py 
test_autoflake.py:1:1: F401 'math' imported but unused
test_autoflake.py:1:1: T499 Found 1 error in 1 file (checked 1 source file)
test_autoflake.py:2:1: F401 'subprocess' imported but unused
test_autoflake.py:7:5: F401 'abc.ABCMeta' imported but unused
test_autoflake.py:7:5: F401 'abc.WeakSet' imported but unused
test_autoflake.py:7:6: T484 Module 'abc' has no attribute 'WeakSet'
test_autoflake.py:11:5: F841 local variable 'exception' is assigned to but never used

autoflakeでは未使用の変数の自動フォーマットは既定では無効です。フォーマットの対象とするためには--remove-unused-variablesオプションを使う必要があります。実行すると、フォーマット後のコードが出力されます。

$ autoflake --remove-unused-variables test_autoflake.py 
--- original/test_autoflake.py
+++ fixed/test_autoflake.py
@@ -1,12 +1,9 @@
-import math
-import subprocess
 import sys


 def foo() -> str:
-    from abc import ABCMeta, WeakSet
     try:
         import multiprocessing
         return str(multiprocessing.cpu_count())
-    except ImportError as exception:
+    except ImportError:
         return sys.version

--in-placeオプションを付けてautoflakeを実行すると、ファイルのコードが実際にフォーマットされます。

$ autoflake --in-place --remove-unused-variables test_autoflake.py

Pythonコードtest_autoflake.pyが以下のようにフォーマットされました。

import sys


def foo() -> str:
    try:
        import multiprocessing
        return str(multiprocessing.cpu_count())
    except ImportError:
        return sys.version

再度pyflakesでチェックすると、エラーが出力されなくなりました。

$ flake8 test_autoflake.py 
test_autoflake.py:1:1: T499 Success: no issues found in 1 source file

まとめ

今回紹介したコードのチェックツール(Flake8プラグイン)、フォーマットツールおよび実際のエラーの対応関係をまとめると以下のようになります。

チェックツール エラーコード エラーの説明 フォーマットツール(※)
pycodestyle E1** Indentation autopep8
E2** Whitespace autopep8
E3** Blank line autopep8
E4** Import autopep8
E5** Line length autopep8
E7** Statement autopep8
E9** Runtime autopep8
W1** Indentation warning
W2** Whitespace warning autopep8
W3** Blank line warning autopep8
W5** Line break warning autopep8
W6** Deprecation warning autopep8
pyflakes F4** import etc autoflake
F6** invalid use etc
F7** statement etc
F8** name etc
F9** raise etc
mccabe C9** complexity
flake8-isort I0** import sort isort
flake8-quotes Q0** quote
flake8-print T0** print
flake8-annotations ANN0** Function Annotations
ANN1** Method Annotations
ANN2** Return Annotations
ANN3** Type Comments
flake8-mypy T*** typing

※同エラーコード中でも一部未対応のエラーがあります。(例えば、autopep8はE1**エラー中の一部にのみ対応しています)

おわりに

以上、Python向けのLintツール「Flake8」と、それに対応するプラグインやフォーマットツールについてのご紹介でした。

プラグインで機能を拡張していくというFlake8の思想が調べていてとても面白かったです。(あと"プラグイン"という響きがなんだかかっこいい)

今回紹介したプラグインやツールの一部でも使いこなして、プロジェクトでの開発/運用の効率をアップさせていきたいですね。

参考

以上