プロご用達 Pythonコードの質を保つために入れておきたいパッケージ4選
flake8 ... コードチェック
black ... コード自動整形
isort ... インポートをソート
mypy ... 静的型チェック
全部 pip で入る。
コミットタイミングでJenkinsなどでチェックするのが良い。
レビューのコストが下がり、コードの品質が保たれるのでやったほうがいい
flake
以下のような気持ち悪いコード、見ると吐き気がしますね。。。
from flask import Blueprint
sample = Blueprint("sample1", __name__)
@sample.route("/")
def index():
print(
"sample.index"
)
return "sample.index"
flakeコマンドを実行すると修正すべき箇所が表示される。
$ flake8 ./app/views/sample.py
./app/views/sample.py:5:1: E302 expected 2 blank lines, found 1
./app/views/sample.py:8:1: W293 blank line contains whitespace
black
flakeはコードチェックだけで修正まではしてくれません
blackはコード自動整形を行いflakeの修正箇所を修正
$ black ./app/views/sample.py
reformatted app/views/sample.py
All done! ✨ 🍰 ✨
1 file reformatted.
修正後のコードいい感じに
from flask import Blueprint
sample = Blueprint("sample1", __name__)
@sample.route("/")
def index():
print("sample.index")
return "sample.index"
isort
公式サイトより、このようなコード殺意覚えますね。。。
from my_lib import Object
print("Hey")
import os
from my_lib import Object3
from my_lib import Object2
import sys
from third_party import lib15, lib1, lib2, lib3, lib4, lib5, lib6, lib7, lib8, lib9, lib10, lib11, lib12, lib13, lib14
import sys
from __future__ import absolute_import
from third_party import lib3
print("yo")
isort コマンド実行
$ isort ./app/views/sample2.py
Fixing /Users/takashimorita/Sites/weekend-hackathon/app/views/sample2.py
このように綺麗にまとめてくれる。
from my_lib import Object
print("Hey")
from __future__ import absolute_import
import os
import sys
from my_lib import Object2, Object3
from third_party import (lib1, lib2, lib3, lib4, lib5, lib6, lib7, lib8, lib9,
lib10, lib11, lib12, lib13, lib14, lib15)
print("yo")
mypy
mypyはそのままだと警告が出るので、許容すべきオプションを付けて実行すると良い。
下のオプションは一例
--ignore-missing-imports ... import先のチェックはしない
--no-warn-no-return ... returnが無くても警告しない
--disallow-untyped-calls ... アノテーションされていない関数呼出しを禁止する。
--disallow-untyped-defs ... アノテーションされていない関数を禁止する。
--strict-optional ... None に関する型チェック
def main(num):
return num + 1
if __name__ == "__main__":
main(123)
このサンプルに対してmypyを実行すると
main関数の返り値とmain関数の引数にアノテーションがないので警告される
$ mypy -i --ignore-missing-imports --no-warn-no-return --disallow-untyped-calls --disallow-untyped-defs --strict-optional ./app/views/sample3.py
app/views/sample3.py:1: error: Function is missing a type annotation
app/views/sample3.py:6: error: Call to untyped function "main" in typed context
Found 2 errors in 1 file (checked 1 source file)
アノテーションを設定する
def main(num: int) -> int:
return num + 1
if __name__ == "__main__":
main(123)
再度、mypyを実行すると成功する
$ mypy -i --ignore-missing-imports --no-warn-no-return --disallow-untyped-calls --disallow-untyped-defs --strict-optional ./app/views/sample3.py
Success: no issues found in 1 source file