pythonの依存関係管理ツールpoetryの基本的な使い方と注意点
はじめに
2020/10時点でのpoetryのごく基本的な使い方を記載します。poetryと他依存関係ツールの違いや、より詳細な使い方は他の方が書いた記事や公式ドキュメントがあるのでそちらを参照ください。
動作確認環境
OS:macOS Catalina v10.15.4
poetry:v1.0.8
poetryのインストール
インストール
curl -sSL https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py | python
初期設定
以下のコマンドを打つと、poetryが作成する仮想環境(.venvフォルダ)がpoetryを使ってパッケージ管理を行うプロジェクトの直下に作成されるようになります。
poetry config virtualenvs.in-project true
これが何故必要かというと、vscodeを使用する際、この設定をしていない場合はいちいち仮想環境のpathをvscodeのsettings.jsonに書き加えるなど仮想環境をvscodeに認識させるための手順が必要になってしまいますが、最初にこの設定をしておけばその手間を省くことができます。
プロジェクトへのpoetry導入
導入
以下のコマンドを打つとパッケージ一覧を管理するpyproject.toml
が直下に作成されます。
poetry init
対話式でいくつかプロジェクトの名称やauthor等について質問されますので、適宜答えてください。とりあえずエンター連打でもまぁ良いです。
プロジェクトを開始する際、poetry new
としても良いのですが、こちらのコマンドではディレクトリやREADMEまで作ってくれてしまいます。ディレクトリ構造等は自前で作りたい場合が多いと思いますので、poetry init
で良いと思います。
パッケージの追加
poetry init
で作成されたpyproject.toml
に使用するライブラリの情報を書き込みつつ、仮想環境へのインストールを行います。
# とりあえず最新のものがあれば良い場合
poetry add <パッケージ名>
# バージョン指定も可能
poetry add "pendulum>=2.0.5"
# gitからも取ってこれる
poetry add git+https://github.com/sdispater/pendulum.git
パッケージの削除
pyproject.toml
からライブラリを削除し、仮想環境からも削除します。
poetry remove <パッケージ名>
仮想環境を使ってコマンドを実行
poetry run <コマンド>
# 例えば、poetryを使って入れたパッケージを有効化した状態で、poetryで入れたjupyterlabを立ち上げたい時
poetry run jupyter lab
パッケージのupdate
# 一部のパッケージのみアップデートする場合
poetry update <パッケージ名>
# 全てのパッケージをアップデートする場合
poetry update
pyproject.toml
記載のパッケージをインストールする場合
他人が作ったpyproject.toml
から一括でパッケージをインストールしたい場合などに使用
poetry install
poetry自体のアップデート
※検索するとたまに出てくる、poetry self:update
はv1.0以前のpoetryのコマンドのようなので、現在は以下コマンドを使用してください。
poetry self update
注意点
パッケージ名の指定
poetry init
時に指定するパッケージ名を、poetry add
でインストールしたいパッケージ名と同一にすると以下のエラーが出る場合があります。
[tool.poetry]
name = "kedro"
❯ poetry add kedro
Using version ^0.16.1 for kedro
Updating dependencies
Resolving dependencies... (0.0s)
[AssertionError]
この場合、name = "kedro_practice"
など、別のものに変えてあげれば正常にインストールできるようになります。
参考issue:https://github.com/python-poetry/poetry/issues/1295
pythonバージョンの指定
poetry init
を行う際に特別設定をしなければ、poetryが想定するpythonのバージョンについてpyproject.toml
に以下のように記載されます。
[tool.poetry.dependencies]
python = "^3.8"
^3.8が何を意味するかと言うと、3.8<=pythonのバージョン<4.0です。左端のメジャーバージョンを表す数値が変わらない最大のバージョンまで想定するというバージョン指定になります。(詳細な情報は公式ドキュメントを見てください。)
poetry add
等でパッケージのインストールを行う際、poetryは導入パッケージがpyproject.toml
で設定されているpythonのバージョンで使用できるかどうか判定を行いますが、その判定対象のpythonのバージョンは想定される全てのバージョンになります。つまり、上記の例だと、「3.8<=pythonのバージョン<4.0」を満たす全てのバージョン、つまりv3.8とv3.9が判定対象になります。
例えばkedroというパッケージは2020/06/07現在で対応するpythonのバージョンが3.6
,3.7
,3.8
で、3.9
には対応していません。
pyproject.toml
の[tool.poetry.dependencies]
欄にpython = "^3.8"
と記載した状態でこういったパッケージをpoetry add
しようとすると、以下のエラーが発生します。
[SolverProblemError]
The current project's Python requirement (^3.8) is not compatible with some of the required packages Python requirement:
- kedro requires Python >=3.6, <3.9
Because no versions of kedro match >0.16.1,<0.17.0
and kedro (0.16.1) requires Python >=3.6, <3.9, kedro is forbidden.
So, because kedro-test depends on kedro (^0.16.1), version solving failed.
バージョン3.8にしてるじゃん!なんでダメなの?!と時間をつぶす羽目になります。
解決策としては、v3.8のみを想定するpythonのバージョンとするよう、以下のようにpyproject.toml
を記載する必要があります。
[tool.poetry.dependencies]
python = "^3.8,<3.9"
#もしくは
python = "=3.8"
より詳細な情報が欲しい方は、poetryのgithubのissueを追ってみてください。
パッケージのupdate
上にパッケージのupdateはpoetry update <パッケージ名>
でできると書きましたが、
このコマンドでupdateできるのはpyproject.toml
に記載されているバージョン指定の範囲内までとなります。
poetry add numpy
でパッケージを導入した場合、pyproject.toml
にはnumpy = "^1.18.2"
と記載され、「1.18.2<=numpyのバージョン<2.0」が指定されます。(詳細な情報は公式ドキュメントを見てください。)
このため、メジャーバージョンのアップデートを行いたい場合、
-
pyproject.toml
を直接編集してからpoetry update <パッケージ名>
をする
か、面倒な場合は -
poetry add <パッケージ名>@latest
を行う必要があります。
バージョン競合メッセージが出た時
パッケージを入れようとしたところ、以下のようなパッケージ間での依存パッケージの競合エラーが出て入れられない場合がある。
以下の例では先にboto3が入っている環境に対しs3fsというパッケージを入れようとしている。
先に入っているboto3が(>=1.19.43,<1.20.0)のbotocoreを使っているのに対し、現在入れようとしているs3fsが(>=1.15.32,<1.15.33 || >=1.17.44,<1.17.45)のbotocoreを必要としており、boto3とs3fsを両立させられないのでパッケージを導入できないと怒られている。
> poetry add s3fs@latest
[SolverProblemError]
...省略
Because no versions of s3fs match >0.5.2,<0.6.0
and s3fs (0.5.2) depends on aiobotocore (>=1.0.1), s3fs (>=0.5.2,<0.6.0) requires aiobotocore (>=1.0.1).
Thus, s3fs (>=0.5.2,<0.6.0) requires botocore (>=1.15.32,<1.15.33 || >=1.17.44,<1.17.45).
And because boto3 (1.16.43) depends on botocore (>=1.19.43,<1.20.0)
and no versions of boto3 match >1.16.43,<2.0.0, s3fs (>=0.5.2,<0.6.0) is incompatible with boto3 (>=1.16.43,<2.0.0).
So, because g-e depends on both boto3 (^1.16.43) and s3fs (^0.5.2), version solving failed.
今回の場合、s3fsの最新バージョンでも(>=1.15.32,<1.15.33 || >=1.17.44,<1.17.45)と比較的古いバージョンのbotocoreを使っているため、boto3とs3fsを両立させるにはboto3のバージョンを(>=1.15.32,<1.15.33 || >=1.17.44,<1.17.45)に合致するようなbotocoreを使っているバージョンまで下げなければならない。
(>=1.15.32,<1.15.33 || >=1.17.44,<1.17.45)に合致するバージョンのbotocoreを使っているboto3のバージョンを調査するのは骨が折れる仕事のため、poetryにやらせたい。
このような場合、まずboto3をアンインストールし、先にs3fsを入れてboto3を入れ直すようにすれば、poetryが自動でs3fsと両立できるboto3のバージョンを調べてインストールしてくれる。
気をつける必要があるのはboto3を再インストールする時のバージョン指定方法で、poetry add boto3
と打つとboto3の最新バージョン(1.16.43)をインストールするように命令していることになり、poetryはboto3の最新バージョンについてしかインストールを試みてくれず、インストールに失敗する。
このため、poetry add "boto3<1.16.43"
のように指定することで、boto3の最新バージョン(1.16.43)以下で依存関係に問題が無いバージョンを探させることができる。
# 現在入っているboto3をアンインストール
poetry remove boto3
# s3fsの最新バージョンをインストール
poetry add s3fs@latest
# s3fsと競合しないboto3のバージョンをインストール
poetry add "boto3<1.16.43"
結果、この場合はboto3のv1.14.44がインストールされた。
❯ poetry add "boto3<1.16.43"
Updating dependencies
Resolving dependencies... (12.9s)
Writing lock file
Package operations: 2 installs, 0 updates, 0 removals
- Installing s3transfer (0.3.3)
- Installing boto3 (1.14.44)
さいごに
本記事では触れていませんが、pyenvと組み合わせて使うといい感じです。pipよりだいぶ快適なので、ぜひ使ってみてください。
Discussion