rcmdnk's blog

20190204_poetry_200_200

Pythonのパッケージ管理といえばpipが一般的ですが、pipでインストールできるパッケージは PyPIで管理されています。 ここには誰でもパッケージを登録することができますが、実際にアップロードするには 色々と体裁を整える必要があります。 特にコマンドラインツールを作ろうと思うと一工夫必要です。

その点、Poetryを使うと設定項目を自分でほとんど書くことなくPyPI用 パッケージを作りアップロードすることができます。

Poetry

Poetry - Python dependency management and packaging made easy.

PoetryはPythonのプロジェクトの依存関係などを管理するためのツール。

PyPIなどにパッケージを登録する際にはsetup.pyとかrequirements.txtとか 色々と用意しないといけないものがあります。

それらを自分で用意するのはとても大変で、大概はどこかにある例をとりあえずコピーして、 みたいに始めると思いますがそれでも調整するのが大変だったりします。

Poetryではpyproject.tomlというファイルでパッケージ管理を行いますが、 まずディレクトリ構造を含め雛形を用意してくれて pyproject.tomlの雛形も用意されます。 また、依存関係のあるパッケージ等の追加がコマンドから自動でできる様になっていたりして ほとんど自分で設定ファイルを書くことなく進めていくことができます。

また、パッケージを管理するとともに、そこにvirtualenvの環境を自動で作ります。 これによりその場で依存関係のパッケージをインストールして 必要な環境下でのテストが可能になります。

インストール

スクリプトget-poetry.py

インストールはGitHubにあるスクリプトを使って

$ curl -sSL https://raw.githubusercontent.com/sdispater/poetry/master/get-poetry.py | python

もしcurlで直接やるのが憚れる場合はスクリプトをダウンロードして ももちろんできます。

$ wget https://raw.githubusercontent.com/sdispater/poetry/master/get-poetry.py
$ cat get-poetry.py
....
$ python get-poetry.py

この方法でインストールすると$HOMEディレクトリに~/.poetry/というディレクトリができ、 ~/.poetry/bin/poetryという実行ファイルがインストールされます。

また、UNIX系の場合には

export PATH="$HOME/.poetry/bin:$PATH"

という行が自動で~/.bash_profileまたは~/.profileなどに追加される様になっています。

これに関して、最初に

Before we start, please answer the following questions.
You may simply press the Enter key to leave unchanged.
Modify PATH variable? ([y]/n)

と聞かれるのですが、ここでnまたはnoとか入れても メッセージが変わるだけで(PATHに入れてください、というのが出るようになる) ~/.bash_profile等への書き込みは行われてしまいます。

バグですが、簡単に治るところだと思ってPull Requestしようとしたら すでにありました。

Fix PATH being altered after installation even though choose not to by tdloi · Pull Request #78 sdispater/poetry

IssuesもPull Requestsも大量に貯まっていてさばききれてない感が。。。

ともあれ、.bash_profileとかに余計なものを入れたくない人はちょっと注意が必要です。

自分の環境では.bash_profileに追加されたものを消して

if [ -f $HOME/.poetry/env ];then
  source $HOME/.poetry/env
fi

といった行を.bashrcに書いています。

アンインストールする場合には

$ wget https://raw.githubusercontent.com/sdispater/poetry/master/get-poetry.py

とかでget-poetry.pyを取ってきて

$ python get-poetry.py --uninstall

とします。これをすると~/.poetryを削除し、~/.bash_profileなどにpoetryのexport行があると それを削除します。

これも勝手に.bash_profileをいじるのでちょっと注意が必要です。

pip

pipを使ってもインストールできます。

$ pip install poetry

またはユーザーレベルで

$ pip install --user poetry

後者の場合は~/Library/Python/2.7/bin(Mac)や~/.local/binなどに インストールsれるのでそれらをPATHに入れておく必要があります。

ただし、これで入れるとpipでpoetryが依存するパッケージを入れることになり それが余計なことをする可能性があるのでスクリプトでインストールする方がおすすめされています。

こちらのアンインストールは

$ pip uninstall poetry

補完

poetryコマンドではサブコマンドを与えていろいろと実行しますが、それを補完するためのファイルの内容を poetry completionで吐き出すことが出来ます。

$ poetry completion bash # for bash
$ poetry completion zsh # for zsh
$ poetry completion fish # for fish

これをシステムにそのまま入れたい場合には

$ poetry completions bash > /etc/bash_completion.d/poetry.bash-completion (Linux)
$ poetry completions bash > $(brew --prefix)/etc/bash_completion.d/poetry.bash-completion (Mac)
$ poetry completions fish > ~/.config/fish/completions/poetry.fish
$ poetry completions zsh > ~/.zfunc/_poetry

とかしてシステムの補完ファイルディレクトリに入れれれば良いですが、 自分用に

$ poetry completions bash >> ~/.bashrc

とかでも大丈夫です。(ただし結構長いので別ファイルにしたほうが良いかも。)

使い方

雛形作成

poetry new <package>で新たにパッケージの雛形を作れます。

$ poetry new --src rcmdnk-package
Created package rcmdnk-package in rcmdnk-package
$ ls
rcmdnk-package
$ cd rcmdnk-package/
$ tree
   |-- README.rst
   |-- pyproject.toml
   |-- src
   |    |-- rcmdnk_package
   |    |    |-- __init__.py
   |-- tests
   |    |-- __init__.py
   |    |-- test_rcmdnk_package.py
$ cat pyproject.toml
[tool.poetry]
name = "rcmdnk-package"
version = "0.1.0"
description = ""
authors = ["rcmdnk <[email protected]>"]

[tool.poetry.dependencies]
python = "^2.7"

[tool.poetry.dev-dependencies]
pytest = "^3.0"

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

ここで--srcオプションはパッケージ直下にrcmdnk_packageディレクトリを置かず srcを挟んで置くようにするためのオプション。

これがないとrcmdnk-package/rcmdnk_package/__init__.pyのような構造になります。

pytestなどを使う際などにこのsrcが入った構造が勧められていて 特に理由がない限り*src**入にしておいたほうが良いです。

Good Integration Practices — pytest documentation

Packaging a python library ionel’s codelog

pyproject.tomlの中にあるメールアドレス等はデフォルトでは~/.gitconfigのユーザー名、メールアドレスを取ってきているようで それがなければ[“Your Name [email protected]”]みたいになります。

このパッケージでは__init__.py

__version__ = '0.1.0'

というバージョン情報が入っていて、testの中では

test_rcmdnk_package.py
1
2
3
4
5
from rcmdnk_package import __version__


def test_version():
    assert __version__ == '0.1.0'

というpytest用のテストが用意されています。

install

雛形を作ったら、まず

$ poetry install
Creating virtualenv test-py2.7 in .../Library/Caches/pypoetry/virtualenvs
Updating dependencies
Resolving dependencies... (0.2s)
...

を実行してみます。 これでこのディレクトリ用のvirtualenv環境が作られ、 poetryを動かす上で最低限必要なパッケージ(pytestなど)がインストールされます。

pytest

テストは

$ poetry run pytest

で実行することが出来ます。これでtestsフォルダにある全てのtest_*.pyファイルの中身を実行します。

特定のファイルだけ実行したい場合には

$ poetry run pytest ./tests/test_rcmdnk_package.py

依存パッケージの追加/削除

依存パッケージを追加したい場合には

$ poetry add fire

の様にします。 これでvirtualenvの環境にパッケージが追加され、 また以下のように

[tool.poetry.dependencies]
python = "^2.7"
fire = "^0.1.3"

pyproject.tomldependenciesのセクションに追加されます。

このpyproject.tomlがあれば、別の環境でpoetry installをした時に ここにあるパッケージも同時にインストールされます。(python以外)

逆にここにパッケージを自分で書いてからpoetry installをしても 同じ状態になります。

逆に削除したい場合は

$ poetry remove fire

で出来ます。

現在インストールされているパッケージについては

$ poetry show

で見ることが出来ます。

コマンドラインツール(CLI)の作成

次の様なファイルを作ります。

src/rcmdnk_package/cli.py
1
2
3
4
5
6
def main():
    print("rcmdnk package test")


if __name__ == "__main__":
    main()

これを直接呼ぶにはpoetry runを使って

$ poetry run python src/rcmdnk_package/cli.py
rcmdnk package test

といった感じに呼べます。

これがパッケージとしてインストールされたとき、rcmdnk_cliという名前で呼ばれるようにするには pyproject.toml

[tool.poetry.scripts]
rcmdnk_cli = "rcmdnk_package.cli:main"

という行を追加します。

これで

$ poetry run rcmdnk_cli
rcmdnk package test

と同じ様にrcmdnk_cliだけで呼べる様になります。

poetry shell

poetry shelとするとvirtualenv環境に入って直接コマンドを使ったり出来るようになります。

$ poetry install # rcmdnk_cliなどもちゃんとインストールしておく
...
$ poetry shell
Virtual environment already activated: /Users/user/Library/Caches/pypoetry/virtualenvs/rcmdnk-package-py2.7
$ rcmdnk_cli
rcmdnk package test

パッケージのビルド

PyPIなどに登録するにはこの他色々と設定ファイルが必要ですが、 これは

$ poetry build

で作成することが出来ます。

これでdist/rcmdnk-package-0.1.0.tar.gzdist/rcmdnk_package-0.1.0-py2.py3-none-any.whlというファイルが作成されます。 rcmdnk-package-0.1.0.tar.gzを展開して中身を見てみるとPKG-INFOsetup.pyができてるのが分かります。

パッケージの登録

TestPyPIへの登録

これですでにパッケージを登録する準備が出来ましたが、 TestPyPI1というテスト用のレポジトリがあるので まずはそちらに上げてテストしてみます。

まずはTestPyPIのページにあるRegisterリンクからアカウント登録を行っておきます。

次に、poetryにレポジトリ情報を渡します。

$ poetry config repositories.testpypi https://test.pypi.org/legacy/

これでtestpypiという名前で登録が出来ました。

登録はpoetry publish -r testpypi で行います。

$ poetry publish -r testpypi

Publishing rcmdnk-package (0.1.0) to testpypi
Username: rcmdnk



Password:

 - Uploading rcmdnk-package-0.1.0.tar.gz 100%
 - Uploading rcmdnk_package-0.1.0-py2.py3-none-any.whl 100%

UsernameとPasswordを入力して rcmdnk-package · TestPyPI にアップロードできました。

これをインストールするには

$ pip install --index-url https://test.pypi.org/simple/ rcmdnk-package

の様に--index-urlhttps://test.pypi.org/simple/を指定します。 (最後のところが登録の部分ではlegacyなのに対してこちらではsimpleなことに注意)。

この登録のところで

$ poetry config http-basic.testpypi <username> <password>

と事前にユーザー名とパスワードを登録しておくと毎回それらを打たずに済みますが、 これらのファイルは平文で保存されるので人が見る可能性のあるシステムではできれば避けた方が良いです。

また、

$ poetry publish -r testpypi --username <username> --password <password>

publishコマンドに引数として渡すことも出来ます。

PyPIへの登録

PyPIのレポジトリはデフォルトとして登録されているので PyPIの方でアカウントを登録し(TestPyPIとは別)、

$ poetry publish

とすればPyPIの方へアップロードされます。

ビルドと登録を同時に行う

$ poetry publish --build

の様に--buildオプションを使うことでアップロード時にbuildを同時に行うことも出来ます。

設定ファイル

poetry configで加えた設定は以下のディレクトリに保存されています。

  • Linux: ~/.config/pypoetry
  • macOS: ~/Library/Application Support/pypoetry
  • Windows: C:\Users<username>\AppData\Roaming\pypoetry

repositoriesなどの情報はconfig.tomlhttp-basicの情報はauth.toml に保存されています。

config.tomlの情報はpoetry config --listでも見ることが出来ます。 (加えていくつかデフォルトの設定値も表示されます。)

設定を削除するにはこれらのファイルを削除するか

$ poetry config --unset http-basic.testpypi

の様に--unsetを使います。

pipでインストールされたCLIパッケージ

Macで

$ pip install --user --index-url https://test.pypi.org/simple/ rcmdnk-package

しました。 --userを使うと、Macでは**~/Library/Python//**に、 Linuxとかだと**~/.local/**などにインストールされます。

$ ls ~/Library/Python/2.7/bin/rcmdnk_cli
/Users/user/Library/Python/2.7/bin/rcmdnk_cli
$ ls ~/Library/Python/2.7/lib/python/site-packages/rcmdnk_package
__init__.py  __init__.pyc cli.py       cli.pyc
$

このrcmdnk_cliは自動でできたファイルですが、こんな内容

rcmdnk_cli
1
2
3
4
5
6
7
8
9
10
11
#!/usr/local/opt/python@2/bin/python2.7

# -*- coding: utf-8 -*-
import re
import sys

from rcmdnk_package.cli import main

if __name__ == '__main__':
    sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0])
    sys.exit(main())

設定ファイル: pyproject.toml

直接書く必要があるものとしては 最初の

[tool.poetry]
name = "rcmdnk-package"
version = "0.1.0"
description = ""
authors = ["rcmdnk <[email protected]>"]

の項目にあるdescription位。 GitHubのユーザー名とかから保管されていなければ(もしくは違うものを使いたければ)authorsも。

加えて

repository = "http://github.com/rcmdnk/rcmdnk_package"
homepage = "http://github.com/rcmdnk/rcmdnk_package"
readme = "READDME.md"
license = "Apache-2.0"
keywords = [...]

などを定義しておくと良いです。

readmeはデフォルトではREADME.rstでSphinx使うreStructuredText形式です。

変更したければreadmeの設定でmdにしても変換して PyPIのページで表示してくれます。

licenseSPDX License List にあるIdentifierを指定するとパッケージに自動で含めてくれます。

後はversionを必要に応じて更新していきます。 (その際、src/rcmdnk_package/__init__.pytests/test_rcmdnk_package.pyなどにある バージョンの更新も忘れずに。)

それから自動で作るとpoetry newしたときのPythonのバージョンのみに対応になりますが、変更したければ

[tool.poetry.dependencies]
python = "^2.7 || ^3.4"

の様に3系なども加えたりしておきます。

Dependency specification Documentation Poetry - Python dependency management and packaging made easy

エラー対処

No JSON object could be decoded

Macで使ってる時に

$ poetry build

[ValueError]
No JSON object could be decoded

build [-f|--format FORMAT]

というのが出る様になりました。runshellなどどのコマンドでも同じエラーが出ます。 唯一configだけが動いてる状態。

どうもconfigだけが動いている、ということからもvirtualenv環境がおかしくなってしまったようで、

$ rm -rf  /Users/user/Library/Caches/pypoetry/

としたら治りました(runコマンドなどを打つとvirtualenv環境を作り直していた)。

Sponsored Links
Sponsored Links

« Python Fireで簡単にサブコマンド付きのコマンドラインツールを作る Mac: gem installでYou don't have write permissions for the /Library/Ruby/Gems/2.3.0 directory »

}