年末年始なんで、2020年にやり残した事を勉強していこうと思います。 今日は最近だんだん聞くようになってきたPoetryについて勉強していきたいと思います。
poetry is 何?
Pythonのパッケージとその依存関係の管理を良い感じにやってくれるライブラリです。
誰しも一度はPythonのライブラリの依存関係に躓くと思います(偏見?)。その経験から、Pipenvなどで仮想環境でPythonプロジェクトを作成している方が多いのではないでしょうか? そういったライブラリの管理から仮想環境の構築までまるっとやってくれるのがPoetryというイメージです。
使ってみる
この辺読みながらやっていきたいと思います。
install
何はともあれインストールです。
OSXやlinux系では下記のようなインストールが推奨されています。
curl -sSL https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py | python -
これでとりあえずインストールはできるようです。 PATHが通ってたり通ってなかったりするので、必要に応じて下記のようなコマンドを入れてください。
source $HOME/.poetry/env
インストールはこれだけです。 本家のページ見てると、python-pipでインストールするのは非推奨のようです。
Using alternative installation methods will make Poetry always use the Python version for which it has been installed to create virtualenvs.
So, you will need to install Poetry for each Python version you want to use and switch between them. Introduction | Documentation | Poetry - Python dependency management and packaging made easy.
この辺は自己責任でやったら良いと思います。
projectを作る
新しくプロジェクトを作るときにはこんな感じに書くと作れます。
poetry new poetry-demo
するとこんな感じのファイルが作成されます。
poetry-demo ├── README.rst ├── poetry_demo │ └── __init__.py ├── pyproject.toml └── tests ├── __init__.py └── test_poetry_demo.py
この辺はふーんって感じですね。
既存プロジェクトに導入する
すでにあるプロジェクトに導入するときはこんな感じになるそうです。
poetry init
こんな感じで対話形式で色々聞かれるので答えていきます。
This command will guide you through creating your pyproject.toml config. Package name [project]: sample Version [0.1.0]: Description []: Author [None, n to skip]: expected string or bytes-like object Author [None, n to skip]: None License []: MIT Compatible Python versions [^3.6]: Would you like to define your main dependencies interactively? (yes/no) [yes] You can specify a package in the following forms: - A single name (requests) - A name and a constraint (requests@^2.23.0) - A git url (git+https://github.com/python-poetry/poetry.git) - A git url with a revision (git+https://github.com/python-poetry/poetry.git#develop) - A file path (../my-package/my-package.whl) - A directory (../my-package/) - A url (https://example.com/packages/my-package-0.1.0.tar.gz) Search for package to add (or leave blank to continue): Would you like to define your development dependencies interactively? (yes/no) [yes] Search for package to add (or leave blank to continue): Generated file [tool.poetry] name = "sample" version = "0.1.0" description = "" authors = ["None"] license = "MIT" [tool.poetry.dependencies] python = "^3.6" [tool.poetry.dev-dependencies] [build-system] requires = ["poetry-core>=1.0.0"] build-backend = "poetry.core.masonry.api" Do you confirm generation? (yes/no) [yes]
すると、pyproject.tomlが生成されて準備は完了になります。
依存関係の作成
この辺からだんだんパッケージ管理っぽくなります。 下記のコマンドで依存関係を管理するpoetry.lockファイルを作成します。
poetry install
このときできるpoetry.lockの中にに依存関係が記述されていきます。
はじめはこんな感じになるんですかね。
package = [] [metadata] lock-version = "1.1" python-versions = "^3.6" content-hash = "17c1e11746ee765c3e36efba80e87b60732cec9c19c2cb56f7da9e92297ecee1" [metadata.files]
パッケージの追加
試しにnumpyを入れてみます。
poetry add numpy
すると仮想環境上でnumpyがインストールされます。
pyproject.tomlの中を見てみると、
[tool.poetry] name = "sample" version = "0.1.0" description = "" authors = ["None"] license = "MIT" [tool.poetry.dependencies] python = "^3.6" numpy = "^1.19.4" [tool.poetry.dev-dependencies] [build-system] requires = ["poetry-core>=1.0.0"] build-backend = "poetry.core.masonry.api"
先程はなかったnumpyに関する記載が増えていますね。
poetry.lockを確認するとこんな感じ。
[[package]] name = "numpy" version = "1.19.4" description = "NumPy is the fundamental package for array computing with Python." category = "main" optional = false python-versions = ">=3.6" [metadata] lock-version = "1.1" python-versions = "^3.6" content-hash = "17c1e11746ee765c3e36efba80e87b60732cec9c19c2cb56f7da9e92297ecee1" [metadata.files] numpy = [ {file = "numpy-1.19.4-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:e9b30d4bd69498fc0c3fe9db5f62fffbb06b8eb9321f92cc970f2969be5e3949"}, {file = "numpy-1.19.4-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:fedbd128668ead37f33917820b704784aff695e0019309ad446a6d0b065b57e4"}, {file = "numpy-1.19.4-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:8ece138c3a16db8c1ad38f52eb32be6086cc72f403150a79336eb2045723a1ad"}, {file = "numpy-1.19.4-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:64324f64f90a9e4ef732be0928be853eee378fd6a01be21a0a8469c4f2682c83"}, {file = "numpy-1.19.4-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:ad6f2ff5b1989a4899bf89800a671d71b1612e5ff40866d1f4d8bcf48d4e5764"}, {file = "numpy-1.19.4-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:d6c7bb82883680e168b55b49c70af29b84b84abb161cbac2800e8fcb6f2109b6"}, {file = "numpy-1.19.4-cp36-cp36m-win32.whl", hash = "sha256:13d166f77d6dc02c0a73c1101dd87fdf01339febec1030bd810dcd53fff3b0f1"}, {file = "numpy-1.19.4-cp36-cp36m-win_amd64.whl", hash = "sha256:448ebb1b3bf64c0267d6b09a7cba26b5ae61b6d2dbabff7c91b660c7eccf2bdb"}, {file = "numpy-1.19.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:27d3f3b9e3406579a8af3a9f262f5339005dd25e0ecf3cf1559ff8a49ed5cbf2"}, {file = "numpy-1.19.4-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:16c1b388cc31a9baa06d91a19366fb99ddbe1c7b205293ed072211ee5bac1ed2"}, {file = "numpy-1.19.4-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:e5b6ed0f0b42317050c88022349d994fe72bfe35f5908617512cd8c8ef9da2a9"}, {file = "numpy-1.19.4-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:18bed2bcb39e3f758296584337966e68d2d5ba6aab7e038688ad53c8f889f757"}, {file = "numpy-1.19.4-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:fe45becb4c2f72a0907c1d0246ea6449fe7a9e2293bb0e11c4e9a32bb0930a15"}, {file = "numpy-1.19.4-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:6d7593a705d662be5bfe24111af14763016765f43cb6923ed86223f965f52387"}, {file = "numpy-1.19.4-cp37-cp37m-win32.whl", hash = "sha256:6ae6c680f3ebf1cf7ad1d7748868b39d9f900836df774c453c11c5440bc15b36"}, {file = "numpy-1.19.4-cp37-cp37m-win_amd64.whl", hash = "sha256:9eeb7d1d04b117ac0d38719915ae169aa6b61fca227b0b7d198d43728f0c879c"}, {file = "numpy-1.19.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:cb1017eec5257e9ac6209ac172058c430e834d5d2bc21961dceeb79d111e5909"}, {file = "numpy-1.19.4-cp38-cp38-manylinux1_i686.whl", hash = "sha256:edb01671b3caae1ca00881686003d16c2209e07b7ef8b7639f1867852b948f7c"}, {file = "numpy-1.19.4-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:f29454410db6ef8126c83bd3c968d143304633d45dc57b51252afbd79d700893"}, {file = "numpy-1.19.4-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:ec149b90019852266fec2341ce1db513b843e496d5a8e8cdb5ced1923a92faab"}, {file = "numpy-1.19.4-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:1aeef46a13e51931c0b1cf8ae1168b4a55ecd282e6688fdb0a948cc5a1d5afb9"}, {file = "numpy-1.19.4-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:08308c38e44cc926bdfce99498b21eec1f848d24c302519e64203a8da99a97db"}, {file = "numpy-1.19.4-cp38-cp38-win32.whl", hash = "sha256:5734bdc0342aba9dfc6f04920988140fb41234db42381cf7ccba64169f9fe7ac"}, {file = "numpy-1.19.4-cp38-cp38-win_amd64.whl", hash = "sha256:09c12096d843b90eafd01ea1b3307e78ddd47a55855ad402b157b6c4862197ce"}, {file = "numpy-1.19.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:e452dc66e08a4ce642a961f134814258a082832c78c90351b75c41ad16f79f63"}, {file = "numpy-1.19.4-cp39-cp39-manylinux1_i686.whl", hash = "sha256:a5d897c14513590a85774180be713f692df6fa8ecf6483e561a6d47309566f37"}, {file = "numpy-1.19.4-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:a09f98011236a419ee3f49cedc9ef27d7a1651df07810ae430a6b06576e0b414"}, {file = "numpy-1.19.4-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:50e86c076611212ca62e5a59f518edafe0c0730f7d9195fec718da1a5c2bb1fc"}, {file = "numpy-1.19.4-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:f0d3929fe88ee1c155129ecd82f981b8856c5d97bcb0d5f23e9b4242e79d1de3"}, {file = "numpy-1.19.4-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:c42c4b73121caf0ed6cd795512c9c09c52a7287b04d105d112068c1736d7c753"}, {file = "numpy-1.19.4-cp39-cp39-win32.whl", hash = "sha256:8cac8790a6b1ddf88640a9267ee67b1aee7a57dfa2d2dd33999d080bc8ee3a0f"}, {file = "numpy-1.19.4-cp39-cp39-win_amd64.whl", hash = "sha256:4377e10b874e653fe96985c05feed2225c912e328c8a26541f7fc600fb9c637b"}, {file = "numpy-1.19.4-pp36-pypy36_pp73-manylinux2010_x86_64.whl", hash = "sha256:2a2740aa9733d2e5b2dfb33639d98a64c3b0f24765fed86b0fd2aec07f6a0a08"}, {file = "numpy-1.19.4.zip", hash = "sha256:141ec3a3300ab89c7f2b0775289954d193cc8edb621ea05f99db9cb181530512"}, ]
こんな感じでパッケージの追加と同時に依存関係が記録されていくみたいです。
実行する
仮想環境内での実行をやってみます。
if __name__ == "__main__": print("hello")
こんな感じ。
root@f9c0ede0dd7a:/home/project# poetry run python sample.py hello
ちゃんと実行できてますね。
そんでもってnumpyが入っているか確認します。
import numpy as np if __name__ == "__main__": print(np.pi)
これを実行すると
root@f9c0ede0dd7a:/home/project# poetry run python sample.py 3.141592653589793
となって、ちゃんとnumpyが入った環境で実行されていることがわかります。
ちなみに仮想環境外で普通に実行すると、
root@f9c0ede0dd7a:/home/project# python3 sample.py Traceback (most recent call last): File "sample.py", line 1, in <module> import numpy as np ModuleNotFoundError: No module named 'numpy'
となってちゃんとエラーが出てくれたので、ちゃんと仮想環境内だけに閉じていることが確認できます。
管理の対象
基本的には.lockファイルは依存関係を記録しているだけなので、これを削除しても復元することができます。
root@f9c0ede0dd7a:/home/project# ls poetry.lock pyproject.toml sample.py root@f9c0ede0dd7a:/home/project# rm poetry.lock root@f9c0ede0dd7a:/home/project# ls pyproject.toml sample.py root@f9c0ede0dd7a:/home/project# poetry install Updating dependencies Resolving dependencies... (0.1s) Writing lock file No dependencies to install or update Installing the current project: sample (0.1.0) root@f9c0ede0dd7a:/home/project# ls poetry.lock pyproject.toml sample.py
こんな感じで、poetry installでまた.lockファイルを作成できるんですね。
ドキュメントにも
For your library, you may commit the poetry.lock file if you want to. This can help your team to always test against the same dependency versions. However, this lock file will not have any effect on other projects that depend on it. It only has an effect on the main project.
If you do not want to commit the lock file and you are using git, add it to the .gitignore.
と書かれているので、Lockファイルは管理しなくても問題ないように思っています。
パッケージング
最後、仮想環境にインストールしたものをまるっとパッケージングしたいとき(PyPIに公開したいときとか)もコマンドで一発です。
root@f9c0ede0dd7a:/home/project# poetry build Building sample (0.1.0) - Building sdist - Built sample-0.1.0.tar.gz - Building wheel - Built sample-0.1.0-py3-none-any.whl
作成ファイルを確認してみるとこんな感じになってます。
. ├── dist │ ├── sample-0.1.0-py3-none-any.whl │ └── sample-0.1.0.tar.gz ├── poetry.lock ├── pyproject.toml └── sample.py 1 directory, 5 files
こんな感じでdistディレクトリにパッケージングされたものが入っています。
あとは、publishするコマンドがあるので、そちらでPyPIに公開できたりするみたいです。
参考文献
下記の記事を参考にさせていただきました。
感想
2020年にちょいちょいPoetryの話題を見かけたので多分流行っているんだと思いますし、これから作るものについてはPoetryを使っていくんだろうなーとか思ったので、使ってみた次第です。 なんだか自分にはPipenvでも十分そうではありますがこういう流行りには乗っておいた方がいいかと思うので、これから作るものについてはPoetryを使っていきたいと思いました。