当サイトは、アフィリエイト広告を利用しています
dockerコンテナ上でpoetryを使ってPythonの開発環境を作りながら、
poetryの使い方をまとめていく。
dockerコンテナ上で実行するがローカル環境でも同じことができるので
ローカルで実行したい場合でも参考にできると思う。
Poetryを具体的に使った開発の例としては
dockerコンテナ上でFastApiのREST APIをVSCodeで開発する方法を
下記記事でまとめています。
poetryはPythonのパッケージ管理をしてくれるツール。
javascriptでいうこところのnpmやyarnみたいなイメージ。
主な機能ととしては
がある
pyproject.tomlファイルでPythonプロジェクトの依存関係を一元的に管理できる。
また。グループを作ることで依存関係を本番、開発、テストとを分けて管理することもできる。
少しややこしかったのが
Poetryでは、依存関係を「開発」「テスト」「本番」などのグループに分けて管理することができるが
それぞれが別の環境を持っているわけでなく
あくまで依存関係をグループごとに選択的にインストールできるようにするための機能であるということ。
具体的には、開発環境やテスト環境、本番環境に必要な依存関係をpyproject.tomlファイルで定義し、
poetry install --only groupコマンドで必要な依存関係をインストールすることができる
つまり特定の環境に必要なパッケージだけをインストールして環境を管理することができるが、同じ仮想環境内での話になる。
poetry.lockファイルによって
依存関係のバージョンがロックされるため、異なる環境で同じ依存関係のバージョンを再現できる
これにより、環境間の不一致による問題を防げる。
Poetryはプロジェクトごとに自動的に仮想環境を作成し、依存関係をその仮想環境内にインストールすることで
プロジェクト間での依存関係の衝突を防ぐことができる。
また仮想環境のアクティベートやデアクティベートも自動で行うので、手動で行う必要がない。
基本的には1プロジェクト1仮想環境となる。
依存関係の追加や更新、プロジェクトのセットアップがシンプルなコマンドで統一されていて
他のツールなしで簡単に操作できる
Pythonでパッケージ管理といえばpipだと思うので
pipの比べてpoetryのメリット、デメリットをまとめてみる。
全体的にpoetryの方が高機能な感じがする
Poetryは依存関係の管理と仮想環境の作成・管理を一元的にできる。
pipの場合はpipとvirtualenvまたはvenvを組み合わせる必要がある。
※コンテナ使う場合はあんまり関係なさそう。。。
Poetryは依存関係の衝突を自動で解決してくれる
複数のパッケージが同じ依存関係を異なるバージョンで要求する場合でも
最適なバージョンを選択してインストールしてくれる
またversionロック機能もついている
Poetryはpyproject.tomlを使用して依存関係を管理し、プロジェクトの設定を一箇所に集約する。
そのためプロジェクト設定が一貫して管理できる
Poetryでは、開発用依存関係と本番用依存関係を簡単に分けて管理できる。
例えば、テストフレームワークなどは開発時のみインストールするように設定できる。
デメリットは下記がある
依存関係の解決が複雑な場合、Poetryは依存関係の解決に時間がかかることがある。
大規模なプロジェクトでは問題になるかもしれない。
Pythonの標準ライブラリでないため、poetryをインストールする必要がある。
※コンテナをdocker-composeで作る場合は無視できると思う。
一部のパッケージやビルドツールとの互換性に問題が出る場合がある。
特に、古いプロジェクトや特殊な設定をしているプロジェクトでは注意する
pipの方がシンプルで使いやすくはある
pythonの標準ツールでもあるため、広く利用されていて
学習コストが低く、使いやすい
pipは依存関係の解決をシンプルに行うため、依存関係のインストールが速い。
特に小規模なプロジェクトではそのメリットが大きい。
ちょっと作るだけとかならさくっとpipを使ったほうがいいかもしれない
必要に応じて複数の仮想環境や依存関係を手動で管理することで柔軟な設定が可能
デメリットは下記がある
pipは依存関係の衝突を自動的に解決する機能がない。
そのため、複雑な依存関係を持つプロジェクトでは手動で解決する必要がある。
pip単体では依存関係のバージョンをロックする機能がなく、
requirements.txtと組み合わせる必要がある。
しかし、requirements.txtはpipが直接管理するわけではないため、バージョンロックが統一的でない。
pipでは、開発用依存関係と本番用依存関係を分けるためには手動でrequirements.txtファイルを複数作成する
などの工夫が必要。
Poetryは、依存関係の自動解決や仮想環境の管理、バージョンロックなどを統合的に行いたい場合に非常に相性がいい。
一方、pipはシンプルで高速、かつPythonの標準ツールとして広く使われているため、
より柔軟に管理したい場合や、標準的な方法でプロジェクトを構築したい場合に向いている。
個人的にはPoetryの方が管理はしやすいイメージ。だが小規模な開発の時やツールを作る時は
pipの方が早くできるので使いやすい。
実際にコンテナで実践していく前によく使うpoetryのコマンドをまとめておく
poetry new test
プロジェクトから作成して開始したいときに使う。
新しいプロジェクトの構成を作成し、pyproject.tomlも生成する。
新しいプロジェクトが作成されるが、この段階では仮想環境は作成されない。
poetry init
既存のディレクトリをpoetryで管理するようにしたい時に使う。
既存プロジェクトにpyproject.tomlファイルを生成し、プロジェクトの初期化を行う。
この時点では仮想環境は作成されない
poetry install
pyproject.tomlが既に作成済みの場合に使う
pyproject.tomlに基づいて依存関係をインストールし、
プロジェクト専用の仮想環境も生成する。
依存関係をインストールしながら仮想環境をセットアップするコマンド
初期化はプロジェクトの状況に合わせて
のどれかを使うことになる。
poetry install --sync
インストール時にpoetry.lockの内容を環境に同期させることができる
poetry lock
pyproject.tomlに基づいてpoetry.lockファイルを再生成する。 ※pyproject.tomlとpoetry lockがずれているとエラーになる
poetry add requests
指定したパッケージを依存関係に追加し、インストールする
同時に仮想環境も作成する。
poetry update
依存関係を最新のバージョンに更新する。
「poetry update <パッケージ名>」とすれば
パッケージを指定して更新できる
poetry remove requests
パッケージを削除する
poetry run python test_module.py
仮想環境内で指定したコマンドを実行する
※test_module.pyを実行する場合のサンプル
poetry show
pyproject.tomlを含むすべてのパッケージとそのバージョンが一覧表示される。
インストール済みは緑、未インストールは赤字になる
仮想環境がない状態でpoetry showを実行すると仮想環境が作成されるが
依存関係のインストールはされない。
poetry show --tree
pyproject.tomlのパッケージとその依存関係をツリー形式で表示する
poetry env list
仮想環境の一覧を表示
※poetryでは基本は1プロジェクト1仮想環境なので1つしかでないことが多い
poetry env info
仮想環境の詳細を表示する
poetry env remove poetry-sample-project-xS3fZVNL-py3.12
仮想環境を削除する
仮想環境名は「poetry env list」で確認する
poetry self update
poetry自体のアップデート
poetry show requests
パッケージの詳細を表示する
そのほかのコマンドや詳細は下記参照
pythonのコンテナを作成する。
その中でpoetryを使ってプロジェクトを作成してみる
コンテナ作成時に同時に実行することも可能だが
動きを見るためにコンテナ内で手動で実行する。
# ベースイメージとしてPythonを使用FROM python:3.12# 作業ディレクトリを作成WORKDIR /workspace# pipを更新RUN pip install --upgrade pip# PoetryをインストールRUN pip install poetry
pythonにpipでpoetryをインストールしたイメージを作成する
version: "3"services:poetry:container_name: "poetry-sample"build:context: .dockerfile: Dockerfilevolumes:# バインドマウント- .:/workspacetty: true
docker-composeでコンテナを作成する。
docker comopse up -d
docker comopseを実行してコンテナを作成する
コンテナに入る。
VSCodeの拡張機能である。
のどちらかを使用すれば、コンテナ内をVSCodeから操作できるので 開発しやすい。
Dev Containersの使い方については下記でまとめています。
ログインし、「/workspace」に移動すると
.|-- docker-compose.yml`-- dockerfile
の状態になっている
root@4afb2b283765:/workspace# pip show poetryName: poetryVersion: 1.8.3Summary: Python dependency management and packaging made easy.Home-page: https://python-poetry.org/Author: Sébastien EustaceAuthor-email: sebastien@eustace.ioLicense: MITLocation: /usr/local/lib/python3.12/site-packagesRequires: build, cachecontrol, cleo, crashtest, dulwich, fastjsonschema, installer, keyring, packaging, pexpect, pkginfo, platformdirs, poetry-core, poetry-plugin-export, pyproject-hooks, requests, requests-toolbelt, shellingham, tomlkit, trove-classifiers, virtualenvRequired-by: poetry-plugin-exportroot@4afb2b283765:/workspace#
pip showコマンドでコンテナにpoetryがインストールされていることを確認しておく
コマンドのところでも書いたがpoetryでプロジェクトを開始する場合
のどれかから開始することになるので
それぞれのパターン別に実践してみる。
またサンプルとして下記のコードを実行する
import requestsdef fetch_data(url):try:# 指定したURLにGETリクエストを送信response = requests.get(url)# レスポンスのステータスコードを表示print(f"ステータスコード: {response.status_code}")# レスポンスの内容を表示if response.status_code == 200:print("データ:")print(response.text)else:print("データを取得できませんでした。")except requests.exceptions.RequestException as e:print(f"リクエスト中にエラーが発生しました: {e}")if __name__ == "__main__":# 取得したいデータのURLurl = "https://jsonplaceholder.typicode.com/todos/1"fetch_data(url)# 実行結果# ステータスコード: 200# データ:# {# "userId": 1,# "id": 1,# "title": "delectus aut autem",# "completed": false# }
jsonplaceholderからダミーデータを取得するpythonスクリプト
requestsのパッケージが必要になる
新規プロジェクト作成から開始する場合のパターン。
流れとしては
のようになる。
コンテナ内で実行していく
コマンドで
poetry new poetry-sample-project
を実行する。
インタラクティブガイドに答えると
下記のようなプロジェクトを作成してくれる
.├── docker-compose.yml├── dockerfile└── poetry-sample-project├── README.md├── poetry.lock├── poetry_sample_project│ ├── __init__.py│ └── test_module.py├── pyproject.toml└── tests└── __init__.py
poetry-sample-project以下が作成される
※test_module.pyは自分で追加する。
pyproject.tomlは下記のようになっている
[tool.poetry]name = "poetry-sample-project"version = "0.1.0"description = ""authors = ["xxxxxxxxxx"]readme = "README.md"[tool.poetry.dependencies]python = "^3.12"[build-system]requires = ["poetry-core"]build-backend = "poetry.core.masonry.api"
test_module.pyを実行するために必要な「requests」パッケージを
インストールする。
インストールすると同時に仮想環境も作成される
※pyproject.tomlがあるディレクトリで実行する必要がある
poetry add requests
実行後のpyproject.tomlは下記のようになる
[tool.poetry]name = "poetry-sample-project"version = "0.1.0"description = ""authors = ["xxxxxxxxxx"]readme = "README.md"[tool.poetry.dependencies]python = "^3.12"requests = "^2.32.3"[build-system]requires = ["poetry-core"]build-backend = "poetry.core.masonry.api"
requestsが追加されている
仮想環境でtest_module.pyを実行する
root@4afb2b283765:/workspace/poetry-sample-project# poetry run python poetry_sample_project/test_module.pyステータスコード: 200データ:{"userId": 1,"id": 1,"title": "delectus aut autem","completed": false}
既存のディレクトリをpoetryのプロジェクトととして管理するようにする
コンテナ作成後の下記の状態から開始する
.|-- docker-compose.yml|-- dockerfile`-- test_module.py
※test_module.pyは自分で作る
既存のディレクトリ内にpyproject.tomlを作成し
poetryのプロジェクトとして初期化する
流れとしては
のようになる。
同様にコンテナ内で実行していく
poetry init
poetry newと同様に
インタラクティブガイドに答えると
pyproject.tomlが生成される
.|-- docker-compose.yml|-- dockerfile|-- pyproject.toml`-- test_module.py
pyproject.tomlは下記のようになっている
[tool.poetry]name = "poetry-sample-project"version = "0.1.0"description = ""authors = ["xxxxxxxxxx"]readme = "README.md"[tool.poetry.dependencies]python = "^3.12"[build-system]requires = ["poetry-core"]build-backend = "poetry.core.masonry.api"
2と3の手順はpoetry newした場合と同じなので割愛する。
pyproject.tomlに基づいて依存関係をインストールし、
プロジェクト専用の仮想環境も生成する。
手順は
のようになる
またpoetry install実行する場合、poetry.lockがあるかないかで
挙動が変わる
poetry.lockない場合、pyproject.tomlでは具体的にどのバージョンがインストールされるかは未定
のためpoetry installを実行すると、その時点で利用可能な最新のバージョンがバージョン範囲に基づいて選ばれる
poetry.lockがある場合は
poetry.lockには、特定のバージョンの依存関係が記録されているので異なる環境や他の開発者が
同じプロジェクトをセットアップするときに、全く同じバージョンの依存関係をインストールできる
要は他の環境を完全に再現するためにはpoetry.lockが必須となる。
pyproject.tomlを任意のディレクトリに格納後、そのディレクトリに
移動し、poetry installを実行する
poetry install
pyproject.tomlに従って依存関係がインストールされる
※poetry.lockがある場合は特定のバージョンで依存関係の解決が行われる。
2はpoery new、poetry initと同じなので割愛する。
poetry.lock作成後にpyproject.tomlを手動で変更した場合
poetry.lockとpyproject.tomlの間に乖離が発生するので
poetry installを実行すると
$ poetry installInstalling dependencies from lock filepyproject.toml changed significantly since poetry.lock was last generated. Run `poetry lock [--no-update]` to fix the lock file.
という感じでズレていることを怒られるので
下記コマンドでpoetry.lockを更新する
poetry lock
Poetryでは依存関係を「開発」「テスト」「本番」などのグループに分けて
選択的にインストールできるようにすることができる。
※「開発」「テスト」「本番」のそれぞれが別の環境を持っているわけではない。
devグループとtestグループはデフォルトで存在するが
その他のグループは使う場合は自分で作成する必要がある。
グループ別に依存関係を追加するコマンドをまとめる
下記のpyproject.tomlに対して実行していく
[tool.poetry]name = "poetry-sample-project"version = "0.1.0"description = ""authors = ["xxxxxxxxxx"]readme = "README.md"[tool.poetry.dependencies]python = "^3.12"[build-system]requires = ["poetry-core"]build-backend = "poetry.core.masonry.api"
poetry add requests
実行後のpyproject.toml
[tool.poetry]name = "poetry-sample-project"version = "0.1.0"description = ""authors = ["xxxxxxxxxx"]readme = "README.md"[tool.poetry.dependencies]python = "^3.12"requests = "^2.32.3"[build-system]requires = ["poetry-core"]build-backend = "poetry.core.masonry.api"
poetry add black flake8 --group dev
実行後のpyproject.toml
[tool.poetry]name = "poetry-sample-project"version = "0.1.0"description = ""authors = ["xxxxxxxxxxxxxxxxxxxxx"]readme = "README.md"[tool.poetry.dependencies]python = "^3.12"requests = "^2.32.3"[tool.poetry.group.dev.dependencies]black = "^24.8.0"flake8 = "^7.1.1"[build-system]requires = ["poetry-core"]build-backend = "poetry.core.masonry.api"
poetry add pytest pytest-cov --group test
実行後のpyproject.toml
[tool.poetry]name = "poetry-sample-project"version = "0.1.0"description = ""authors = ["xxxxxxxxxxxxxxxxxxxxx"]readme = "README.md"[tool.poetry.dependencies]python = "^3.12"requests = "^2.32.3"[tool.poetry.group.dev.dependencies]black = "^24.8.0"flake8 = "^7.1.1"[tool.poetry.group.test.dependencies]pytest = "^8.3.2"pytest-cov = "^5.0.0"[build-system]requires = ["poetry-core"]build-backend = "poetry.core.masonry.api"
poetry add pydantic --group sample
実行後のpyproject.toml
[tool.poetry]name = "poetry-sample-project"version = "0.1.0"description = ""authors = ["xxxxxxxxxxxxxxxxxxxxx"]readme = "README.md"[tool.poetry.dependencies]python = "^3.12"requests = "^2.32.3"[tool.poetry.group.dev.dependencies]black = "^24.8.0"flake8 = "^7.1.1"[tool.poetry.group.test.dependencies]pytest = "^8.3.2"pytest-cov = "^5.0.0"[tool.poetry.group.sample.dependencies]pydantic = "^2.8.2"[build-system]requires = ["poetry-core"]build-backend = "poetry.core.masonry.api"
任意のグループが作成されている
addはインストールする時にグループを設定しているだけであり
コマンドを実行した仮想環境には上記のパッケージはすべてインストールされている
追加済みの依存関係を見てみる
root@aa632dfa840c:/workspace# poetry showblack 24.8.0 The uncompromising code formatter.certifi 2024.8.30 Python package for providing Mozilla's CA Bundle.charset-normalizer 3.3.2 The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet.click 8.1.7 Composable command line interface toolkitcoverage 7.6.1 Code coverage measurement for Pythonflake8 7.1.1 the modular source code checker: pep8 pyflakes and coidna 3.8 Internationalized Domain Names in Applications (IDNA)iniconfig 2.0.0 brain-dead simple config-ini parsingmccabe 0.7.0 McCabe checker, plugin for flake8mypy-extensions 1.0.0 Type system extensions for programs checked with the mypy type checker.packaging 24.1 Core utilities for Python packagespathspec 0.12.1 Utility library for gitignore style pattern matching of file paths.platformdirs 4.2.2 A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`.pluggy 1.5.0 plugin and hook calling mechanisms for pythonpycodestyle 2.12.1 Python style guide checkerpyflakes 3.2.0 passive checker of Python programspytest 8.3.2 pytest: simple powerful testing with Pythonpytest-cov 5.0.0 Pytest plugin for measuring coverage.requests 2.32.3 Python HTTP for Humans.urllib3 2.2.2 HTTP library with thread-safe connection pooling, file post, and more.
別の環境に上記のpyproject.tomlを持って行って
installコマンをオプション付きで実行することで
グループ別のインストールが可能になる。
グループ別に依存関係を追加したpyproject.tomlを元に
グループ別に依存関係をインストールしてみる
[tool.poetry]name = "poetry-sample-project"version = "0.1.0"description = ""authors = ["xxxxxxxxxxxxxxxxxxxxx"]readme = "README.md"[tool.poetry.dependencies]python = "^3.12"requests = "^2.32.3"[tool.poetry.group.dev.dependencies]black = "^24.8.0"flake8 = "^7.1.1"[tool.poetry.group.test.dependencies]pytest = "^8.3.2"pytest-cov = "^5.0.0"[build-system]requires = ["poetry-core"]build-backend = "poetry.core.masonry.api"
を別の環境に持って行ってインストールを実行して試す。
下記のような構成で試す
.|-- docker-compose.yml|-- dockerfile|-- poetry.lock|-- pyproject.toml`-- test_module.py
pyproject.tomlとpoetry.lockを残した状態で
コンテナを再作成する※下記コマンド
コンテナを再作成し、ログイン後、仮想環境を削除する
# 仮想環境一覧表示root@16cfe12632ec:/workspace# poetry env listpoetry-sample-project-xS3fZVNL-py3.12 (Activated)# 仮想環境削除root@16cfe12632ec:/workspace# poetry env remove poetry-sample-project-xS3fZVNL-py3.12Deleted virtualenv: /root/.cache/pypoetry/virtualenvs/poetry-sample-project-xS3fZVNL-py3.12# 削除後確認root@16cfe12632ec:/workspace# poetry env list
最後に依存関係がないことを確認する
赤字のものはインストールされていない
次からグループごとのインストールを試してみる
デフォルトではすべてのグループインストールされる
poetry install
本番グループのみインストール
poetry install --without dev,test
開発グループのみインストール
poetry install --only dev
テストグループのみインストール
poetry install --only test
poetryを使ってpythonの実行環境をコンテナ内で
作成してみた。
javascriptのフレームワークであるReactやAngularで
npmやyarnを使っていた人は感覚的に理解しやすいと思う。
またpipに比べて管理能力は高いのでプロジェクトで使うには
良いと思う。
pipで管理していたプロジェクトをpoetry管理に変更する場合は
requirements.txtからパッケージをpoetryでインストールする方法もある
下記記事でまとめている