pip/requirements.txtを直接操作するではなくさらに上位のツールを使いたかった。ライブラリの先の依存を陽に書かなくてもよくしたい & バージョンの固定をやりやすくしたい。
最終的に決まった手順
pip-toolsを使う。Pipenvは後述の通り挫折した。
$ sudo apt install -y curl python3-venv python3-distutils
$ python3 -m venv --without-pip venv
$ source venv/bin/activate
(venv) $ curl -kL https://bootstrap.pypa.io/get-pip.py | python
(venv) $ pip install pip-tools
(venv) $ vi requirements.in && pip-compile # ライブラリを追加、バージョン変更する場合のみ
(venv) $ pip-sync
--without-pip
で始める理由は、pipがグローバルに入っていない環境への対応。pipはグローバルに 入ってない方がよい という意見がある。
- https://qiita.com/tatamyiwathy/items/c673c19202eea260f37e
- https://amano41.hatenablog.jp/entry/wsl-python3-venv-error
- https://qiita.com/suzuki_y/items/3261ffa9b67410803443
- https://qiita.com/ryu22e/items/ad3f8f3df30886d23661
開発時の流れ
-
ライブラリの選定、バージョンの選択/lockをする担当者
- venv/pip-toolsをインストールする
- requirements.inを書いてpip-compileをし、requirement.txtを作る。equirements.inでバージョンを特に書かずにpip-compileすればその時に解決できたバージョンがrequirements.txtの方に書き込まれるので便利。requirements.inでバージョンを陽に書けばpip-compileをし直しても特定のバージョンで固定もできるし、定期的に最新版に更新する運用ならin側でバージョンを書かなければよい。
- requirements.inとrequirements.txtをgit commitする。後者がlockファイルに相当する
-
↑の結果を利用してコードを書くだけの開発者
- venv/pip-toolsをインストールする
- pip-syncを叩く。必要なライブラリがインストールできるほか、不要なライブラリを消すこともできる
-
CI
- venvは状況に応じて必要なら入れる。pip-toolsは入れてもよいが、たぶんCIでは不要で
pip install -r requirements.txt
するだけで再現が可能。pip install -r
とpip-sync
の主な違いは不要なライブラリを削除してくれる効果があるかどうか。CIでは綺麗な環境から作ると思うので、pip install -r
でよいことになる。
- venvは状況に応じて必要なら入れる。pip-toolsは入れてもよいが、たぶんCIでは不要で
その他運用上のポイント
プライベートリポジトリを登録する
requirements.inファイルに以下のようにgithub privateリポジトリを書く。
git+https://github.com/account/library.git@branch
git+ssh://github.com/account/library.git@branch
sshの場合は然るべき秘密鍵を事前に設置しておけば対話なしでインストールできるし、httpsの場合は事前の仕込みが何もない場合は対話でusername/passwordを促されるし、環境変数なり.netrcなりを書いて対話不要にすることもできる。pip-toolsを活用するのはどちらかと言うとCIとかではなく自身が開発するときの話なので、「変な仕込みを入れないままで動かしてもちゃんと対話的にパスワード入力できるようになっている」ことがありがたい。
プライベートリポジトリを改変可能な状態で参照する
上記の代わりに-eを付けた形式でrequirementsを書くとeditable installというものになってそのライブラリのpyファイルも直接いじれるようになるが、なぜかegg名を陽に書かないといけなくなる。「ライブラリのpyファイルも直接いじれる」とは具体的には、venvの下に.gitが付いている状態のリポジトリがcloneされてきて、そこでダイレクトに編集→コミット&プッシュができるようになる。
-e git+https://github.com/account/library.git@branch#egg=library
-e git+ssh://github.com/account/library.git@branch#egg=library
Python自体のバージョンを固定する
pip-tools (というかrequirements.txt) でPythonバージョンを固定する方法は無さそうだが、「version x.y以上でないと動かないよ」という事実を何らかの形で記録したいだけなので、ここは諦めてREAMDE等に記すという運用にする。
npmのenginesのようにエラーが出るだけで十分なのだけれど…
参考: Pipenvで挫折した理由
- Pipenvもパッケージバージョンのlockができるが、Pipenv.lockファイルの生成に信じられないくらい時間がかかるので、numpyとかlibrosaとかを使う場合は--skip-lockを常用することになる。これだとバージョンのlockができないので困る
- プライベートリポジトリを登録してhttpsで対話的にパスワード入れるのもPipenvだとうまく対話ができなくて、.netrcにアクセスキーを書く必要があった