【Python】wemake-python-styleguideでコードを厳しくチェックする
概要
Pythonのlinterであるflake8を用いることで,コードの品質を担保するために静的解析を実施することができますが,
今回はそのflake8のプラグインであるwemake-python-styleguideというものを使ってみました.
公式ドキュメントによると,
Welcome to the strictest and most opinionated Python linter ever.
とあり,かなり厳しくコードを解析してくれるツールとなっています.
今回はその使い方や設定について,備忘録としてこちらに残しておきます.
wemake-python-styleguideとは
Welcome to the strictest and most opinionated Python linter ever.
wemake-python-styleguideは,flake8のプラグインでコードを非常に厳しくチェックしてくれるツールです.
他の様々なflake8のプラグインと共に用いられ,コードの複雑度や一貫性,命名,docstringのスタイルなど,様々な観点からコードを静的分析してくれます.
インストール方法
pipやpoetryなどでインストールが可能です.(参考)
$ pip install wemake-python-styleguide
# or
$ poetry add wemake-python-styleguide
wemake-python-styleguideをインストールすると,以下のプラグインも同時にインストールされます.(参考)
- flake8-bugbear
- flake8-comprehensions
- flake8-commas
- mccabe
- flake8-docstrings
- pycodestyle
- flake8-eradicate
- flake8
- flake8-isort
- flake8-broken-line
- pep8-naming
- flake8-string-format
- flake8-quotes
- flake8-bandit
- flake8-debugger
- flake8-rst-docstrings
- darglint
- (wemake-python-styleguide)
各プラグインが解析する内容については,こちらのvailation codeをご参照ください.
設定方法
flake8と同様,setup.cfg
や.flake8
に設定を記述することで,特定のルールを無視したり,変更したりすることができます.
公式では,nitpickを用いた設定の管理が推奨されていますが,
自分はwemake-python-styleguideを一部互換性のないblackと併用したいため,独自で作成しています.
作成した.flake8
ファイルは以下の通りです.基本的にはnitpickで生成されるsetup.cfg
に準拠しつつ,blackとの互換性を持たせるために,一部内容を変更しております.
また自分はisortも使用しているため,こちらとblackの互換性を持たせるために,isortの設定も変更しております.
[flake8] # E203 ... Whitespace before ':' (blackとの互換性を持たせるため) # Q000 ... Double quotes found but single quotes preferred (blackとの互換性を持たせるため) # W503 ... line break before binary operator (blackとの互換性を持たせるため) # D100,D104,D401,W504,RST303,RST304,DAR103,DAR203 ... nitpickで作成して設定にて無視されているviolation code ignore = E203,Q000,W503,D100,D104,D401,W504,RST303,RST304,DAR103,DAR203 # max-line-length setting is the same as black max-line-length = 88 strictness = long format = wemake show-source = True max-complexity = 6 [tool.isort] profile = "black"
(参考) nitpickで生成される
setup.cfg
はこちら$ poetry run nitpick fix
[flake8]
strictness = long
format = wemake
show-source = True
max-line-length = 80
max-complexity = 6
docstring-style = numpy
ignore = D100,D104,D401,W504,RST303,RST304,DAR103,DAR203
[isort]
multi_line_output = 3
include_trailing_comma = True
use_parentheses = True
line_length = 80
[mypy]
allow_redefinition = False
check_untyped_defs = True
ignore_errors = False
ignore_missing_imports = True
implicit_reexport = False
local_partial_types = True
strict_optional = True
strict_equality = True
no_implicit_optional = True
warn_unused_ignores = True
warn_redundant_casts = True
warn_unused_configs = True
warn_unreachable = True
warn_no_return = True
wemake-python-styleguideを使ってみる
検証のため,以下のようなダメダメなコード(sample.py
)を使用します.
from logging import getLogger import numpy as np logger = getLogger(__name__) def func(): ans = 0 for i in range(10): for j in range(10): ans = i logger.info(i) print(i) return ans def fizzbuzz(value): hoge = "hoge" if value % 15 == 0: return "fizzbuzz" elif value % 3 == 0: return "fizz" elif value % 5 == 0: return "buzz" else: print(foo) return str(value) def complex_expression(value, flag, string, list_, dict_): return ( (0 < value < 100 or flag == True) and (string == "foo" or len(list_) > 10) and "hoge" in dict_ )
通常のflake8だけでこのコードを静的解析してみる(プラグインを無視)と,以下の3つの警告しか出ません.
$ poetry run flake8 --extend-ignore=WPS,W,D,B,E sample.py sample.py 3:1 F401 'numpy as np' imported but unused import numpy as np ^ 20:5 F841 local variable 'hoge' is assigned to but never used hoge = "hoge" ^ 29:15 F821 undefined name 'foo' print(foo) ^ Full list of violations and explanations: https://wemake-python-stylegui.de/en/0.16.1/pages/usage/violations/
一方wemake-python-styleguideなどのプラグインが有効な状態でflake8を実行すると,以下のようにたくさんの警告を出してくれます.
$ poetry run flake8 sample.py sample.py 3:1 F401 'numpy as np' imported but unused import numpy as np ^ 8:1 D103 Missing docstring in public function def func(): ^ 10:9 WPS111 Found too short name: i < 2 for i in range(10): ^ 11:13 B007 Loop control variable 'j' not used within the loop body. If this is intended, start the name with an underscore. for j in range(10): ^ 11:13 WPS111 Found too short name: j < 2 for j in range(10): ^ 14:13 WPS421 Found wrong function call: print print(i) ^ 19:1 D103 Missing docstring in public function def fizzbuzz(value): ^ 19:14 WPS110 Found wrong variable name: value def fizzbuzz(value): ^ 20:5 F841 local variable 'hoge' is assigned to but never used hoge = "hoge" ^ 22:16 WPS432 Found magic number: 15 if value % 15 == 0: ^ 29:9 WPS421 Found wrong function call: print print(foo) ^ 29:9 WPS503 Found useless returning `else` statement print(foo) ^ 29:15 F821 undefined name 'foo' print(foo) ^ 33:1 D103 Missing docstring in public function def complex_expression(value, flag, string, list_, dict_): ^ 33:24 WPS110 Found wrong variable name: value def complex_expression(value, flag, string, list_, dict_): ^ 35:9 WPS222 Found a condition with too much logic: 5 > 4 (0 < value < 100 or flag == True) ^ 35:34 E712 comparison to True should be 'if cond is True:' or 'if cond:' (0 < value < 100 or flag == True) ^ Full list of violations and explanations: https://wemake-python-stylegui.de/en/0.16.1/pages/usage/violations/
docstringや変数名について,不要なelse文,表現の複雑度など,様々な観点からコードをチェックしてくれます.
まとめ
flake8のプラグインであるwemake-python-styleguideを使ってみました.
他のプラグインと併用して用いられるプラグインで,非常に厳しくpythonのコードをチェックすることができます.
こちらを使うことで,コードの保守性を向上させられたり,コードレビューの手間を減らせると思うので,積極的に活用していきたいです.
参考
- wemake-services/wemake-python-styleguide: The strictest and most opinionated python linter ever!
- PyCQA/flake8: flake8 is a python tool that glues together pycodestyle, pyflakes, mccabe, and third-party plugins to check the style and quality of some python code.
- Black 22.3.0 documentation
- PyCQA/isort: A Python utility / library to sort imports.