/dev/null

脳みそのL1キャッシュ

poetryでpythonの依存関係管理

はじめに

今まで自分はPythonでライブラリ、CLIツールを書く場合、大抵はpiprequirements.txtで依存管理していましたが、なんだか界隈ではPipenvとかpoetryとかが流行っているのでこの流れに乗っておこうと思います。

選択肢としてPipenvとpoetryがありましたが、ここによると、Pipenvに比べpoetryはPEP 518で標準化されたpyproject.tomlを使っているようですし、setup.pyなど、パッケージング周りの作業も面倒を見てくれるそうなので、今回はpoetryを選びました。

環境

poetryの導入はそこまで環境依存ではないのですが、念のために自分の環境情報を載せておきます。

$ uname -a
Darwin <user-name> 19.5.0 Darwin Kernel Version 19.5.0: Tue May 26 20:41:44 PDT 2020; root:xnu-6153.121.2~2/RELEASE_X86_64 x86_64
$ pyenv --version
pyenv 1.2.18-4-g5b009e87
$ python --version
Python 3.8.2

導入

公式のREADME.mdでは、以下のコマンドによるインストールを推奨しています。

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

もちろん、pipを使ったインストールも可能です。

$ pip install poetry

今回インストールしたpoetryのバージョンは以下の通りです。

$ poetry --version
Poetry version 1.0.5

プロジェクトの生成

poetry new プロジェクト名で新しいプロジェクトを作れます。

$ poetry new sample_python_project
Created package sample_python_project in sample_python_project

プロジェクトの構成はこんな感じになっています。

$ tree ./sample_python_project
./sample_python_project
├── README.rst
├── pyproject.toml
├── sample_python_project
│   └── __init__.py
└── tests
    ├── __init__.py
    └── test_sample_python_project.py

2 directories, 5 files

pyproject.tomlの中身はこんな感じです。

[tool.poetry]
name = "sample_python_project"
version = "0.1.0"
description = ""
authors = ["d2verb <xxx@example.com>"]

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

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

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

依存パッケージの追加

poetry add パッケージ名で依存パッケージを追加できます。

$ poetry add bottle
Creating virtualenv sample-python-project in /Users/d2verb/Workspace/dev/private/sample_python_project/.venv
Using version ^0.12.18 for bottle

Updating dependencies
Resolving dependencies... (1.1s)

Writing lock file


Package operations: 10 installs, 0 updates, 0 removals

  - Installing pyparsing (2.4.7)
  - Installing six (1.15.0)
  - Installing attrs (19.3.0)
  - Installing more-itertools (8.4.0)
  - Installing packaging (20.4)
  - Installing pluggy (0.13.1)
  - Installing py (1.9.0)
  - Installing wcwidth (0.2.5)
  - Installing bottle (0.12.18)
  - Installing pytest (5.4.3)

仮想環境の生成

最初に仮想環境を作っているようです。

Creating virtualenv sample-python-project in /Users/d2verb/Workspace/dev/private/sample_python_project/.venv

仮想環境がどこに作成されるかはpoetry config --listコマンドで調べることができます。

$ poetry config --list
cache-dir = "/Users/d2verb/Library/Caches/pypoetry"
virtualenvs.create = true
virtualenvs.in-project = true
virtualenvs.path = "{cache-dir}/virtualenvs"  # /Users/d2verb/Library/Caches/pypoetry/virtualenvs

virtualenvs.in-projecttrueの場合、プロジェクト内(./.vnev)に作られますが、falseの場合は{cache-dir}/virtualenvsに作られます。

virtualenvs.in-projectfalseにしたい場合は以下を実行すればいいです。

$ poetry config virtualenvs.in-project false

パッケージのインストール

poetry add bottleを実行するとpyproject.tomlにbottleの情報が追加されます。

[tool.poetry]
name = "sample_python_project"
version = "0.1.0"
description = ""
authors = ["d2verb <xxx@example.com>"]

[tool.poetry.dependencies]
python = "^3.8"
bottle = "^0.12.18"

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

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

また、poetry.lockという名前でロックファイルも作られます。

開発環境でのみ必要な依存パッケージのインストール

例えば、linterとか型チェッカーは開発環境でしかいらないので、これらは開発環境時にのみ必要なパッケージとしてpoetry add パッケージ名 -Dで追加できます。

$ poetry add mypy flake8 black -D
Using version ^0.782 for mypy
Using version ^3.8.3 for flake8
Using version ^19.10b0 for black

Updating dependencies
Resolving dependencies... (0.6s)

Writing lock file


Package operations: 14 installs, 0 updates, 0 removals

  - Installing appdirs (1.4.4)
  - Installing click (7.1.2)
  - Installing mccabe (0.6.1)
  - Installing mypy-extensions (0.4.3)
  - Installing pathspec (0.8.0)
  - Installing pycodestyle (2.6.0)
  - Installing pyflakes (2.2.0)
  - Installing regex (2020.6.8)
  - Installing toml (0.10.1)
  - Installing typed-ast (1.4.1)
  - Installing typing-extensions (3.7.4.2)
  - Installing black (19.10b0)
  - Installing flake8 (3.8.3)
  - Installing mypy (0.782)

pyproject.tomlを見ても[tool.poetry.dev-dependencies]にしかない追加されていないことがわかります。

[tool.poetry]
name = "sample_python_project"
version = "0.1.0"
description = ""
authors = ["d2verb <xxx@example.com>"]

[tool.poetry.dependencies]
python = "^3.8"
bottle = "^0.12.18"

[tool.poetry.dev-dependencies]
pytest = "^5.2"
mypy = "^0.782"
flake8 = "^3.8.3"
black = "^19.10b0"

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

仮想環境への切り替え

Pythonでの開発は基本的に仮想環境上でするものかと思います。仮想環境に入るには以下のように、仮想環境内のactivateスクリプトを実行する必要があります。

# 有効化
$ source ./.venv/bin/activate

# 無効化
(.venv) $ deactivate

poetryを使う場合、poetry shellで仮想環境に入ることができます。

# 有効化
$ poetry shell
Spawning shell within /Users/d2verb/Workspace/dev/private/sample_python_project/.venv

# 無効化
(.venv) $ exit

poetryは仮想環境に入る際に新しいシェルを立ち上げているので、抜ける時はexitを実行するだけでいいのが嬉しいポイントですね。

プロジェクトで利用されているパッケージをリストアップ

poetry showを使えば、現在のプロジェクトで利用されているパッケージの情報をリストアップすることができます。

$ poetry show
appdirs           1.4.4     A small Python module for determining appropriate platform-specific dirs, e.g. a "user data dir".
attrs             19.3.0    Classes Without Boilerplate
black             19.10b0   The uncompromising code formatter.
certifi           2020.6.20 Python package for providing Mozilla's CA Bundle.
chardet           3.0.4     Universal encoding detector for Python 2 and 3
click             7.1.2     Composable command line interface toolkit
flake8            3.8.3     the modular source code checker: pep8 pyflakes and co
gmpy2             2.0.8     GMP/MPIR, MPFR, and MPC interface to Python 2.6+ and 3.x
idna              2.10      Internationalized Domain Names in Applications (IDNA)
isort             4.3.21    A Python utility / library to sort Python imports.
mccabe            0.6.1     McCabe checker, plugin for flake8
...

おわりに

時代は変わりました。もうrequirements.txtは古いのです。今後はpoetryを使っていきます。

参考文献

org-technology.com