はじめに
以前、pyenvとpyenv-virtualenvの自分流使い方という記事を書きました。その終わりの部分で「pyenv-virtualenv+pipをpoetryで置き換えられるんじゃないかな」と書いていたのですが、実際に試してみた結果をご紹介したいと思います。結論から言うと、pyenv-virtualenvとpipは使わなくなりました(笑)
Poetryとは
PoetryはPythonのパッケージマネージャの一つです。v1.0になったのが2019年末なのでまだまだ新しいツールです。pipと同じようにパッケージをpypiなどからダウンロードしてきてインストールすることができますが、それに加えて次のようなこともできます。
- パッケージ管理ファイルの生成・変更
- インストールされているパッケージのアップデート
- プロジェクトごとの仮想環境のセットアップ
- などなど...
他の言語だと、npm
yarn
(JavaScript)やcargo
(Rust)などのパッケージマネージャーがありますが、それらと同等のものがようやくPythonにも来たという感じです。
Poetryはそのように多機能であるわけですが、その裏返しとして「コマンドがたくさんあって難しそう」とか「自分はpipで困ってないし、requirements.txt
を自分でコントロールするのが好き」と言う方が少なからずいるかと思います。自分もその一人でしたが、実際使ってみると楽になる部分が多くあることに気が付きました。自分もまだ使い始めたばかりで全ての機能を使っているわけではないですが、それでもpipとpyenv-virtualenvを置き換えられると思ったので、とりあえず始めてみたい方のために、基本機能に絞って使い方をご紹介します。
Poetryのインストール
Mac、Linux、Windows(Bash)上でのインストールは次の一行でいけます。
curl -sSL https://install.python-poetry.org | python3 -
(Windows(Powershell)での導入方法はここにかかれているのですが、私はMacを使っているので残念ながら試せていません...)
Poetryを使う
利用する際の流れはこんな感じになります。
- Pythonのセットアップ
- プロジェクトのセットアップ
- 仮想環境のセットアップ
- 依存パッケージの追加
- 仮想環境で実行
1. Pythonのセットアップ
PoetryのインストールにPythonが必要なので既に入っている前提ですが、特定のバージョンを使いたい時にはpyenvを使ってインストールしておきます。pyenvのインストール方法はここを参照して下さい(pyenv-virtualenvは不要)。その上で、特定のバージョンのpythonを入れるには以下のようにします。
# インストールされているバージョンを確認
pyenv versions
# インストール可能なバージョンを表示
pyenv install --list
# 指定したバージョンをインストール
pyenv install <python-version>
# グローバルなデフォルトを指定したバージョンに変更
pyenv global <python-version>
2. プロジェクトのセットアップ
使いたいバージョンのPythonがセットアップされたら、次にPoetryのプロジェクト(パッケージ)をセットアップします。これには「新規に立ち上げる場合」と「既にあるプロジェクトをpoetry管理下に置く場合」の二通りあります。
新規に立ち上げる場合
まっさらな状態から新たにプロジェクトを作る場合は poetry new
を使います。
poetry new <project-name>
そうすると、<project-name>
ディレクトリ配下にファイルが幾つかできます。以下の例では "project_abc"というパッケージ名をつけています。
project_abc
├── README.rst
├── project_abc
│ └── __init__.py
├── pyproject.toml
└── tests
├── __init__.py
└── test_project_abc.py
Pythonパッケージの標準的なディレクトリ構成で自動的にファイルを作ってくれています。
-
REAME.rst ... そのプロジェクトの概要を記述するファイル。GitHubだとトップページにこれを表示してくれますね。中身は空ですが、拡張子が
.rst
になっていて reStructuredText というマークアップ言語で書くことが期待されています。reStructuredTextはMarkdownが流行る前からPython系のドキュメントで使われていた形式ですが、Markdownの方が得意という方はこれをREADME.md
に変えてしまっても良いかなと思います。なお、GitHubではREADME.rst
だったとしても問題なくレンダリングしてくれます。 -
project_abc/...
project_abc/
はこのパッケージのpythonソースコードを格納するディレクトリで、その元締めとして__init__.py
が作られています。ここではバージョンの定義だけがされています。 - pyproject.toml ... Poetryプロジェクトに関するメタデータや依存関係を記述するためのファイルです。TOMLという形式で書かれています。これに関しては後述します。
-
tests/ ...
tests/
はユニットテストを格納するディレクトリで、__init__.py
とバージョン番号を確認する簡単なテストがtest_project_abc.py
に書かれています。
既にあるプロジェクトをpoetry管理下に置く場合
既にソースコードを書き始めてしまった場合、あるいは既にpipなどで管理しているPythonのプロジェクトでpoetryを使い始める場合には poetry init
を使います。
cd project_xyz
poetry init
そうすると、対話的に色々と訊かれていくのでそれに答えていきます。英語ですがそれほど難しくないと思います。質問の後に[]
でデフォルト値が書かれているのでそれで良い場合は単にEnterを押すだけです。だいたいこんな感じ。
Package name [project_xyz]:
Version [0.1.0]:
Description []:
Author [John Doe <johnd@example.com>, n to skip]:
License []:
Compatible Python versions [^3.9]:
上から、パッケージ名、バージョン、説明文、著者、ライセンス、互換性のあるPythonのバージョン、です。
そしてこの後に "Would you like to define your main dependencies interactively? (yes/no) [yes]"と訊かれるのですが、これは「依存関係を今ここで登録する?」という問いですね。あとで一つ一つ poetry add
で追加することができるので no
でも良いのですが、yes
してみると、指定の仕方の説明が出てきたり、名前を入れると似たような名前のものをサジェストしてくれたり、一回やってみると面白いかも知れません。追加するものがない時には何も入れずにEnter押すと次に進みます。
で終わりかと思いきや、また "Would you like to define your development dependencies interactively? (yes/no) [yes]" と訊かれます。あれ、また同じこと訊かれている?と思うのですが、よく見るとさっきのは "main dependencies"でこちらは "development dependencies"です。何が違うかと言うと、mainの方はそのパッケージが動作するのに必要な依存パッケージを登録し、developmentの方は本番動作に必要ないけど開発する時には必要なパッケージを登録します。後者は、例えばpytest
などのテストフレームワークや flake8
, black
などのリンター、フォーマッターなどですね。パッケージを使うだけの人にとってはそれらのフレームワークやツールは不要なので、developmentの依存関係として登録しておいて、インストール時にそれを省ける様になっています。
これを終えると、「これで良い?」と今まで入力したものの確認がされて、Enter押すと完了です。そして、カレントディレクトリに pyproject.toml
ができていると思います。init
の場合は既に色々作られているという前提なのでnew
の時のような他のファイルは作られません。
pyproject.toml
poetry new
やpoetry init
した時にできるpyproject.toml
ですが、これはPEP-518で定義されたPython標準のフォーマットです。そのため、poetryだけではなく、例えば最近のpipでもこのファイルを参照してパッケージのビルド・インストールができたりしますし、今後対応するツールがもっと出てくるでしょう。これまでは setup.py
とrequirements.txt
に同じような情報をコピーして持たなければならなかったのが、pyproject.toml
に集約された感じですね。
以下は生成されたpyproject.toml
の例です。
[tool.poetry]
name = "project_abc"
version = "0.1.0"
description = ""
authors = ["John Doe <johnd@example.com>"]
[tool.poetry.dependencies]
python = "^3.9"
[tool.poetry.dev-dependencies]
pytest = "^5.2"
[build-system]
requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api"
3. 仮想環境のセットアップ
前の手順でPoetryのセットアップが終わったので、次にこのプロジェクト用の仮想環境を立ち上げます。それには
poetry install
とします。
引数無しで起動すると、まずは ./.venv
というディレクトリ配下に仮想環境のセットアップを行い、そこに、pyproject.toml
に書かれた依存関係(mainとdevelopmentの双方)のパッケージをインストールしていきます。先ほど、poetry new
で作ったproject_abc
で実行してみると、pytest
がデフォルトでdevelopment依存関係に入っているので、それがインストールされたかと思います。
また、もしdevelopmentの依存関係が不要であれば、
poetry install --no-dev
とすることもできます。
4.依存パッケージの追加
poetry new
した場合やpoetry init
で依存関係の追加をスキップした場合は、必要なパッケージの追加をする必要があります。また、開発途中で必要に応じて依存パッケージを追加することもよくあります。そんな時にはpoetry add
を使います。
poetry add <package-name>
pip同様に指定したパッケージだけでなく、それが依存しているパッケージも合わせてインストールしてくれます。そして、pyproject.toml
にインストールしたパッケージをバージョンとともに追加してくれます。
[tool.poetry.dependencies]
python = "^3.9"
requests = "^2.26.0"
ここでバージョン番号に ^
という記号が付いていると思いますが、これは許容するバージョンの範囲を示すものです。例えば^2.26.0
であれば、2.26.0 <= version < 3.0.0
の範囲でアップップグレード可能ということになります。ここで用いているのは Semantic Versionという考え方で、バージョンは major.minor.patch
という形で、minor
とpatch
は値が上がっても後方互換性は維持するということになっています。したがって、この場合だと、major
バージョンの2
が維持される限りアップグレードしても問題は起こらない前提を置くことができます。このように、バージョンを範囲で指定でできるので、新しいバージョンが出る度に pyproject.toml
を変更しなくても良いということになります。
ただ、そうすると実際に使っている依存パッケージのバージョンが曖昧になってしまうという問題があります。上の例だと、ある人は2.26.0
を使い続け、また別の人はその後にリリースされた2.27.0
を使っているということが起こりえます。その問題を解決するために poetry.lock
というファイルがあります。
poetry.lock
はpoetryが自動的に生成するファイルの一つです。実は上で poetry install
した時に既に作られていました。ここに何が書いてあるかというと、今現在仮想環境にインストールされているパッケージのリストとそのバージョンです。pyproject.toml
で指定されているものだけでなく、それらが依存しているパッケージも含まれています。
そして、poetry.lock
ファイルがある場合には、poetry install
はそちらを先に見に行きます。したがって、例えば pyproject.toml
に^2.26.0
と書いてあって、poetry.lock
に version="2.27.0"
と書いてあれば、2.27.0
がインストールされることになります。チーム開発している場合は、poetry.lock
をバージョン管理化に置いて、リポジトリにコミットすれば、チームメンバー全員が同じバージョンのパッケージを使って開発をすることが出来ます。
インストールされているパッケージのアップグレード(バージョンアップ)を行いたい時には poetry update
を使います。
poetry update --dry-run
とするとアップグレードされるパッケージがわかるので、それを確認した上で
poetry update
すると実際にアップグレードが行われます。なお、poetry update
した時に変更されるのはpoetry.lock
だけで pyproject.toml
はそのままです。新しいバージョンの新機能を使うなどの場合はpyproject.toml
を手動で修正してして依存するバージョンを変える必要があります。
5. 仮想環境で実行
必要な依存パッケージの追加ができたら実行です。仮想環境でpythonのプログラムを実行するには
poetry run python <python-file>
あるいは
poetry shell
python <python-file>
とします。前者は実行のたびに仮想環境に入り、終わったら元の世界に戻ってくるという実行方法。後者は一旦仮想世界に入って、行きっぱなしのまま実行するという方法です。
なお、仮想環境ではpythonだけでなく、依存関係で追加したパッケージに含まれるコマンドも実行できます。例えば、project_abc
でpytest
によるユニットテストを実行するには、
poetry run pytest
あるいは
poetry shell
pytest
とすれば良いです。
まとめ
Poetryを使い始めてみる方法について書いてみました。Poetryにはまだまだ他にたくさん機能があるのですが、今回は基本的な機能に絞ってみました。私自身もまだ使いこなしているとは言えないので、より便利な使い方が見つかったらまた記事にしてみたいと思います。