どこにでもいるSEの備忘録

たぶん動くと思うからリリースしようぜ

Poetryを使ってみたメモ

f:id:nogawanogawa:20201227153840j:plain
 

年末年始なんで、2020年にやり残した事を勉強していこうと思います。 今日は最近だんだん聞くようになってきたPoetryについて勉強していきたいと思います。

poetry is 何?

Pythonのパッケージとその依存関係の管理を良い感じにやってくれるライブラリです。

python-poetry.org

誰しも一度はPythonのライブラリの依存関係に躓くと思います(偏見?)。その経験から、Pipenvなどで仮想環境でPythonプロジェクトを作成している方が多いのではないでしょうか? そういったライブラリの管理から仮想環境の構築までまるっとやってくれるのがPoetryというイメージです。

使ってみる

この辺読みながらやっていきたいと思います。

python-poetry.org

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に公開できたりするみたいです。

参考文献

下記の記事を参考にさせていただきました。

ohke.hateblo.jp

kk6.hateblo.jp

qiita.com

感想

2020年にちょいちょいPoetryの話題を見かけたので多分流行っているんだと思いますし、これから作るものについてはPoetryを使っていくんだろうなーとか思ったので、使ってみた次第です。 なんだか自分にはPipenvでも十分そうではありますがこういう流行りには乗っておいた方がいいかと思うので、これから作るものについてはPoetryを使っていきたいと思いました。