動機
近頃pipenv のインストールがかなり遅いので poetry を試してみました。
一通り使ってみてわかったことをまとめます。Pipenvを使っているのでそことの比較も。
パッケージ関連のコマンド(build, publish...)に関してや、細かい機能に関しては記述しないので、公式 Docを参考にしてください。
Poetryについて
Poetryは、Pythonのパッケージ管理ツールです。Pipenvと同様、依存関係を解決しパッケージのインストール、アンインストールを行ってくれ、
poetry.lockファイルによって、他のユーザーも適切なバージョン、依存関係でパッケージをインストールすることが出来ます。
仮想環境を利用でき、パッケージングも可能です。
環境
- CentOS 7.6.1810
- pyenv 1.2.14-8-g0e7cfc3b
- poetry 1.0.2
Python は pyenv でインストールしたものを使う。
- Python 3.7.4 (pyenv global)
導入
$ curl -sSL https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py | python
~./bash_profile
に PATH が記入され、poetry が立ち上がる。
$ poetry -V
Poetry version 1.0.2
Poetry 設定
- PIPENV_VENV_IN_PROJECT
pipenv の場合、.venv
フォルダをプロジェクト内に設定するには環境変数を利用していた。
$ export PIPENV_VENV_IN_PROJECT=1
$ pipenv install...
poetry の場合、poetry config
から設定を行う。
--list
オプションで現在の設定を確認できる。デフォルトではvirtualenvs.in-project=false
。
$ poetry config --list
cache-dir = "/home/user/.cache/pypoetry"
virtualenvs.create = true
virtualenvs.in-project = false
virtualenvs.path = "{cache-dir}/virtualenvs" # /home/user/.cache/pypoetry/virtualenvs
設定を変更。
$ poetry config virtualenvs.in-project true
$ poetry config --list
cache-dir = "/home/user/.cache/pypoetry"
virtualenvs.create = true
virtualenvs.in-project = true
virtualenvs.path = "{cache-dir}/virtualenvs" # /home/user/.cache/pypoetry/virtualenvs
プロジェクトのスタート
ひな形の生成
poetry new
でプロジェクトをスタート、ひな形が生成される。
以下は公式 Docの通り。
$ poetry new my-package
Created package my_package in my-package
my-package
├── pyproject.toml
├── README.rst
├── my_package
│ └── __init__.py
└── tests
├── __init__.py
└── test_my_package.py
生成されるpyproject.toml
は以下の通り。dev-dependencies に自動で pytest が入るようだ。
[tool.poetry]
name = "my-package"
version = "0.1.0"
description = ""
authors = ["Your Name <you@example.com>"]
[tool.poetry.dependencies]
python = "^3.7"
[tool.poetry.dev-dependencies]
pytest = "^5.2"
[build-system]
requires = ["poetry>=0.12"]
build-backend = "poetry.masonry.api"
ただどうも my-package の中に my_package ディレクトリが出来るのが使いにくい。--name
オプションでパッケージ内のディレクトリ名を変更出来る。
-
--name
オプション
$ poetry new my-package --name app
Created package app in my-package
my-package
├── pyproject.toml
├── README.rst
├── app
│ └── __init__.py
└── tests
├── __init__.py
└── test_my_package.py
-
--src
オプション
--src
オプションというのもあるようだが、余計ややこしくなるので使わなそう。
$ poetry new --src my-package
├── pyproject.toml
├── README.rst
├── src
│ └── my_package
│ └── __init__.py
└── tests
├── __init__.py
└── test_my_package.py
pyproject.toml
の生成
ひな形が必要ない場合、poetry init
でpyproject.toml
のみ作成出来る。
npm init
のように対話式でpyproject.toml
の内容を決める。
$ poetry init
Package name [{folder_name}]:
Version [0.1.0]:
Description []:
Author [None, n to skip]: n
License []:
Compatible Python versions [^3.7]:
Would you like to define your main dependencies interactively? (yes/no) [yes] no
Would you like to define your dev dependencies (require-dev) interactively (yes/no) [yes] no
Generated file
[tool.poetry]
name = "new_ais"
version = "0.1.0"
description = ""
authors = ["Your Name <you@example.com>"]
[tool.poetry.dependencies]
python = "^3.7"
[tool.poetry.dev-dependencies]
[build-system]
requires = ["poetry>=0.12"]
build-backend = "poetry.masonry.api"
Do you confirm generation? (yes/no) [yes] yes
package name は何も入力しないとそこのフォルダ名になる。Author と dependencies のところは y/n を入力。これでカレントディレクトリにpyproject.toml
が作成される。
Pipenv と同じように使うなら init で始めたほうがわかりやすそう。
install
poetry install
はpipenv install
と同じく、上で作成したpyproject.toml
から、依存関係を解決し、必要なパッケージをインストールする。
$ poetry new myapp
$ cd myapp
$ poetry install
reating virtualenv myapp in /home/user/workspace/poetry/myapp/.venv
Updating dependencies
Resolving dependencies... (0.5s)
Writing lock file
Package operations: 11 installs, 0 updates, 0 removals
- Installing more-itertools (8.1.0)
- Installing zipp (1.0.0)
- Installing importlib-metadata (1.4.0)
- Installing pyparsing (2.4.6)
- Installing six (1.14.0)
- Installing attrs (19.3.0)
- Installing packaging (20.0)
- Installing pluggy (0.13.1)
- Installing py (1.8.1)
- Installing wcwidth (0.1.8)
- Installing pytest (5.3.2)
- Installing myapp (0.1.0)
install を行うと、poetry.lock
ファイルが作成され、依存関係を見ることが出来る。
-
--no-root
オプションpoetry はデフォルトで myapp をインストールする。これを回避するには、
--no-root
オプションを付けてインストール。$ poetry install --no-root
-
--no-dev
オプションdev-dependencies を install しない場合は、
--no-dev
オプションで OK。$ poetry install --no-dev
add
パッケージをインストール。Pipenv とは異なり、add なので注意。
pipenv に比べて locking が早い。
$ poetry add django==2.2.8
dev-dependencies の場合、--dev(-D)
オプション。
$ poetry add flake8 -D
--dry-run
オプションを用いればインストールは行わず、インストールされる内容を見る事ができる。
$ poetry add django --dry-run
Using version ^3.0.2 for django
Updating dependencies
Resolving dependencies... (0.4s)
Package operations: 4 installs, 0 updates, 0 removals, 13 skipped
- Skipping more-itertools (8.1.0) Already installed
- Skipping zipp (1.0.0) Already installed
- Skipping importlib-metadata (1.4.0) Already installed
- Skipping pyparsing (2.4.6) Already installed
- ...
update
プロジェクトにインストールしたパッケージをアップデートする場合
$ poetry update
個別にアップデート
$ poetry update requests django
add と同じく、--dry-run
オプションでアップデートの内容を見る事ができる。
$ poetry update --dry-run
Updating dependencies
Resolving dependencies... (0.4s)
No dependencies to install or update
- Skipping more-itertools (8.1.0) Already installed
- Skipping zipp (1.0.0) Already installed
- Skipping importlib-metadata (1.4.0) Already installed
- Skipping pyparsing (2.4.6) Already installed
- Skipping six (1.14.0) Already installed
- Skipping atomicwrites (1.3.0) Not needed for the current environment
- ...
remove
インストールしたパッケージを削除。
$ poetry remove flask
dev-dependencies にインストールしたパッケージは--dev(-D)
オプションが必要なので注意。
$ poetry add flake8 -D
$ poetry remove flake8 # failed
[ValueError]
Package flake8 not found
$ poetry remove flake8 -D # OK
remove でも--dry-run
オプションが使用できる。
show
利用可能なパッケージの一覧を表示する。
pip list
の強化版のような機能。
$ poetry show
asgiref 3.2.3 ASGI specs, helper code, and ada...
attrs 19.3.0 Classes Without Boilerplate
django 3.0.2 A high-level Python Web framewor...
entrypoints 0.3 Discover and load entry points f...
flake8 3.7.9 the modular source code checker:...
importlib-metadata 1.4.0 Read metadata from Python packages
mccabe 0.6.1 McCabe checker, plugin for flake8
more-itertools 8.1.0 More routines for operating on i...
packaging 20.0 Core utilities for Python packages
pluggy 0.13.1 plugin and hook calling mechanis...
...
パッケージに関する情報も表示出来る。
$ poetry show django
name : django
version : 3.0.2
description : A high-level Python Web framework that
encourages rapid development and clean, pragmatic
design.
dependencies
- asgiref >=3.2,<4.0
- pytz *
- sqlparse >=0.2.2
-
--tree
オプションツリー構造で依存関係を表示できる。
pipenv graph
に近い機能。実際は色付き出力なので見やすい。$ poetry show --tree django 3.0.2 A high-level Python Web framework that encourages rapid development and clean, pragmatic design. ├── asgiref >=3.2,<4.0 ├── pytz * └── sqlparse >=0.2.2 flake8 3.7.9 the modular source code checker: pep8, pyflakes and co ├── entrypoints >=0.3.0,<0.4.0 ├── mccabe >=0.6.0,<0.7.0 ├── pycodestyle >=2.5.0,<2.6.0 └── pyflakes >=2.1.0,<2.2.0 ...
-
--latest(-l)
オプション最新バージョンを表示。
$ poetry show --latest asgiref 3.2.3 3.2.3 ASGI specs, helper code, a... attrs 19.3.0 19.3.0 Classes Without Boilerplate django 3.0.2 3.0.2 A high-level Python Web fr... entrypoints 0.3 0.3 Discover and load entry po... flake8 3.7.9 3.7.9 the modular source code ch... importlib-metadata 1.4.0 1.4.0 Read metadata from Python ...
-
--outdated(-o)
オプションバージョンが古いパッケージの表示。
$ poetry show -o django 2.2.4 3.0.2 A high-level Python Web framework that e...
lock
pyproject.toml
で指定された依存関係をロックする。(インストールは行わない)
poetry.lock
が生成される。
$ poetry lock
env
仮想環境関連のコマンド。[python]の部分には 3.7.4 等を指定すればよい。
$ poetry env info # 現在の仮想環境の情報
$ poetry env list # 仮想環境一覧
$ poetry env remove <python> # 仮想環境の削除
$ poetry env use <python> # 仮想環境をアクティブまたは作成
自分の環境だと、virtualenvs.in-project=true
の場合、list にも表示されず remove も効かなかった。
.venv/を削除すればいい話だが。
shell
仮想環境内でシェルを起動。pipenv shell
と同等。
$ poetry shell
scripts
pyproject.toml
に以下を記入し、スクリプトを実行することが出来る。
[tool.poetry.scripts]
start = "script:main"
def main():
print("Run script with poetry!")
$ poetry run start
Run script with poetry!
仮想環境に入らずとも、スクリプトから実行すると仮想環境内で実行してくれる。
引数の扱い
poetry の scripts 実行コードを見る限り、引数は渡せないようだ。
# poetry script実行コード
def run_script(self, script, args):
if isinstance(script, dict):
script = script["callable"]
module, callable_ = script.split(":")
src_in_sys_path = "sys.path.append('src'); " if self._module.is_in_src() else ""
cmd = ["python", "-c"]
cmd += [
"import sys; "
"from importlib import import_module; "
"sys.argv = {!r}; {}"
"import_module('{}').{}()".format(args, src_in_sys_path, module, callable_) # 実行
]
return self.env.execute(*cmd)
上のスクリプト設定であれば、import_module('script').main()
が実行されるので、そもそも引数を渡す部分がない。
Pipenv ではよくstart = "python manage.py runserver 0.0.0.0:8000"
を登録していたので、困った。
[tool.poetry.scripts]
start = "manage:main"
とし、poetry run start runserver 0.0.0.0:8000
とすれば一応動くが。。。
所感
-
(pipenv と比べ)良い
install、add、remove、lock が Pipenv より早く(重要)、コンソール上の表示が見やすいので良い。
pip list
やpipenv graph
に相当する機能もかなり見やすい。 -
(pipenv と比べ)申し分ない
venv との連携。Pipenv と同様の使い心地で使える。
(venv in project の時の動作が気になるが)
pipenv から pyenv install できる機能はないようだが、そんな頻繁に使うものでもないので大丈夫。 -
(pipenv と比べ)悪い
やはり script の部分。issue は多く出ていたので改善待ちかな。
オプションが多い気がする。覚えれば良い。
以上の点を踏まえても、poetry を使っていくことになりそうだ。
贅沢を言うならpoetry show
で dev かどうかわかればよかったな。
参考
- Poetry - Python dependency management and packaging made easy
https://python-poetry.org/docs/