Poetry事始め
ごく簡単なCLIアプリケーションの一連の作成手順を通して,Pythonプロジェクト管理ツールPoetryの基本的な使用方法をまとめる.
実行環境はMacOS/Ubuntuを想定.
Poetryのバージョンは1.0.5
ゴール
以下のように動作するgreetコマンドを作成する.
コマンドに必要なPythonパッケージを管理したり,ローカルの仮想環境にコマンドをインストールして使用できるようにしたりするためPoetryを使用する.
$ greet hello John
Hello John!
$ greet goodnight John
Goodnight John...
$ greet goodnight --sleeping John
zzz
補足
Poetryを使用してローカル環境に直接パッケージをインストールするのは少し厄介.
簡単なので題材をCLIツールとしたが,これを普段使い用にPoetryでインストールするいい方法がわからなかった.
詳しくは本稿末 "Poetryの設定" の項目を参照してください.
Poetry
Pythonプロジェクトで使用するパッケージの依存関係やバージョンを管理するためのツール
(ここではパッケージを作成するために必要なディレクトリ構成とファイルをまとめてプロジェクトと呼ぶ).
pyproject.tomlファイルをもとにパッケージの情報を管理するので,pyproject.tomlファイルを共有すればプロジェクトに必要な環境を簡単に再現できる.pyproject.tomlファイルの雛形もPoetryが自動的に作成する.
公式では
Poetry is a tool for dependency management and packaging in Python. It allows you to declare the libraries your project depends on and it will manage (install/update) them for you.
Poetryのインストール
予めPyenvが使用可能であるとインストール時のトラブルが少なくて良い,
以降の説明ではPythonの実行をpythonコマンドによるものとする.
MacOS/Linuxの場合,以下でPoetryをインストールする.
curl -sSL https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py | python
MacOSの場合はsource ~/.bashrc,Ubuntuの場合はsource ~/.profileを実行してpoetryコマンドのパスを通す.
poetry -hを実行してきれいなヘルプが出力されればOK.
python3コマンドでのPoetryのインストールは本稿末の "python3コマンドでのPoetryのインストール" の項目を参照してください.
新規Pythonプロジェクトの作成
Poetryのnewコマンドで新規Pythonプロジェクトを作成する.
任意の場所でpoetry new greetを実行し,新規Pythonプロジェクトgreetを作成.
greetパッケージを作成するために必要なファイル一式が自動的に作成される.
greet
├── greet
│ └── __init__.py
├── pyproject.toml
├── README.rst
└── tests
├── __init__.py
└── test_greet.py
pyproject.toml
後述するpoetry installでプロジェクトからパッケージを作成する際に使用される.
コマンド実行時,よく見ているとPoetryが一時的にsetup.pyを作成しているのがわかる.
[tool.poetry.dependencies], [tool.poetry.dev-dependencies]でプロジェクトで使用するパッケージのリストとそのバージョンが列挙されている.
依存するパッケージのインストール時に自動的にアップデートされる.
Pythonパッケージのインストール
addコマンドでプロジェクトで使用するPythonパッケージをインストールできる,
デフォルトではvirtualenvでプロジェクト用の仮想環境が自動的に作成され,その中にインストールされる.
greetツールでは以下のPythonのパッケージを使用する.
- 動作に必須のパッケージ
- cleo
- 開発中のみ使用するパッケージ(dev用)
- flake8
- autopep8
pyproject.tomlのあるgreetディレクトリで以下を実行する.
poetry add cleo
poetry add --dev flake8 autopep8
dev用はaddコマンドに--dev/-Dオプションをつけてインストールする.
これにより,poetry installでプロジェクトのパッケージ(ここではgreetパッケージのこと)をインストールする際,--no-devオプションを指定して実行に必要のないパッケージのインストールをスキップできる.
補足1
Ubuntuでpoetry add ...を実行して次のようなエラーが出る場合は,エラーメッセージの通りapt-get install python3-venvを実行すると正常に動作するようになる.
Creating virtualenv greet-b6grBBry-py3.6 in /root/.cache/pypoetry/virtualenvs
The virtual environment was not created successfully because ensurepip is not
available. On Debian/Ubuntu systems, you need to install the python3-venv
package using the following command.
apt-get install python3-venv
You may need to use sudo with that command. After installing the python3-venv
package, recreate your virtual environment.
Failing command: ['/root/.cache/pypoetry/virtualenvs/greet-b6grBBry-py3.6/bin/python', '-Im', 'ensurepip', '--upgrade', '--default-pip']
補足2
VSCodeを使用している場合は,VSCodeで使用するPythonインタプリタにPoetryで作成された仮想環境のものを選択すること.
仮想環境のパスはpoetry env infoのPathで確認できるのでそれを指定.
例えば以下の場合,/root/.cache/pypoetry/virtualenvs/greet-b6grBBry-py3.6を指定.
$ poetry env info
Virtualenv
Python: 3.6.9
Implementation: CPython
Path: /root/.cache/pypoetry/virtualenvs/greet-b6grBBry-py3.6
Valid: True
System
Platform: linux
OS: posix
Python: /usr
greetツールの実装
pyproject.tomlのあるgreetディレクトリでpoetry shellを実行し,本プロジェクト用の仮想環境に入る.
greet/greetディレクトリに以下のapplication.pyを作成.
CleoはPythonのCLI用パッケージであり,コマンドやオプションを簡単に追加できるほか,出力もきれいに配色されたものにできる.Poetryも使用している.
from cleo import Command, argument, option, Application
class HelloCommand(Command):
name = 'hello'
description = 'Say hello to someone'
arguments = [argument('name', 'Name of a person to hello')]
def handle(self):
self.line(f'Hello {self.argument("name")}!')
class GoodnightCommand(Command):
name = 'goodnight'
description = 'Say goodnight to someone'
arguments = [argument('name', 'Name of a person to goodnight')]
options = [option('sleeping', 's', 'Sleeping...')]
def handle(self):
if self.option('s'):
self.line('zzz')
else:
self.line(f'Goodnight {self.argument("name")}...')
application = Application()
application.add_commands(HelloCommand(), GoodnightCommand())
def main():
application.run()
pyproject.tomlファイルの編集
pyproject.tomlファイルに以下を追記.
[tool.poetry.scripts]
greet = 'application:main'
[tool.poetry.scripts]はsetuptoolsのentry_pointsにあたるもので,<command_name> = '<module_name>:<function_name>'のように指定する.
これにより,greetコマンドを実行したときapplication.pyのmain関数が実行される.
greetパッケージの作成・インストール
pyproject.tomlのあるgreetディレクトリでpoetry installを実行する.
poetry install --no-devとした場合,dev用パッケージはインストールされない.
開発目的ではpoetry installを使用し,パッケージを使用するだけであればpoetry install --no-devを使用する.
greetコマンドの動作確認
冒頭のゴールに示したように,仮想環境内で以下のようにgreetコマンドが実行できる.
$ greet hello John
Hello John!
$ greet goodnight John
Goodnight John...
$ greet goodnight --sleeping John
zzz
greet -hを実行すると,Cleoによって配色されたきれいなヘルプが見れるはず.
以上が本稿の趣旨.
Appendix
python3コマンドでのPoetryのインストール
pythonコマンドがない状態(/usr/binにpythonがなく,python3のみの状態)を想定.
python3コマンドを使用している場合は以下でインストールことができる.
curl -sSL https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py | python3
必要であれば,echo 'alias python="python3"' >> ~/.bashrc && source ~/.bashrcを実行してPython3をpythonコマンドで実行可能にしてからcurl ... pythonでPoetryをインストールできる.
しかし,いずれの場合もインストール後にパスを通した後も以下のエラーでPoetryが実行できない.
/usr/bin/env: ‘python’: No such file or directory
原因は,Poetryは実行される際インストールに使用されたインタプリタを使用するが, ~/.poetry/bin/poetryの1行目に#!/usr/bin/env pythonがハードコーディングされており,python3でインストールした場合も/usr/bin/pythonを使用しようとするためで,これを#!/usr/bin/env python3に書き換えれば正常に使用できる.
(issue: https://github.com/python-poetry/poetry/issues/1543)
pythonコマンドがない状態(/usr/binにpythonがなく,python3のみの状態)の解決策として,ln -s /usr/bin/python3 /usr/bin/pythonでシンボリックリンクを作成してからcurl ... pythonでPoetryをインストールしても問題なく動作する.
ほかにも,pythonコマンドでPython2を,python3コマンドでPython3を実行している場合は注意が必要.
Pyenvを使用し,3系に切り替えてPoetryをインストールするのが一番トラブルが少ないと思われる.
Poetryを使用した複数人での開発
pyproject.tomlファイルをリポジトリで共有することで,開発環境を揃えることができる.
開発に新規参加する場合,リポジトリをcloneした後,pyproject.tomlファイルのあるディレクトリでpoetry installを実行するだけで,このPythonプロジェクト用の仮想環境が切られ,その中に必要なパッケージがインストールされる.
Poetryの設定
poetry config --listでPoetryの設定が列挙される.
| 設定項目 | デフォルト値 | 説明 |
|---|---|---|
| virtualenvs.create | true |
poetry addやpoetry installの実行時,仮想環境を使用するかどうか.falseにした場合直環境に作用するため注意.例えば,falseの状態でpoetry install --no-devを実行すると,pyproject.tomlに列挙されたdev用パッケージが直環境からアンインストールされる. |
| virtualenvs.in-project | false |
poetry virtualenvs.in-project trueでtrueに設定できる.仮想環境用のファイルがプロジェクト内に作成されるようになる.これにより,プロジェクトのディレクトリを削除したとき仮想環境も同時に削除できる. |
ローカル環境に直接パッケージをインストールするにはvirtualenvs.createをfalseにすれば良いが,poetry install --no-devでパッケージをインストールすると,ローカル環境からdev用パッケージがアンインストールされてしまう.
一方,poetry installでパッケージをインストールするとdev用パッケージの不要なものまでインストールされてしまうので,ローカル環境全体に渡って使用するパッケージをPoetryでインストールするのは難しい.いい方法があったら教えてください.