はじめに
お助けプリーズ🙏 nikkieです
今さらの話ではあるのですが、「pipの動きが変わったなー」と思っていた事象がどうやら新リゾルバに起因するらしいとこのたび分かりました。
ラバーダッキングも狙って、何に困っているかを書き出してみます。
目次
pip 20.3からの新リゾルバ
遡ること約3年、Pythonのpipは依存解決の動きが変わったのです!
ばんくしさんのエントリがめちゃ詳しく、分かりやすかったです。
✍️強い依存解決を「しない」から「する」へ変わった
pipにおける重要な変更として、2つ目に、現在テスト段階にある依存解決を行うリゾルバ、2020-resolverのリリースがある。
先述の通り、pipは強い依存解決を行わないツールだった。(略) 対して2020-resolverは、シンプルなbacktrackingを利用した依存解決リゾルバであり、強い依存解決を事前に行う事で、pipのインストールの前後関係による課題を解消するものである。
英語での情報は以下
- Python Software Foundation News: Releasing pip 20.3, featuring new dependency resolver
- pipのドキュメント Changes to the pip dependency resolver in 20.3 (2020)
モノレポで大きな1つの仮想環境を作りたいときに困った!
サンプルモノレポ
複数のPythonライブラリを1つのリポジトリで開発する状況を指して、ここではモノレポという語を使いました。
説明のための例として、lib-a1とlib-bを1つのリポジトリで開発する場合です。
ここでlib-bはlib-aに依存します
libB/setup.py
setup(
...,
install_requires=[
"lib_a@git+ssh://git@github.com/ftnext/monorepo-python-practice@main#egg=lib_a&subdirectory=libA"
],
)
開発環境構築では、1つのvenvにlib-aもlib-bもeditable installできるといいんですよね〜。
editable installとは、Pythonファイルをコピーせずにimportパスに加えるインストール。
ref: https://pip.pypa.io/en/stable/topics/local-project-installs/#editable-installs
モノレポで1つのvenvにlib-aもlib-bも editable installできていると、lib-aを変更した後にインストール(=ファイルコピー)し直さなくても、lib-bにもlib-aの変更が反映されるのです。
. # リポジトリのルートディレクトリ ├── libA # lib-aの実装 ├── libB # lib-bの実装。lib-aに依存 └── venv # この仮想環境にlib-aもlib-bもeditable installしたい
pip 20.2.4まで
lib-a -> lib-b の順でeditable installすると、2つともeditable installできます!
モノレポのルートディレクトリで操作していきます2。
% python -V Python 3.10.9 % python -m venv venv % source venv/bin/activate % # プロンプトの(venv)は省略します % pip install -U pip==20.2.4 % pip install -e libA # libA以下のsetup.pyを参照し、lib-aをeditable install % pip install -e libB # lib-bをeditable install % pip list Package Version Location ---------- ------- -------------------------------------------------- lib-a 0.0.1 /.../monorepo-python-practice/libA lib-b 0.0.1 /.../monorepo-python-practice/libB pip 20.2.4 setuptools 65.5.0
出力内容を確認すると、pip install -e libB
のとき、libBのsetup.pyのinstall_requiresに書いたlib-aへの依存は「Requirement already satisfied」として扱われるんですね。
なので、lib-aはeditable installのまま残り、venvには2つのライブラリがeditable installされた状態となります3。
pip 20.3以降
同じ手順を適用すると、lib-aがGitHub(VCS)から再インストールされ、editable installではなくなります。
lib-bのみeditable installとなります(これが悩ましい〜😣)4
% deactivate % python -m venv venv --clear % source venv/bin/activate % pip install -U pip==20.3 % pip install -e libA % pip install -e libB % pip list Package Version Location ---------- ------- -------------------------------------------------- lib-a 0.0.1 lib-b 0.0.1 /.../monorepo-python-practice/libB pip 20.3 setuptools 65.5.0
出力を見るとpip install -e libB
のとき、依存するlib-aについてeditable installはアンインストールされ、VCSからインストールしています。
これによりlib-aはeditable installされていない状態になります。
私はlib-aもeditableのままにしたいのです〜
再度pip install -e libA
とすればやりたい状態にはなります(同じコマンドを2回実行しているのが微妙です。また3つとか5つになったときに現実的かというと、う〜ん...)
% pip install -e libA % pip list Package Version Location ---------- ------- -------------------------------------------------- lib-a 0.0.1 /.../monorepo-python-practice/libA lib-b 0.0.1 /.../monorepo-python-practice/libB pip 20.3 setuptools 65.5.0
試行錯誤ログ
Workaroundとしては以下です。
ですがきれいに解消できていないので、他の方に積極的にオススメしづらいですね。
pip install
の--no-deps
オプション
lib-bをeditable installするところでpip install -e libB --no-deps
とします
https://pip.pypa.io/en/stable/cli/pip_install/#cmdoption-no-deps
Don’t install package dependencies.
lib-bが依存するパッケージ(ここではlib-a)をインストールしません。
これによりlib-aはeditable installのまま残ります。
% deactivate % python -m venv venv --clear % source venv/bin/activate % pip install -U pip==20.3 % pip install -e libA % pip install -e libB --no-deps % pip list Package Version Location ---------- ------- -------------------------------------------------- lib-a 0.0.1 /.../monorepo-python-practice/libA lib-b 0.0.1 /.../monorepo-python-practice/libB pip 20.3 setuptools 65.5.0
lib-bがモノレポ外のサードパーティライブラリに依存した場合(例:requests)、requestsは別途pip installが必要となり、煩雑になっていくように思われます
pip install
の--ignore-installed
オプション
https://pip.pypa.io/en/stable/cli/pip_install/#cmdoption-I
Ignore the installed packages, overwriting them.
% # 仮想環境の再作成。有効化は省略します % pip install -U pip==20.3 % pip install -e libA % pip install -e libB --ignore-installed % pip list Package Version Location ---------- ------- ------------------------------------------------------------------------------- lib-a 0.0.1 /.../monorepo-python-practice/venv/lib/python3.10/site-packages lib-b 0.0.1 /.../monorepo-python-practice/libB pip 20.3 setuptools 65.5.0
lib-aはvenvの下にeditable installされました(GitHubなどのVCSからeditable installは可能です5)。
lib-aを変更する場合、libAの下だけでなくvenv下のソースもいじる必要があり、重複作業が気になりますね。
雑感
手を動かして感じたことの書き出しです。
- pipの新リゾルバは、なぜeditable installしているlib-aをアンインストールという判断をするのだろう?
- 1つの大きなvenvという考え方がよくないのかな
- libA, libBの下に仮想環境を作る方針に切り替える案
- lib-aを変更したあとの、libB下の仮想環境への再インストールもそんなに手間ではないととらえ直す?
- install_requiresにVCSのURLを書くのがよくないのかな(疑心暗鬼になってる)
- Direct referencesというらしい。「Remote URL examples」
- 他の例:requirements.txtを使う方法
- モノレポの例だとPantsを聞くかも
終わりに
モノレポでの開発ですべてのライブラリを1つの仮想環境にeditable installしたいときに、pip 20.3以降の新リゾルバの挙動だとなかなか全部editable installにできなくて悩まされているという共有でした。
私の中では未解決問題です。
これはというアイデアが浮かんだ方、ぜひともお助けくだされ〜(@ftnextまでタレコミ待ってます!)
新リゾルバはなにか事情や妥当な理由があってeditable installをアンインストールするのだと思うので、その意思決定や実装は気になるところです。
- Pythonのパッケージ名ですが、正規化されるのでlib-aもlib_aも同じと今回知りました。ref: パッケージ名の正規化 — Python Packaging User Guide↩
- pyproject.tomlでの検証は宿題です。↩
-
pip 20.2.4で
--use-feature=2020-resolver
を指定したところ、20.3以降の動きが再現しました。このことから新リゾルバの挙動に悩まされているという認識です↩ -
続く手順の
--clear
について(rm
不要なのでオススメです!)↩ - https://pip.pypa.io/en/stable/topics/vcs-support/#editable-vcs-installs↩