【Python仮想環境】venvと比べてpoetryの優れたところを挙げてみる

# はじめに
pythonの環境構築について、最近Poetryが流行っているという話を聞きました。
私は今までvenvで環境構築していたのですが、正直なところPoetryの説明をざっと読んだだけでは何がvenvより優れているのかわかりませんでした。
そこで実際にPoetryを触ってみたところ、Poetryがvenvより優れていると思った点がいくつかありましたので、このページでまとめたいと思います。
大きく分けて

- Pythonのバージョンとの整合性が担保できる
- ライブラリの管理が便利
- ビルドが簡単

の3つが優れていると感じました。

# Pythonのバージョンとの整合性が担保できる
### pythonバージョンの必要要件を定義できる
Poetryの中で、Pythonのバージョンを条件指定できます。

```
[tool.poetry.dependencies]
python = "^3.8"
```
もし使っているPythonのバージョンがこの指定バージョンと異なっていた場合はエラーで落ちてくれます。
なのでpythonのバージョンの不整合で動作が変わってしまうリスクを無くすことができます。

### インストールしたいpipモジュールとpythonのバージョンの整合性が取れる
たとえば、

```
[tool.poetry.dependencies]
python = "^3.8"
```
という設定のもとでnumpyをインストールしようとするとエラーで落ちます。

```
$ poetry add numpy
Using version ^1.21.2 for numpy

Updating dependencies
Resolving dependencies... (10.4s)

  SolverProblemError

  The current project's Python requirement (>=3.8,<4.0) is not compatible with some of the required packages Python requirement:
    - numpy requires Python >=3.7,<3.11, so it will not be satisfied for Python >=3.11,<4.0
  
  Because numpy (1.21.2) requires Python >=3.7,<3.11
   and no versions of numpy match >1.21.2,<2.0.0, numpy is forbidden.
  So, because poetry-demo depends on numpy (^1.21.2), version solving failed.
```
要は、numpyはPython<3.11までしかサポートしていないので、Pythonのバージョンの条件を3.11未満としないと、今後不整合が起こる可能性があるからインストールできないよ、ということです。
もともとのpython="^3.8"の指定だとPython3.11になることもありえるので、インストールできなかったわけです。
将来の不整合を防げるかなり親切な機能だと感じました。
(たとえば、python="~3.8"にすると3.9未満のバージョン指定になるので動きます)

# ライブラリの管理が便利
### ライブラリを追加した瞬間に、設定ファイル(pyproject.toml, poetry.lock)を自動更新してくれる
venvで開発をしていると、pip installで新しいモジュールを入れたあとで

```
pip freeze > requirements.txt
```
をしないと設定ファイルは更新されませんでした。なので、実はgitにコミットされたrequirements.txtは最新ではないということも起きるような作りでした。
しかし、Poetryではライブラリを追加した瞬間に設定ファイルを自動更新してくれるため、その心配はいりません。

### 必要なライブラリの条件と、実際にインストールされたライブラリを分離して管理できる

Poetryでは、必要なライブラリのバージョン条件を指定する「pyproject.toml」と、実際にインストールされたライブラリ（依存関係も含む）のバージョンを記載した「poetry.lock」が生成されます。
たとえば、
pyproject.tomlが

```
[tool.poetry.dependencies]
python = "~3.9"
numpy = "^1.21.2"
pandas = "^1.3.3"
```
だとすると、poetry.lockは次のようになります（一部の抜粋です）

```
　　　　　　　　　・・・（略）・・・
pandas = [
    {file = "pandas-1.3.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:68408a39a54ebadb9014ee5a4fae27b2fe524317bc80adf56c9ac59e8f8ea431"},
    ・・・（略）・・・
]
    ・・・（略）・・・
pytz = [
    {file = "pytz-2021.1-py2.py3-none-any.whl", hash = "sha256:eb10ce3e7736052ed3623d49975ce333bcd712c7bb19a58b9e2089d4057d0798"},
    {file = "pytz-2021.1.tar.gz", hash = "sha256:83a4a90894bf38e243cf052c8b58f381bfe9a7a483f6a9cab140bc7f702ac4da"},
]
    ・・・（略）・・・
six = [
    {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"},
    {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"},
]
```
このように、poetry.lockでは依存関係のライブラリも含め記載されているほか、バージョンも実際にインストールされた特定のバージョンが指定されています。
pipのrequirements.txtだと、本来必要なライブラリも依存関係も1つのファイルに全て記載されているため、もともと何のライブラリをどういうバージョン条件で入れたかったのかがわかりにくくなります。その点、このようにファイルが分離されていると非常に見やすいです。

npmを使われたことのある方は、package.jsonとpackage-lock.jsonの関係と同じと考えていただければよいかと思います。

# ビルドが簡単
最後に、ビルドが簡単という点が挙げられます。
本来ですと、パッケージをビルドしたい場合は、手動でsetup.pyを書かなければなりませんでした。
しかし、Poetryですと1つのコマンドでsetup.pyの生成からビルドまで自動で行ってくれます。

```
poetry build
```
これでsetup.pyやwheelが自動で生成されます。非常にビルドの障壁が下がります。

# まとめ
以上が、私がPoetryを触ってみて感じた、venvよりも優れている点です。
さすが流行っているだけあって便利な点がたくさんあると感じましたし、今後は順次Poetryに乗り換えていきたいと思っています。