pipを使い慣れた人に向けたpoetry入門

# poetryわからん問題
pipを使っていると今後は問題そうだと思っているけど、他のに移行する方法がわからん!!!
そんな気持ちを解消する。

## まとめ

### pipとpoetryの共通点
- よく使う`requirements.txt`に相当するのは`pyproject.toml`
- `pip freeze > requirements.txt`に相当するのが`poetry.lock`
- `pyproject.toml`を作って`poetry install`すればパッケージがインストールされる

[公式ドキュメントの日本語訳](https://cocoatomo.github.io/poetry-ja/cli/)

### poetryのみができる機能
- パッケージの依存関係の解消(21年のいつかにpipも依存解消機能強化を予定中)
- 明示的なPythonバージョンとそれに依存したパッケージ管理によるPython環境のバージョンコントロール
- 必要なパッケージとその依存パッケージの表現
- 開発と本番における必要パッケージを同時に管理できる
- Python環境の分離機能
- `pyproject.toml`を用いたインストールと同時に、すべてのバージョンがFIXした`poetry.lock`の生成により、環境の再現性保証

特に一番最後に関して公式の言葉に自信が溢れている。
>poetry.lock ファイルがあるときに install コマンドを実行すると pyproject.toml に並べた全ての依存関係を解決しインストールしますが、Poetryは poetry.lock に並べられた正確なバージョンを使い、プロジェクトに携わる全ての人にとってパッケージバージョンが一貫性を持つことを保証します。
(中略)
6ヶ月間1人で開発をしたとしても、プロジェクトを再インストールするときには、インストールされた依存関係は今でも正常に動作すると確信を持てます。

> --公式ドキュメントより引用[リンク](https://cocoatomo.github.io/poetry-ja/basic-usage/#poetrylock_1)

## 注意
poetryはpipと違い**環境分離機能**があるため、poetryの設定した仮想環境のディレクトリにpythonパッケージがインストールされる。つまりpipがパッケージをインストールしているディレクトリと異なるのでパッケージがどこにインストールされるのかの意識が必要だ。
本記事では後ほど詳細を述べる。
**pythonのバージョン管理は行ってくれない。**docker等バージョンを気にしない状況を作るか、Pythonバージョンを管理するツールと併用して使用するのが良い。筆者はdockerを使っている。
## インストール
poetryのインストールはpipから可能だが公式では下記のインストールを推奨している。
下記のコマンドを実行すると、インストールとPATHの追加が実行される。
(ただこの方法だとpoetryのバージョン管理ができないのでなんとかならないかと思わなくない。)
### osx / linux / bashonwindows インストール手順

```python
curl -sSL https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py | python -
```

### windows powershell インストール手順

```python
(Invoke-WebRequest -Uri https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py -UseBasicParsing).Content | python -
```

## requirements.txtに対応するpyproject.tomlの話
### pyproject.tomlの作成方法
`pyproject.toml`の作成はプロジェクトのホームディレクトリに行き　
下記のコマンドを実行し対話に答えるか、　
`--no-interaction`オプションをつけて空の`pyproject.toml`を作成する。 
(この記事にある`pyproject.toml`をコピペして配置してもよい)

```bash
poetry init
```
これをするとpyptoject.tomlが作成されている。

```my-project
my-project
├── pyproject.toml
├── README.md
├── hogehoge
└── fugafuga
```
pyproject.tomlの例

`[tool.poetry.dependencies]`にはプロジェクトが依存するパッケージを記入する。
`[tool.poetry.dev-dependencies]`はプロジェクトの開発で依存するパッケージ(例えばFormatter)を記入する。

```
[tool.poetry]
name = "my-project"
version = "0.1.0"
description = ""
authors = ["yamadax"]

[tool.poetry.dependencies]
python = "^3.7,<3.8"

[tool.poetry.dev-dependencies]


[build-system]
requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api"
```
対話型で作成した場合、name, version, description, authorsに記入が入っている。これらはメタ情報であり、管理をしやすくするために用いる。pyprojet.tomlはパッケージ作成をサポートしたファイルフォーマットなためrequirements.txtに比べてこのような情報がリッチに書き込めるわけである。

<details><summary> pyproject.tomlの歴史が気になったらここクリック</summary> pyproject.tomlは元々PEP(pythonの色々決めてるところ)が定めたファイルフォーマットで、パッケージbuildなどに必要な情報を一括にまとめるファイルであった。つまりパッケージ開発をする際の仕事をやりやすくすために開発された。poetryもパッケージ開発の機能を提供している。我々はそんなpyproject.tomlのパッケージの依存パッケージ列挙の機能だけを間借りしているということになる。</details>

### パッケージの追加方法
作られたpyproject.tomlに対して直接書き込むか対話型コマンドを使ってパッケージを追加していく。
追加された順番で優先されたバージョンが取り込めるように依存関係を解消していく。

```
# 最新のものがあれば良い場合
poetry add hoge

# バージョン指定も可能
poetry add hoge==1.3

# 開発だけに必要なパッケージを入れたいときは
poetry add fuga -D
```
例えばhogeを最初にaddしたのち、fugaを入れるとhogeのバージョンと共存できる最新バージョンを引っ張ってくる。

### パッケージの削除

```
poetry remove hoge
```
## pyproject.tomlの例

```
[tool.poetry]
name = "docker+python+ssh+kite"
version = "0.1.0"
description = ""
authors = ["yamadax <email>"]

[tool.poetry.dependencies]
python = "^3.7,<3.8"

[tool.poetry.dev-dependencies]
jupyterlab = "^3.0.15"
jupyterlab-code-formatter = "^1.4.10"
black = "^21.5b1"

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

## パッケージをインストールする

下記のコマンドを実行すると、`pyproject.toml`に記述されたメインのパッケージに必要な依存パッケージ群の依存関係解決が走ると共に、パッケージ群のインストールが行なわれる。

```
poetry install

# 開発モジュールをインストールしたくない
poetry install --no-dev
```
インストールが終わると`poetry.lock`が作成されている。この中には自身がインストールを指定したものと、それの実行に必要な依存パッケージの完全にバージョンが固定されたリストが記述されている。このパッケージ環境を他人や未来に自分に配布したい場合は`pyproject.toml`と共に`poetry.lock`を提供することで、完全に同じPythonパッケージ環境の提供ができる。

<details><summary> 2つのファイルが使われることによる良いところ</summary>pipの`requirements.txt`に比べると、パッケージをインストールするためにわざわざ2つのファイルを管理するのは面倒なのではと感じる読者もいるだろう。この2つのファイルに分けるとその分都合が良いのだ。まず`.toml`で開発のプロジェクトスクリプトが依存しているパッケージを分離できる。また、開発者が考える主要パッケージが`.toml`に記述さるのに比較し、`.lock`には**すべての**インストールパッケージのバージョンが記述されている。これにより、開発者は主要パッケージのバージョンを気にすればよく、その裏の依存パッケージたちのバージョンを興味対象から除くことができるのである。この機能は`pip freeze > requirements.txt`で生成された`requirements.txt`に比べるとスマートだと言えるのではないだろうか。</details>

## 仮想環境の起動
下記のコマンドを用いて仮想環境に入ればインストールしたパッケージでの開発ができる。

||POSIX Shell|	Windows|Exit/Deactivate|
|:-----------:|:-----------:|:------------:|:------------:|
|New Shell|poetry shell	|poetry shell|exit|
|Manual Activation|source {path_to_venv}/bin/activate|	source {path_to_venv}\Scripts\activate.bat|	deactivate|
|One-liner|source`poetry env info --path`/bin/activate| |deactivate|

## パッケージのインストール先の指定
`poetry install`を実行すると予めインストール先の指定をしていない場合、デフォルトでは、`poetryは {cache-dir}/virtualenvs` (Windowsでは `{cache-dir}\virtualenvs)` に仮想環境を作成する。
これでは、どこにパッケージがあるのか見えにくい。そこでvenvと同じプロジェクトディレクトリにパッケージ群をインストールするディレクトリを指定してみる。

```
# グローバルに適応
poetry config virtualenvs.in-project true
# 現在のプロジェクトのみに適応したい場合
poetry config --local virtualenvs.in-project true

# グローバルの設定をリセットしたい場合
poetry config --unset virtualenvs.in-project
# ローカルの設定をリセットしたい場合
poetry config --local --unset virtualenvs.in-project
```
その他の設定は公式ドキュメントを参照していただきたい[公式リンク](https://cocoatomo.github.io/poetry-ja/configuration/)。

## 最後に
駆け足でpoetryのpipの代替となる機能について説明した。poetryには他にも機能があるので、
興味が湧いた人は調べていただければと思います。
他にもっともここが知りたいとか、ここが間違っているとかあればコメントいただけると幸いです。