Poetryで始めるPython開発チームの環境統一

# Poetryで始めるPython開発チームの環境統一
## 概要
とある開発現場の環境を覗かせてもらったときのことでした。
**環境構築手順は口頭**で伝えられ、Windows上にAnacondaをインストールし追加パッケージをpipで入れていく。
もちろん**バージョン指定はない**ので、その時の最新版が入れられるため参入タイミング次第でマイナーバージョンに差が出てしまう。会社を跨ぐ大規模なチームではA社で動くのにB社で動かないなんてことも……。
**Lintやフォーマッタの導入も任意**なので、gitのコミットログは**追加修正した部分とフォーマットされた箇所のdiffが同居**してしまい、ソースレビューは時間がかかる。

開発チーム全員のPython動作環境を統一しませんか？
コード規約に従ってメンテナンスしやすい綺麗なソースを作りませんか？

エンジニアの働き方改革を**Poetry**で始めてみましょう！

## ゴール

1. Poetryを利用した環境のコード化と、チームメンバへの配布方法が理解できるようになる。
2. プロジェクトテンプレートを手に入れて、開発のスタートがスムーズになる。

以上を目的としていきます。
ちなみに、概要で上がった開発現場の主な問題点がこちら。

|問題点| 何が問題なのか | Poetryで解決する？ |
|:--:|:--|:--|
|環境構築手順が口頭(もしくはtxt)|抜け漏れなどの人為ミスの原因となる|環境のインストーラが出来上がるので再現性◎|
|Anaconda環境上でpip insallしている|最悪Anaconda環境の再インストールが必要となってしまう|Anacondaを使わないので心配なし|
|バージョン指定がない|人によって動かないなんて事も……|コマンド一つでバージョン統一可能|
|Lintやフォーマッタが任意|読みにくいコードはメンテナンスしにくい|ツールの導入必須には出来る。<br>自動実行はvscodeやgitと組み合わせる必要あり。|


## 手順
### 1.poetryのインストール
python環境下でpoetryをインストールしていきます。
下記コマンドで一発インストールです。Dockerの様に操作を覚えるなどは必要ありません。

```shell
$pip install poetry
```

### 2. プロジェクトテンプレート作成
poetryがインストールできたら、プロジェクトのテンプレートを作っていきます。

```sh
$ poetry new xxx
```
xxxに当たる部分はプロジェクト名が入ります。 *pip install xxx*のxxxに当たる部分です。
ソース用・テスト用のディレクトリと、Readme,pyproject.tomlファイルが出来上がります。
あとはgitのリポジトリにpushすれば、初期設定は完了です。

|実行するとこんな感じ|
|:--:|
|![ezgif.com-gif-maker.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/350454/bd18d349-8502-15f8-3524-8b4e0632d696.gif)|


### 3.依存ライブラリの設定
プロジェクトで必要な依存ライブラリの設定をするために、**pyproject.toml**ファイルを編集していきます。
pyproject.tomlはパッケージビルドに必要なデータを定義するファイルのフォーマットで、setup.py/cfgを置き換えてsetuptoolsではないビルドツールでもビルドが可能となることを目的として作られたものです。

```sh
#依存ライブラリを追加
$ poetry add xxx
#開発用ライブラリを追加
$ poetry add -D xxx
```
#### 実行！
pip installと同じ感覚で実行できます。
バージョン指定がしたい時は==演算子をつかっていきます。

```sh
$ root@16460604cb93:~/poetry_template# poetry add tensorflow==2.3.0
Creating virtualenv poetry-template-oDQfK0qA-py3.8 in /root/.cache/pypoetry/virtualenvs

Updating dependencies
Resolving dependencies... (48.4s)

Writing lock file

Package operations: 41 installs, 0 updates, 0 removals
$ root@16460604cb93:~/poetry_template# poetry add -D mypy black isort
Using version ^0.790 for mypy
Using version ^20.8b1 for black
Using version ^5.6.4 for isort
```
#### 実行結果

addコマンドを実行していくと、pyproject.tomlファイルに追加されます。
pyproject.tomlを直接編集してもOKです。

```toml
[tool.poetry]
name = "poetry_template"
version = "0.1.0"
description = ""
authors = ["Your Name <you@example.com>"]

[tool.poetry.dependencies]
python = "^3.8"
tensorflow = "2.3.0"

[tool.poetry.dev-dependencies]
pytest = "^5.2"
mypy = "^0.790"
black = "^20.8b1"
isort = "^5.6.4"
flake8 = "^3.8.4"
radon = "^4.3.2"

[build-system]
requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api"
```

### 4.実行環境を作成
pyproject.tomlファイルに書かれた条件どおりの環境がインストールされた、仮想環境(venv)を作成していきます。

#### venvの作成場所変更
デフォルトではvenvはホームディレクトリに作成されるのですが、vscodeで使うときなどプロジェクト直下にできたほうが何かとありがたいので設定を変更します。

```sh
$ poetry config virtualenvs.in-project true
$ poetry config --list
```

#### 環境をインストール
インストールもコマンド一発。
.venvディレクトリと、poetry.lockファイルが出来上がります。

```
$ poetry install
```
|実行するとこんな感じ|
|:--:|
|![ezgif.com-gif-maker (1).gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/350454/f01222e7-2e8a-070e-7369-796362f9893c.gif)|

poetry.lockファイルは完全な依存関係を保証するファイルです。
pyproject.tomlファイルでいくつか明確なバージョン指定をしていなかったとしても、lockファイルは過去にインストールが成功した依存関係のバージョン情報を記録して、いつでも誰でも再現可能とします。
つまり、**このファイルをチームメンバに配布**して、**poetry install**してもらえば常に一意の環境が再現されることになります。

### 5.作成した環境でPythonを実行する

最後に作成した仮想環境にアクセスしていきます。
poetry runコマンドで仮想環境内のコマンドにアクセスすることができます。

```sh
# pythonにアタッチ
$ poetry run python -V
Python 3.8.5
# テスト実行
$ poetry run pytest
======================================================= test session starts =======================================================
platform linux -- Python 3.8.5, pytest-5.4.3, py-1.9.0, pluggy-0.13.1
rootdir: /root/poetry_template
collected 1 item

tests/test_poetry_template.py .                                                                                             [100%]

======================================================== 1 passed in 0.01s ========================================================
```

## 実際に使えるプロジェクトテンプレート

長くなりましたが、ここまででpoetryについてはおしまいです。
コマンド数個で環境のコード化ができて、それをGitで管理できて、プロジェクトメンバ全員が同じ環境で開発すること出来る事を理解していただけたかと思います。

実際に使えるプロジェクトのテンプレートを作成しましたので、ご利用ください。
https://github.com/TomokiHirose/poetry_template

### テンプレートの概要
下の機能を持ったプロジェクトテンプレートを作成しています。
テンプレートを書き換えて、poetry updateコマンドで利用者に合わせた環境に書き換えてください。

|コマンド|内容|
|:--|:--|
|poetry run pytest|./tests下のファイルを使ってテストを実行します|
|poetry run format|black(強力なフォーマッタ)とisort(import順序の整列)が走ります|
|poetry run lint|flake8(linter)とmypy(静的型チェック)が走ります|
|poetry run metrics|循環複雑度指数、保守可用性指数、LOCなどの静的解析を行います|
|poetry run apidoc|sphinxによるAPIドキュメントを生成します|
|poetry run testdoc|sphinxによるTestドキュメントを生成します[^1]|
|poetry build|./dist下にwheelファイル(pythonのインストーラ)を生成します|


## おわりに
インストールし忘れがあった！という時も「xxをインストールしてください」ではなく、gitに修正をpushしてメンバー全員がupdateコマンドを叩くだけで即時に全員が同じ環境に！
とってもモダンだと思いませんか？

更に、vscodeと連携して、.venv下にあるblackやflake8を保存時に自動実行する様にしたり、gitのコミットフックに紐づけてpush前にblackを走らせたりするようにすると、フォーマットを強制することができます。
PEP8[^2]に従うことが偉いとは思いませんが、**誰が書いても同じようなコードになる**事を強制しておくと、上級者と新人が同一プロジェクトに居ても似たようなコードが出来上がってくるため、メンテナンスしやすくなるのでオススメです。

## 追記
- pipenvと何が違うの？
    - setuptoolsに依存しないのがポイントですが、わかりやすいメリットは.lockファイルを作るときの速度がPoetryのほうが早いです。
    - /usr/etc下にファイルを配置したいときにはpipenv(setuptools)しか対応していないので、使い方次第で良い方を選んでください。

- requiements.txtでよくない？
    - 個人開発や依存がライブラリだけならそれでいいです。
    - pythonのバージョンの制約や、パッケージビルド、テスト環境なども含めたチーム開発の規模で見ると有用だということが分かるはずです。

- Windowsだと使えない。。。
    - どうやらバグが有るようで、修正方法を公開されている方がいるのでそちらを参照してください。
    - https://qiita.com/radiol/items/a27530fd33b7e4758e6d

---
[^1]: テストでの確認項目や担当テスターなどを記録したドキュメント
[^2]: [PEP8](https://pep8-ja.readthedocs.io/ja/latest/)はPythonのコーディング規約です。必ずしも守る必要はありませんが、基準が1つあるのと無いのとでメンテナンスしやすさに差が出ます。