はじめに
pypiに登録しない場合でもsetup.pyでパッケージ管理をするのはそれなりにポピュラーなやり方だと思いますが
そこからPipenvに移行して便利な点と少し迷った点について書きました。
以下で挙げている迷いポイントは全て考慮されていていわゆるバッドノウハウ的なものは必要ありません。
便利ポイント
- constraints.txtを管理しなくてよい
-
dependencies
的なものとdevDependencies
的なものの扱いが分かれている - Dockerfileに書くときの方法も用意されている
迷いポイント
- 環境がどこにできるのか迷う
- setup.pyと役割が被っているがsetup.pyを無くせるのか迷う
constraints.txtを管理しなくて良い
そもそもsetup.pyには以下のような決まりがありました。
ライブラリは、 setup.py の install_requires で 抽象的な依存関係 を定義します。 厳密にどのバージョンをインストールし、どこから依存パッケージを取得するかの判断は、あなたが決めることではありません!
とするとsetup.pyだけだと「実際に実行できるか」を担保できないという問題があって
constraints.txtは開発時にバージョンだけを参照するためのものとして使用されていました。
$ pip install -e . -c constraints.txt
つまりこのコマンドは
- 何をインストールするかは
./setup.py
に聞く - どのバージョンをインストールするかは
./constraints.txt
に聞く
という意味で使われていました。
中身はただのpip freeze
なので何かライブラリを入れたときに出力しなおす必要があって大分煩わしい感じがあったんですがPipenvなら
$ pipenv install pyyaml
で新しいパッケージを入れたときにPipenv.lockで自動でやってくれます。
dependencies
的なものとdevDependencies
的なものの扱いが分かれている
個人的にはsetup.pyのextras_require
でテスト用の依存関係はこっちに入れるみたいな運用をしていましたが、
$ pipenv install pyyaml
$ pipenv install --dev pyyaml
のようにするとpackage.json
のdependencies
とdevDependencies
みたいな感じで分けることができるようになっています。
テスト用のツールやlinter(tox
, flake8
, mypy
とか)は--dev
で入れるとよいと思います。
Dockerfileに書く時に良い方法も用意されている
単純なPythonアプリの場合はこんな感じになると思います。
FROM python:3.7
WORKDIR /app
COPY app .
RUN pip install pipenv
RUN pipenv install --system --deploy
--system
: 仮想環境を作らずにローカルにインストールする。
--deploy
: Pipfile
とPipfile.lock
に齟齬があった時に自動で更新してくれる便利機能があるが、本番用にビルドする時には余計なので齟齬があったらコケてくれる。
これでいい感じにインストールしてくれると思います。
迷いポイント
環境がどこにできるのか迷う
実際のところPipenvというツール的にはどこにできてもあまり関係ないように作られているのですが
個人的にはVSCodeで補完用のインタプリタを指定するときにどこにあるかわからないと困ったりします。
そういうときは環境変数を
$ export PIPENV_VENV_IN_PROJECT=true
とセットすると今いる場所に.venv
ディレクトリの中に作ってくれます。
また、環境は作ったり消したりしたくなると思いますが、消すときは
$ pipenv --rm
で消せます。
setup.pyと役割が被っているがsetup.pyを無くせるのか迷う
ここに色々書いてありますが...。
要するにpipenvは依存しているライブラリとそのバージョンを管理するものであって
- pypiに登録するためのメタデータ(バージョン情報とか)が含まれた生成物を作る機能
- 他のリポジトリからライブラリとして呼び出されるための機能
- entory_pointsなどを定義する機能
みたいなライブラリとしてのメタ情報を定義する機能は持ちません。
なのでこれらの機能を使わないのであればPipenvだけで良いですし、使うのであればsetup.pyも必要になります。
またPipenvはsetup.pyを使う場合も便利で
$ pipenv install -e .
のようにするとsetup.pyの中に書いている依存関係もPipenv
, Pipenv.lock
によって管理してくれるので
開発環境を新たに作るときには
$ pipenv install --dev
で再現性のある実行環境を作ることができます。
まとめ
setup.py
を開発環境の定義にまで使うのはそれをテストで使用するtoxと併せて良いアイデアだなとは思いつつも
本来は外部からの見え方を定義するものであるはずなので若干の違和感はありました。
Pipenvは完全に開発環境と実行環境のツールとしての位置付けで、とても品質の高いものだと思います。