はじめに
この記事は以前書いたpipenvとGitとDockerを使ったPython開発フローの姉妹記事です。Pipenvの開発があまり活発ではなくなった現在、Pythonを使ったプロジェクトではPoetryを使う場面もぼちぼち出てくると思います。そこで改めてPoetryを使った開発フローについてまとめ直してみようと思います。
全体の流れ
- 開発環境のインストール
- プロジェクトの初期化
- Docker化
前提環境
- Python 3.x
- UnixライクなOS
開発環境のインストール
Poetryのインストール
たいていの場合お使いのOS付属のパッケージマネージャーからインストールすることができると思います。
macOSの場合
$ brew install poetry
Arch Linux
$ sudo pacman -S python-poetry
Ubuntu 18.04
残念ながら標準リポジトリには登録されていないので、公式インストーラーからインストールします。
$ sudo apt install python3 python3-pip
$ curl -sSL https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py | python3
インストールが完了したら ~/.poetry/bin
に PATH を通してください。お使いのシェルによると思いますが、~/.zshrc
や ~/.bashrc
に以下のような設定を加えます。
export PATH=${HOME}/.poetry/bin:${PATH}
その他ツールの導入
この先 Git と Docker / Docker Compose を使うので用意しておいてください。
Python プロジェクトの初期化
ではいよいよ poetry を使って Python プロジェクトを初期化していきます。
プロジェクトの作成
まずは適当なディレクトリを作ってその中に入っておきます。
$ mkdir sample-app
$ cd sample-app
次に poetry init
を実行することでプロジェクトの初期化ができます。対話式になっているので、それぞれ答えていきましょう。途中依存パッケージをインストールするかどうかも聞かれますが、今回は個別にインストールしたいのでスキップしておきます。
$ poetry init
This command will guide you through creating your pyproject.toml config.
Package name [sample_app]:
Version [0.1.0]:
Description []: Sample App
Author [Aruneko <webmaster@example.com>, n to skip]:
License []: MIT
Compatible Python versions [^3.7]:
Would you like to define your main dependencies interactively? (yes/no) [yes] no
Would you like to define your development dependencies interactively? (yes/no) [yes] no
Generated file
[tool.poetry]
name = "sample_app"
version = "0.1.0"
description = "Sample App"
authors = ["Aruneko <aruneko99@gmail.com>"]
license = "MIT"
[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]
対話環境を抜けると pyproject.toml
ができあがっています。これでプロジェクトの初期化は完了です。
$ ls
pyproject.toml
Poetryの 初期設定
通常は ~/Library/Caches/pypoetry/virtualenvs
や ~/.config/poetry
以下に作成される Python 仮想環境が、以下の設定を追加しておくとプロジェクトルート直下に .venv
ディレクトリを作って、そこで Python 環境を管理してくれるようになります。お好みで設定してください。
$ poetry config virtualenvs.in-project true --local
なお、この設定は pyproject.toml
ではなく poetry.toml
に記載されるので注意してください。
パッケージの追加
Poetry 環境下では npm などと同じく add
を使ってパッケージを追加します。サンプルとして FastAPI を使ったアプリケーションを開発してみましょう。
$ poetry add fastapi uvicorn
Poetry でパッケージをインストールするとその際に解決できた依存パッケージや、それぞれのパッケージのバージョン情報が poetry.lock
に書き込まれます。
開発時にしか使わないパッケージはこれまた npm と同様に -D
オプションを付けてインストールします。例えばコードフォーマッターである black
をインストールしてみましょう。
$ poetry add -D black
ここまでのコマンドを実行すると、pyproject.toml
の tool.poetry.dependencies
セクションと tool.poetry.dev-dependencies
セクションに今までインストールしたパッケージ群が追加されていることが確認できます。
[tool.poetry.dependencies]
python = "^3.7"
fastapi = "^0.52.0"
uvicorn = "^0.11.3"
[tool.poetry.dev-dependencies]
black = "^19.10b0"
今後は必要に応じたパッケージをその都度インストールしてください。
Gitの初期化
続いてこのプロジェクトを Git で管理するために Git の初期化を行います。gitignore.io を利用して、まず .gitignore
ファイルを作ってしまいましょう。今回は Python と virtualenv を指定して作ってもらいます。.gitignore
に追加の設定が必要な方はここで編集しておいてください。
.gitignore
ができたら手元の Git リポジトリを初期化して、ざっくり全ファイルを追加して commit しておきます。
$ curl -o .gitignore https://www.gitignore.io/api/python,virtualenv
$ git init
$ git add pyproject.toml poetry.lock poetry.toml .gitignore
$ git commit -m "Initial Commit"
仮想環境への入り方
Poetry で作成した Python 仮想環境に入るには shell
サブコマンドを使います。仮想環境に入り忘れるとインストールしたはずのパッケージが見えないなどいろいろな不具合が起こりますので、よく確認するようにしましょう。なお、抜けるときは exit
コマンドです。
$ poetry shell
(.venv)$ exit
Docker 化
では一通り Poetry プロジェクトを作り終わったところでいよいよ Docker 化に取り組んでいきます。
.dockerignore の準備
転送しなくて良いファイルは .dockerignore
に記入するようにしましょう。特に .venv
ファイルをプロジェクトルートに作るように設定している場合は必ず記述するようにします。その他にも __pycache__
ディレクトリなどは転送しないようにしておくと良いでしょう。
.venv/
__pycache__/
Dockerfile の準備
ついに Dockerfile を書いていきます。今回は Multi Stage Build を使った方法を紹介します。前半で requirements.txt
を作成、後半でそれを用いて Python アプリケーションの載った Docker Image を作成するという手順に分かれています。
そもそもなぜそうする必要があるのかというと、poetry.lock
を読むためには Poetry をインストールする必要がある一方、アプリケーションが載るコンテナには Poetry を入れておく必要がないため、これらを切り離したいという意図があるからです。Poetry には requirements.txt
を生成する機能があるため、これを活用していきます。
まず前半部分の説明から。Docker のキャッシュ戦略をうまく使うため、一番最初に Poetry をインストールしてしまいます。こうすることで、ビルドのたびに Poetry をインストールする手間が省けます。次に、pyproject.toml
と poetry.lock
だけをコピーして、requirements.txt
を生成してしまいます。
続いて後半の説明です。できあがった requirements.txt
を前半部分からコピーしてきた上で、pip
コマンドを使ってそれらのパッケージを全てインストールします。もしこれらのファイルに変更がない場合はキャッシュが使われて自動で次のレイヤのビルドが行われるので、ビルドのたびに依存パッケージをダウンロードしてくるような動作を事前に防止することができます。これで圧倒的にビルド時間を節約できるのでオススメの構成です。インストールが終わった後に、各種 Python スクリプトを転送して、動かしたいコマンドなどを書いておけば完成です。
FROM python:3.8-slim as builder
WORKDIR /usr/src/app
RUN pip install poetry
COPY pyproject.toml poetry.lock ./
RUN poetry export -f requirements.txt > requirements.txt
FROM python:3.8-slim
ENV PYTHONUNBUFFERED=1
WORKDIR /usr/src/app
COPY --from=builder /usr/src/app/requirements.txt .
RUN pip install -r requirements.txt
COPY . .
EXPOSE 8000
CMD [ "uvicorn", "main:app", "--host", "0.0.0.0" ]
ついでに Docker Compose の設定もしておくと良いでしょう。開発用にローカルファイルをマウントした上でオートリロードの設定などを入れておくとはかどるかもしれません。
version: '3'
services:
app:
build: .
volumes:
- ./:/usr/src/app
ports:
- "8000:8000"
command: ["uvicorn", "main:app", "--reload", "--host", "0.0.0.0"]
FAQ
パッケージの更新方法
poetry update
が使えます。ただし pyproject.toml
に記述したバージョンを超えてアップデートされることはないので、メジャーバージョンアップの際などは注意してください。
パッケージの削除方法
poetry remove PACKAGE_NAME
で削除できます。
途中から開発に参加した場合
poetry install
で開発用依存パッケージごとインストールできます。
おわりに
ここまで Poetry を使った Python プロジェクトの開発フローについて説明してきました。Poetry においても Pipenv と同様に poetry.lock
を活用することによって開発者間でのバージョンの差異を取り除き、安定した開発環境を提供できるようになっていると思います。また、PEP で取り決められたフォーマットに従っているため、将来性も悪くないように感じられます。
一方で、Pipenv では実現できていたワンライナーを走らせる script
機能を欠いているなど、Python アプリケーションではなく Python パッケージ開発者のためのプロジェクト管理ツールであるという印象も受けます。Lint とかテストを実行するのに結構使うんですけどね、この機能。
ということで Poetry も Pipenv も一長一短な感じがあります。お使いのプロジェクトに合わせて選択していくのが現時点では無難なのかなと思うところです。それでは皆さん良い Python ライフをお送りください。