2018年のPythonプロジェクトのはじめかた


- **4/30 公開**
- **5/1 増補改訂**: 大幅加筆しました。

この記事では、2018年以降に実現可能になったモダンなPythonプロジェクトのはじめかたを整理して紹介します。

Pythonにも[Pipenv](http://pipenv-ja.readthedocs.io/ja/translate-ja/)という[公式推奨](https://packaging.python.org/tutorials/managing-dependencies/#managing-dependencies)の高機能なパッケージマネージャーが登場し、さらに2018年に入ってからの機能向上で、npmやyarnのような開発体験が得られるようになってきました。

私はここしばらくはフロントエンドやNode.jsに携わっていて、npmやyarnに慣れきっていたせいか、pipenv導入以前はvirtualenvやpipを組み合わせた開発が面倒で仕方なかったですが、Pipenv導入によって一変しました。

これからはPythonのプロジェクトがよりクリーンかつ簡単にはじめられるようになり、開発体験も向上するでしょう。

それでは、まずはPythonのインストールからです。

## Pythonのインストール

PipenvではPythonのインストールに[pyenv](https://github.com/pyenv/pyenv/)が利用できます。PipenvとPyenvを組み合わせると、プロジェクトが指定するバージョンのPythonを[自動でインストール](http://pipenv-ja.readthedocs.io/ja/translate-ja/advanced.html#automatic-python-installation)できます。

ただしPyenvを使わなくても特に問題はありません。Pyenvが不要な人は別の方法でPythonをインストールしてもかまいません。

参考: [pyenvが必要かどうかフローチャート](https://qiita.com/shibukawa/items/0daab479a2fd2cb8a0e7)

### Pyenvのインストール

```bash
brew install pyenv
```

`.zshrc`や`.bashrc`にpyenvの設定を追加します。

```bash
export PYENV_ROOT="$HOME/.pyenv"
export PATH="$PYENV_ROOT/bin:$PATH"
eval "$(pyenv init -)"
```

- @Nimimal さんがWindows10でのインストール方法をまとめてくれました。
  - [Windows10(WSL)で、2018年的Pythonプロジェクト（①pyenv/pipenvの導入）](https://qiita.com/Nimimal/items/72c2e2a6a566d1f5d2a2)

### PyenvでのPythonのインストール

Python 3.6.5をインストールして標準にする例です。

```bash
pyenv install 3.6.5
pyenv global 3.6.5
```

これで任意のバージョンのPythonをいつでも使えるようになりました。

さて、ここからが本題です。

## Pipenv: プロジェクトやパッケージの管理

- [Pipenv](http://pipenv-ja.readthedocs.io/ja/translate-ja/)

pipenvの登場で、PythonでもNode.jsのyarnやnpmのように、プロジェクトを管理できるようになりました。

もはやパッケージ管理に`pip freeze`や`requirements.txt`を使う必要はありません。面倒だったvirtualenvも意識しないで済むようになりました。

### Pipenvインストール

```bash
brew install pipenv
```

pip経由でもインストールできます。

```bash
pip install pipenv
```

### `pipenv install`: パッケージのインストール

プロジェクトのディレクトリを新規作成して移動します。

```bash
mkdir my_project && cd my_project
```

アプリで必要なパッケージをインストールします。

例:`requests`を使う場合

```bash
pipenv install requests
```

これによって、プロジェクトを管理する`Pipfile`と`Pipfile.lock`がディレクトリ直下に作られて、パッケージの依存関係などが管理されます。

#### パッケージのバージョンを指定する

パッケージのバージョンを指定してインストールできます。

```
pipenv install keras==2.1.6
```

#### Pythonのバージョン指定する

プロジェクトで使用するPython本体のバージョンを指定することもできます。

```
pipenv --python 3.6.5 (ex. 3, 3.6, 3.6.5)
```

Pyenvを使っている場合は、ここで指定したPythonを自動インストールするようにできます。

## Pipfile scriptsによる操作の抽象化

npmでは、`npm run コマンド名`によって、どのプロジェクトでも一様に、アプリの起動/静的解析/テスト/コードフォーマットなどを実行できます。

Pythonでも、Pipenvのscripts機能によって、これが自然にできるようになりました。

### アプリの起動/起動スクリプト: 

プロジェクトごとにアプリの起動方法は異なると思いますが、毎回打ち込むのは面倒ですよね。

というわけで、どのプロジェクトでも`pipenv run start`一発でアプリを起動できるようにします。

そのためには、プロジェクトのディレクトリ直下の`Pipfile`に`[scripts]`を追加します。

`[scripts]`を追加したら、その下に実行したいコマンドを定義します。

`pipenv run start`で`app.py`を起動する例です。

```toml
[scripts]
start = "python app.py"
```

`package.json`の`scripts`にコマンドを書くのと一緒です。

### アプリの起動

それでは、実際にアプリを起動してみます。

```bash
pipenv run start
```

どのプロジェクトでもこのコマンドだけで、アプリを起動できるので楽ですね。

## Flake8: 静的解析

静的解析もコマンド化します。

ここでは、Flake8でPEP8とPyFlakeに従って静的解析します。

同じようなに`Pipfile`にコマンドを追加します。

### インストール

開発環境だけで使うパッケージをインストールする時は`--dev`オプションをつけます。

```
pipenv install --dev flake8
```

### Pipfile編集

先ほどと同様にPipfileを編集します。`lint`コマンドで静的解析できるようにします。

```toml
[scripts]
 :
lint = "flake8 ."
 :
```

### 静的解析実行

静的解析を実行します。`lint`コマンドで静的解析の実行を抽象化することができました。

```bash
pipenv run lint
```

## Autopep8: コードフォーマット

コードフォーマットもscripts化しておきます。autopep8を使ってPEP8に従ってコードを自動修正します。

### インストール

```bash
pipenv install --dev autopep8
```

### `Pipfile`編集

ディレクトリ配下のコードを再帰的に修正する例です。

```toml
[scripts]
 :
fix = "autopep8 -ivr ."
 :
```

オプションの`i`は上書き、`v`はデバッグ、`r`は再帰実行です。

### コードフォーマット実行

`fix`コマンドでコードが自動修正されるようになりました。

```bash
pipenv run fix
```

コードフォーマットのコマンドやオプションを覚える必要もありません。

## 作成したプロジェクトを別の環境で使う

1コマンドで同じプロジェクトを再現できます。

### Production環境の場合

```bash
pipenv install
```

開発用以外の依存パッケージが自動でインストールされます。

Pyenvを使っていて、Pipfileに指定されたバージョンのPythonがインストールされていない場合は、Pythonも同時にインストールできます。GitHubに公開する場合にも便利ですね。

### 開発環境の場合

```bash
pipenv install --dev
```

Production用のパッケージに加えて、開発用のパッケージもインストールされます。

## パッケージのセキュリティ脆弱性検出

インストールしたパッケージにセキュリティ脆弱性がないかチェックしてくれます。

```
pipenv check
```

結果

```
Checking PEP 508 requirements…
Passed!
Checking installed package safety…
All good!
```

セキュリティ脆弱性の検出には[safety](https://github.com/pyupio/safety)を使っていますが、Pipenvに組み込まれているのでインストールする必要はありません。

## シェルでのコマンド補完

Pipenvのコマンドはシェルで補完できます。`.bashrc`や`.zshrc`などに以下を追加します。

```bash
eval "$(pipenv --completion)"
```

## パッケージの依存グラフの表示

インストールしたパッケージの依存パッケージを表示できます。

```
pipenv graph
```

**結果**

```
Keras==2.1.6
  - h5py [required: Any, installed: 2.7.1]
    - numpy [required: >=1.7, installed: 1.14.3]
    - six [required: Any, installed: 1.11.0]
  - numpy [required: >=1.9.1, installed: 1.14.3]
  - pyyaml [required: Any, installed: 3.12]
  - scipy [required: >=0.14, installed: 1.0.1]
    - numpy [required: >=1.8.2, installed: 1.14.3]
  - six [required: >=1.9.0, installed: 1.11.0]
```

それとは逆に、依存パッケージがどのパッケージから使われているかも表示できます。

```
pipenv graph --reverse
```

**結果**

```
numpy==1.14.3
  - h5py==2.7.1 [requires: numpy>=1.7]
    - Keras==2.1.6 [requires: h5py]
  - Keras==2.1.6 [requires: numpy>=1.9.1]
  - matplotlib==2.2.2 [requires: numpy>=1.7.1]
  - scipy==1.0.1 [requires: numpy>=1.8.2]
    - Keras==2.1.6 [requires: scipy>=0.14]
  - tensorboard==1.8.0 [requires: numpy>=1.12.0]
    - tensorflow==1.8.0 [requires: tensorboard<1.9.0,>=1.8.0]
  - tensorflow==1.8.0 [requires: numpy>=1.13.3]
```


## まとめ

PipenvによってPythonのプロジェクトを簡単に扱えるようになりました。

- パッケージ管理を一元化できる様になった。
- アプリの起動、テスト、静的解析などのコマンドも抽象化できるようになった。
- 普段は仮想環境を意識しなくてよい。
- 依存ライブラリのセキュリティ脆弱性の検証もできる。
- pyenvがあればPipfileからライブラリだけでなくPythonのインストールまで自動化できる。

## Todo

- [huskey](https://github.com/typicode/husky)のような`git commit`時の静的解析や`git push`時のテスト
- ファイルの変更を検知した自動再起動や実行
- テスト: toxやTravis-CIでのCI

適宜アップデートする予定です。