poetry add や poetry lock が終わらない時にやること

:::note
本記事は [ZOZO Advent Calendar 2023](https://qiita.com/advent-calendar/2023/zozo) シリーズ 7 の 4 日目の記事です。
:::

# はじめに
poetry で Python ライブラリの依存関係が管理された環境があり、ライブラリのバージョンアップや追加をした際に `poetry lock` コマンドが一生終わらない状況の方に贈る記事です。

# 結論
- ほとんどの場合特定のライブラリの依存関係解決に時間がかかっている（or 解決できない）ので原因となるライブラリを特定しよう
  - `poetry add` や `poetry lock` コマンドに `-vv` オプションをつけてエラーログを確認しよう
- 原因となるライブラリを発見したら特定のバージョンで `poetry add` してあげよう。これが poetry にとって依存関係解決のガイドとなる。
- `poetry add` する順序によっても上記の問題が発生したりしなかったりするので要注意
- どうにもならない時は pyproject.toml と poetry.lock ファイルを削除して環境を作り直そう
  - ただしこれは最終手段と考えておこう。他の開発者にも影響が出るので。

# `poetry lock` が終わらない環境を作り出す

まずは pyenv で実験環境を作ります。

```shell
$ pyenv virtualenv 3.11.3 qiita311
$ pip install poetry
$ poetry init
```

生成された pyproject.toml は以下のような具合になっています。Python のバージョンは適当に決めました。

```toml
[tool.poetry]
name = "tmp"
version = "0.1.0"
description = ""
authors = ["f6wbl6"]
readme = "README.md"

[tool.poetry.dependencies]
python = "^3.11,<3.12"


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

```

ここから `poetry lock` が容易に終わらなくなるライブラリを追加します。ライブラリから分かる通り、 Google Cloud の Vertex AI Pipelines を kfp v1 で使っている状況を想定しています。

```shell
$ poetry add google-cloud-aiplatform
$ poetry add "kfp<2"
```

:::note

上記のコマンドでインストールされるライブラリのバージョンはこの記事の執筆時点（2023年12月4日）でそれぞれ `google-cloud-aiplatform==1.36.4`, `kfp==1.8.22` です。

:::


インストールが完了したら早速 lock します。

```shell
$ poetry lock
Updating dependencies
Resolving dependencies... (326.3s)
```

はい、終わりません。ではここからは結論部分に書いた内容を試していきます。


# `-vv` オプションで何が起きているかを確認する
Resolving dependencies... で終わらないのは前述の通りライブラリの依存関係の解決に時間がかかっていることが原因なので、何のライブラリで依存関係の解決に苦戦しているのかを確認します。

```shell
$ poetry lock -vv
...(中略)
   4: ! which is caused by "google-api-core (>=1.34.0,<2.0.dev0 || >=2.11.dev0,<2.11.0 || >=2.11.dev0,<2.14.0 || >2.14.0,<3.0.0dev) requires grpcio-status (>=1.49.1,<2.0dev) or google-api-core (1.34.0)"
   4: ! thus: google-api-core (>=1.32.0,<2.0.dev0 || >=2.8.dev0,<2.8.0 || >=2.8.dev0,<2.8.0 || >=2.8.dev0,<2.8.0 || >=2.8.dev0,<2.8.0 || >=2.8.dev0,<2.11.0 || >=2.11.dev0,<2.11.0 || >=2.11.dev0,<2.11.0 ...
...
```

ログが多すぎるので必要な箇所以外を省略しています。ログの内容的に `google-api-core` の周辺で依存関係の解決に苦労していそうな雰囲気を感じます。

続いて必要と思われるライブラリを明示的に add していきます。

# 原因と思われるライブラリを `poetry add` する

まず `google-api-core` を `poetry add` してから `poetry lock` をしてみます。

```shell
$ poetry add google-api-core
$ poetry lock
...(中略)
   4: ! which is caused by "google-api-core (>=1.34.0,<2.0.dev0 || >=2.11.dev0,<2.11.0 || >=2.11.dev0,<2.14.0 || >2.14.0,<3.0.0dev) requires grpcio-status (>=1.49.1,<2.0dev) or google-api-core (1.
34.0)"
   4: ! thus: google-api-core (>=1.32.0,<2.0.dev0 || >=2.8.dev0,<2.8.0 || >=2.8.dev0,<2.8.0 || >=2.8.dev0,<2.8.0 || >=2.8.dev0,<2.8.0 || >=2.8.dev0,<2.11.0 || >=2.11.dev0,<2.11.0 || >=2.11.dev0,<2
.11.0 || >=2.11.dev0,<2.11.0
...
```


うーん、終わらない。更に `grpcio-status` を add してから `poetry lock` をします。

```shell
$ poetry add grpcio-status
$ poetry lock
...(中略)
   1: fact: googleapis-common-protos (1.61.0) depends on grpcio (>=1.44.0,<2.0.0.dev0)
   1: selecting googleapis-common-protos[grpc] (1.61.0)
   1: fact: proto-plus (1.22.3) depends on protobuf (>=3.19.0,<5.0.0dev)
   1: selecting proto-plus (1.22.3)
   1: selecting attrs (23.1.0)
   1: selecting colorama (0.4.6)
   1: Version solving took 0.904 seconds.
   1: Tried 1 solutions.

Writing lock file
```

終わりました。一旦結論に記載した手順を踏むことで無事に lock できました。


:::note warn
確かに lock はできましたが、この過程で `kfp` のバージョンが元々 add した時から下がって `kfp==1.4.0` がインストールされてしまっています。これでも動くのであれば問題ありませんが、バージョンを指定する際は極力バージョンのレンジが狭くなるように指定しましょう。
:::


# 再度結論
`Resolving dependencies...` が終わらない場合は `poetry lock` に `-vv` オプションを加えて原因となるライブラリを特定しましょう。そこからの対処は上記手順をご確認ください。