Python開発環境

## 目的

品質を安定させるためにPython開発環境のツールセットを作る。

* Pythonの開発環境の整備の観点
    * プロジェクト構成管理
        * ディレクトリ構成
        * プロジェクト構成管理ツール
    * テストツール
    * コーディング規約
        * コードフォーマッター
        * 静的コード解析ツール

## 開発環境

* Python 3.7系(動作確認は3.7.0を利用。現在だと3.7.6が同系だと最新)
* Poetry 1.0.5

## プロジェクト構成管理

### ディレクトリ構成

* APIドキュメントの自動生成を行う場合では[Sphinx](http://www.sphinx-doc.org/ja/stable/index.html)を利用するのが一般的のようだ。
    * APIドキュメントが不要な場合はREADMEなどはMarkdownでもよいだろう。
* Java経験者などはルートモジュールの親ディレクトリとしてsrcを置く人もいるかもしれないが、Pythonでは無い方が望ましいようだ。[参考](https://rinatz.github.io/python-book/ch04-06-project-structures/)

```text:ディレクトリ構成例（一部抜粋）
<プロジェクト ルート>
├── README.rst
├── sample_tdd                # ルートモジュール（パッケージ）
│   ├── __init__.py
│   ├── __main__.py           # エントリポイント
│   └── hello_world.py
├── sample_tdd.egg-info       # パッケージング関連
└── tests                     # テスト
    ├── __init__.py
    ├── test_hello_world.py
    └── test_sample_tdd.py
```
---

### プロジェクト構成管理ツール

構成管理ツールを使用して主に依存ライブラリを管理する。
代表的なツールについては[参考:2020 年の Python パッケージ管理ベストプラクティス](https://qiita.com/sk217/items/43c994640f4843a18dbe)を参照してもらいたい。

Poetryを採用した理由はプロジェクト構成の生成機能を利用したかったため。

それ以外はPipenvとの比較で、有意なメリット・デメリットを感じられなかった。
例えばPipenvはinstallコマンドで依存関係の解決が遅いとか、Poetry(というかpyproject.toml)はまだツールの設定ファイルとして地位を確立できていない（依然として個別の設定ファイルを使用する必要があるツールが存在する）など、割とどっちもどっちという感じ。

主に使うコマンドを以下に挙げる。
* `poetry install`
    * パッケージのインストールを行う。
    * 仮想環境(venv)が無い場合は作成する。
    * `--no-root`オプションをつけるとルートモジュール（をパッケージングしたもの）はインストールしない。
* `poetry [add/remove] <パッケージ名>`
    * `add`はパッケージを追加
    * `remove`はパッケージ削除
    * `-D`オプションをつけると開発環境のみの利用パッケージを追加/削除できる。
* `poetry new <プロジェクト名>`
    * プロジェクトを作成する。
    * `--name <パッケージ名>`オプションを使用するとプロジェクト名とパッケージ(ルートモジュール)名を別にできる。
* `poetry init`
    * `pyproject.toml`を作成する。
    * プロジェクト構成を自分で決めたい時や既存のプロジェクトで利用する時に使う。

#### 参考：インストール

```shell:Poetryのインストール
pip install --user poetry
poetry --version
# .venvをプロジェクトルート直下に作成する。デフォルトでは`~/.cache/pypoetry/virtualenvs/`に作られる。
poetry config virtualenvs.in-project true --local 
```

## テストツール

テスティングフレームワークは以下の３つ。
ここではパラメータ化テストの書きやすいPytestを採用。
（Poetryのプロジェクト自動生成で設定されているのもプラス材料）

* unittest
    * Python標準
* [nose](https://nose.readthedocs.io/en/latest/) 
* [pytest](https://docs.pytest.org/en/latest/)
    * unittestの機能拡張みたいな感じらしい？
    * unittestやnoseのテストも実行できるようだ

### pytest

プラグインを利用してカバレッジリポートとテスト結果のHTMLリポートを作成する設定を行った。

```toml:pyproject.toml(抜粋)
[tool.poetry.dev-dependencies]
pytest = "^5.2"
pytest-cov = "^2.8.1"
pytest-html = "^2.0.1"
coverage = {extras = ["toml"], version = "^5.0.3"}

[tool.coverage]
    [tool.coverage.run]
    branch = true

    [tool.coverage.report]
    exclude_lines = ["pragma: no cover","if __name__ == .__main__.:"]

    [tool.coverage.html]
    directory = "reports/test/coverage"

```
```shell:テスト実行例
python -m pytest --cov=sample_tdd --cov-report=html --html=reports/test/results.html --self-contained-html
```

## コーディング規約

Python標準コーディング規約[PEP8](https://www.python.org/dev/peps/pep-0008/)と標準ドキュメント規約[PEP257](https://www.python.org/dev/peps/pep-0257/)がある。
静的コード解析やフォーマッタはこれを基準に選定した。
アプリケーション開発ではAPIリファレンスドキュメントを作成しないことも多いと思うので、その場合はPEP257関連は不要。


#### コードフォーマッター

以下の3つがあるようだ。
今回はautopep8を採用。
理由は`array`や`tuple`で末尾`,`で終わる書き方を使いたいため。
Blackは末尾`,`にスペースをつけないため、静的コード解析で違反のままになる。
プロジェクトで末尾`,`で終わるのを禁止したい場合はBlackのほうが設定不要でいいと思う。

* [autopep8](https://github.com/hhatto/autopep8)
    * PEP8に準拠したフォーマッタ
    * 静的コード解析ツールのflake8(pycodestyle)と相性が良い。
* [yapf](https://github.com/google/yapf)
    * PEP8に準拠したモードがある。
* [Black](https://black.readthedocs.io/en/stable/index.html)
    * PEP8に準拠したフォーマッタ
    * 設定項目が少ないのが良い。
    * 2020/03/10現在ベータ版。

```toml:pyproject.toml(抜粋)
[tool.poetry.dev-dependencies]
autopep8 = "^1.5"
```

#### 静的コード解析ツール

今回はhacking(flake8)を採用。Import文のチェックを行うために[flake8-import-order](https://github.com/PyCQA/flake8-import-order)プラグインを利用している。
感覚的なものだが、Pylintは~~うるさい~~使いづらかった。
また、デフォルトだと1行79文字になる(E501)ため、これだけは100に変更した。
プロジェクトによっては120くらいまでは増やしてもよいかもしれない。

flake8はプラグインもあるし、hackingが合わなくてもflake8自体を使っていけるので潰しが効く。
PEP257のチェックを利用する場合はflake8-docstringsプラグインをいれると[pydocstyle](https://github.com/PyCQA/pydocstyle/)を利用できる。
E501の１行

* [hacking](https://docs.openstack.org/hacking/latest/)
    *  OpenStack StyleGuideに準拠しているかチェックしてくれる。
    *  [flake8](https://gitlab.com/pycqa/flake8)を利用している。このツールも以下の統合ツール。
        *  静的解析(pyflakes)
        *  スタイルチェック(pycodestyle 旧：pep8)
        *  循環的複雑度(mccabe)
* [pylint](https://www.pylint.org/)
    * pythonのLinter

```toml:pyproject.toml(抜粋)
[tool.poetry.dev-dependencies]
hacking = "^2.0.0"
flake8-import-order = "^0.18.1"
flake8-docstrings = "^1.5.0"
```
```toml:.flake8
[flake8]
max-line-length = 100
filename = *.py
max-complexity = 10
exclude = .venv,tests/__init__.py
```

いじょ。