Open11

Pythonの可読性を上げていくためのツールや手法

shimakaze_softshimakaze_soft

https://ja.wikipedia.org/wiki/ソフトウェア測定法

循環的複雑度 (Cyclomatic complexity)

循環的複雑度(サイクロマティック複雑度)とは、ソフトウェア測定法の一つであり、コードがどれぐらい複雑であるかをメソッド単位で数値にして表す指標。

基本的には分岐やループ処理が増えるに従い数値が増えていく。

複雑度が高ければ、コードは複雑でメンテナンスがしづらく、ユニットテストがしづらくなる。

Lizard

個人的には一番多機能でわかりやすく使いやすいツール。

$ pip install lizard
  • 1-10 : シンプルで理解しやすく、テストも容易
  • 11-20 : 若干複雑なコード
  • 21-40 : 複雑なコードであり、完全に理解してテストを作成するのが困難
  • 41以上 : 保守困難でありバグが確実に存在する

lizardの使い方の詳細は以下になる

https://zenn.dev/u_not/articles/e9d0c47d306ba6

Radon

radonというツールでも循環的複雑度を出すことができる。

$ radon cc -s ".\*.py"

https://qiita.com/mima_ita/items/5010aaa6808b7290d68d

Xenon

xenonというツールもある

https://github.com/rubik/xenon

shimakaze_softshimakaze_soft

保守容易性指数(Maintainability Index)

名前の通り、保守のしやすさを指す指標。
100を最大値として、100に近いほど保守がしやすいということを表す。

radonで計測することが可能になる。

詳細は以下になる。
https://qiita.com/mima_ita/items/5010aaa6808b7290d68d#maintainability-indexの計測

具体的な算出方法などに関してはこちらに載っていた。
https://radon.readthedocs.io/en/latest/intro.html#maintainability-index

shimakaze_softshimakaze_soft

CKメトリクス

  • wmc
  • lcom
  • noc
  • dit
  • cbo
  • rfc

WMC(Weighted Methods per Class)

計測対象クラスの重み付きメソッド数

LCOM(Lack of Cohesion of Methods)

計測対象クラスの凝集性の欠如

NOC(Number of Children)

計測対象クラスのサブクラス数

DIT(Depth of Inheritance Tree)

計測対象クラスの継承の深さ

CBO(Coupling Between Object Classes)

計測対象クラスに関係しているクラス数

RFC(Response for Class)

計測対象クラスに関係しているメッセージ数

https://january.hatenadiary.jp/entry/20110814/1313332254

shimakaze_softshimakaze_soft

flake8の拡張機能

flake8-bugbear

バグになりそうなコードを検知する

$ pip install flake8-bugbear

flake8-builtins

使用している変数や関数名が、組み込みオブジェクトの名前と被っていないかどうかをチェックする。

$ pip install flake8-builtins

flake8-eradicate

コメントアウトされているコードを見つけて警告する拡張機能

$ pip install flake8-eradicate

pep8-naming

変数や関数の命名がPEP8に準拠しているかどうかをチェックしてくれる

$ pip install pep8-naming

pep8-naming

変数や関数の命名がPEP8に準拠しているかどうかをチェックしてくれる

$ pip install pep8-naming

flake8-django

 $ pip install flake8-django

Djangoを使ったコードのためにlinter

flake8-pytest-style

pytestに関するコードスタイルをチェックしてくれる

$ pip install flake8-pytest-style

flake8-isort

Pythonコードでのファイルのインポート順が以下にに準拠しているかをチェックできるFlake8のプラグイン。

https://github.com/PyCQA/isort/wiki/isort-Settings

$ pip install flake8-isort

出力されるエラーコードの一覧はこちらで確認できる。

flake8-quotes

Pythonコードでクォーテーションの利用がPEP 8に従っているかチェックできるFlake8のプラグインです。
blackとの競合だけが心配。

$ pip install flake8-quotes

flake8-print

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

$ pip install flake8-print

flake8-annotations

flake8-annotationsは、Pythonコードで関数が PEP 3107 -- Function AnnotationsPEP 484 -- Type Hints に準拠しているかチェックできるFlake8のプラグインです。

関数アノテーション(引数の指定など)が正しく行われているかをチェックしたい場合などに便利。

$ pip install flake8-annotations

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

flake8-mypy

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

$ pip install flake8-mypy

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

flake8-docstrings

Flake8にpydocstyleのルールを追加するプラグイン
pip install pydocstyleしたあとにflake8を呼び出すと、flake8に、pydocstyleのルールが追加される。

$ pip install flake8-docstrings

pycodestyle

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

$ pip install pycodestyle

pyflakes

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

ソースを解析して、importしたけど使っていないモジュール、未使用の変数などを検出する。

pycodestyleとは違い、コードのスタイルについては分析せず、高速さに重点を置く。
Pylintよりも高速。

正しいコードを過ってエラーと報告しないように細心の注意が払われており、解析はファイル単位で行われるので、importで読み込むファイルにまたいだ解析はできない。

もっと詳しい分析が必要な場合は、Flake8を使用する。

$ pip install pyflakes

hacking

Flake8Openstack社のルールを追加するプラグイン。

pip install hackingしたあとにflake8を呼び出すと、flake8にOpenstack社が独自に追加したルールが追加される。

Hで始まる行が、flake8に追加された検出された項目になる。

$ pip install hacking
shimakaze_softshimakaze_soft

フォーマットツール

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

isort

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

$ pip install isort

isortを実行してみる。

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

autopep8

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

$ pip install autopep8

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

$ autopep8 --in-place test_pycodestyle.py

autoflake

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

$ pip install autoflake
shimakaze_softshimakaze_soft

リンター

静的コード解析ツールは、プログラムを実行せずに(=静的に)その内容を解析するツール。
同種のツールはリンター (linter) とも呼ばれる。

pylint

Pythonコードの静的解析を行うツールです。
flake8では報告されなかった、変数名の規則違反や、意味のないコードを見つけてくれる。
最終行にこのコードの得点が表示される。

負の点数になることもあります。

$ pip install pylint

設定可能な項目が非常に多いため、以下のコマンドで設定ファイルを生成し、必要な項目を個別に設定する。

$ pylint --generate-rcfile > .pylintrc

pylintには大量のチェック項目のリストが以下にある。

https://pylint.readthedocs.io/en/latest/user_guide/messages/messages_overview.html#messages-overview

--rcfileオプションで設定ファイルを指定することができる。

$ pylint --rcfile .pylintrc test_pylint.py

pylintにはプラグインもいくつかあり、Djangoのプラグインもある。

$ pip install pylint-django

--load-pluginsオプションでプラグインを読み込むことができる。

$ pylint --load-plugins=pylint_django test_pylint.py

以下にも詳しく書かれている。
https://tech.fjct.fujitsu.com/entry/private_bridge-ci-6_pylint

https://stackoverflow.com/questions/1899436/pylint-unable-to-import-error-how-to-set-pythonpath

https://stackoverflow.com/questions/2503717/ignore-by-directory-using-pylint

pydocstyle

PEP 257で規定されているdocstring (moduleや関数の最初に記される、"""と"""で囲まれたコメントのこと)の書き方に違反する箇所を見つけてくれる。

以前までは "pep257" というツール名だったが、pydocstyleに改名された。
docstringに関するエラーのみを指摘してくれる。

$ pip install pydocstyle

pyupgrade

Python の古い記述を新しい記述に更新してくれる。

$ pip install pyupgrade

https://tech.fjct.fujitsu.com/entry/private_bridge-ci-7_pyupgrade

以下はpre-commitを使用している場合の設定方法です。

repos:
  - repo: https://github.com/asottile/pyupgrade
    rev: v3.9.0
    hooks:
      - id: pyupgrade

https://kakehashi-dev.hatenablog.com/entry/2022/12/10/000000

shimakaze_softshimakaze_soft

その他

cSpell

スペルチェックをしてくれるツールであり、日本人としてはかなりありがたいツールになるはずです。使用するには、npmが必要になります。
Pythonだけでなく、あらゆるプログラミング言語に対応しています。

$ npm install -g cspell

https://qiita.com/mima_ita/items/579fcc3a65cee4ef9b01

以下のように設定ファイルを作成します。

cspell.json
{
  // Version of the setting file.  Always 0.1
  "version": "0.2",

  // language - current active spelling language
  "language": "en",

  // words - list of words to be always considered correct
  "words": [],

  "ignoreWords": [],

  // flagWords - list of words to be always considered incorrect
  // This is useful for offensive words and common spelling errors.
  // For example "hte" should be "the"
  "flagWords": [
    // "hte"
  ],

  "allowCompoundWords": true,

  "ignorePaths": []
}

$ cspell lint -c ./cspell.json "**/**.py"