2018/04/25

[Python] setup.py に dependency_links を書いても "Could not find a version that satisfies the requirement" が出る場合の対処方法4種

2018/10/16 追記
Pip 18.1 以降は dependency_links を使わない方法が正式になりました。
[dependency_links を使わないでレポジトリを明示的に指定する方法](https://kokufu.blogspot.com/2018/10/dependencylinks.html)
Python で `pip install` 可能なパッケージを作成した際、 [PyPI](https://pypi.org/) に登録してしまえば `pip` が適切に処理してくれるので簡単です。 しかし、内部用のライブラリの場合は明示的にリポジトリの場所を指定しなければなりません。 そのための機能として、`setuptools.setup()` には `dependency_links` という引数があります。 ところが、`pip install` しようとした場合、`dependency_links` は無視されてしまい、うまくいきません。 `dependency_links` は、基本的に `python setup.py install` の場合を想定しているようです。 ただ、`pip` は `setup.py` の上位ラッパーこの表現が適切かどうかは怪しいですがのはず。 対処方法が無いはずはないと思って調べてみました。 ### 普通に `pip install` するとエラーが発生する まずはエラーが発生する状況を説明します。 例として、インハウスレポジトリ `myserver.com` に登録してある `mytestlib` というパッケージを想定します。 この時、`mytestlib` を使用するアプリケーション(mytestapp)の `setup.py` は以下のようになります。 ```python `title: "mytestapp/setup.py"; `highlight: [21, 24]; # -*- coding: utf-8 -*- import setuptools with open('README.md') as f: readme = f.read() with open('LICENSE') as f: license = f.read() setuptools.setup( name='mytestapp', version='0.1', description='Test Application for checking dependency_links', long_description=readme, url='', licence=license, packages=setuptools.find_packages(exclude=('tests', 'docs')), dependency_links=[ 'git+https://myserver.com/kokufu/mytestlib.git#egg=mytestlib-0.1', ], install_requires=[ 'mytestlib==0.1' ], test_suite='tests', entry_points={ 'console_scripts': [ 'mytestapp=mytestapp.main:main' ] } ) ``` これを以下のように `pip` を使ってインストールしようとすると、"Could not find a version that satisfies the requirement mytestlib==0.1" とエラーが発生してしまいます。 ```console `gutter: false; highlight: 5; $ pip install git+ssh://git@myserver.com/kokufu/mytestapp.git Collecting git+ssh://git@myserver.com/kokufu/mytestapp.git Cloning ssh://git@myserver.com/kokufu/mytestapp.git to /tmp/pip-req-build-yxzmlrqy Collecting mytestlib==0.1 (from mytestapp==0.1) Could not find a version that satisfies the requirement mytestlib==0.1 (from mytestapp==0.1) (from versions: ) No matching distribution found for mytestlib==0.1 (from mytestapp==0.1) ``` ### 解決法1 `--process-dependency-links` を使う `pip install` に `--process-dependency-links` をつけると以下のようにインストール可能です。 ```console `gutter: false; highlight: [4, 7]; $ pip install --process-dependency-links git+ssh://git@myserver.com/kokufu/mytestapp.git Collecting git+ssh://git@myserver.com/koufu/mytestapp.git Cloning ssh://git@myserver.com/kokufu/mytestapp.git to /tmp/pip-req-build-1k5_70ia DEPRECATION: Dependency Links processing has been deprecated and will be removed in a future release. Collecting mytestlib==0.1 (from mytestapp==0.1) Cloning https://myserver.com/kokufu/mytestlib.git to /tmp/pip-install-vnodyi4t/mytestlib DEPRECATION: Dependency Links processing has been deprecated and will be removed in a future release. ...略 Successfully installed mytestapp-0.1 mytestlib-0.1 ``` ただ、よく見てみると `DEPRECATION: Dependency Links processing has been deprecated and will be removed in a future release.` との警告が。 `--process-dependency-links` は将来的には無くなる可能性があるわけです。 この DEPRECATION、有効な代替手段が無いようで、DEPRECATION 自体を取りやめるべきだという議論も起きています。 > 参考 > > [Un-deprecate `--process-dependency-links` until an alternative is implemented · Issue #4187 · pypa/pip · GitHub](https://github.com/pypa/pip/issues/4187) 現時点では確実なことは言えませんが、DEPRECATION が取りやめになるか、他に有効な代替手段が提供されるのではないかと思います。
2018/8/24 追記
「有効な代替手段が無いようで」と書いたのですが、[Issue #4187](https://github.com/pypa/pip/issues/4187) のその後の議論で [PEP 508](https://www.python.org/dev/peps/pep-0508/) の `@` 以降にURLを書く方法が有効な代替手段であると結論付けられました。 こちらは、[PR #4175](https://github.com/pypa/pip/pull/4175) で実装され、次のリリースで有効になるようです。 次のリリースは 10月とのことです。それ以降は PEP 508 の `@` を使うのがよいでしょう。
### 解決法2 `--find-links` を使う 多分、`--process-dependency-links` の正統な代替手段なのだと思われますでも使い勝手がすごく悪い。 以下のように、`pip` の実行時に信頼できるパッケージを列挙します。 この時、`setup.py` 内の `dependency_links` は無くてもかまいません。 ```console `gutter: false; $ pip install --find-links="git+https://myserver.com/kokufu/mytestlib.git#egg=mytestlib-0.1" git+ssh://git@myserver.com/kokufu/mytestapp.git ...略 Successfully installed mytestapp-0.1 mytestlib-0.1 ``` > 参考 > > [Python: PyPI にないパッケージを依存パッケージにするには - CUBE SUGAR CONTAINER](http://blog.amedama.jp/entry/2016/02/18/221555) この方法、確かに動作するのですが、依存パッケージの数が増えてくると手間がかかりすぎてしまいます対処方としては README にインストールコマンドを書いておくくらいか?。 また、`mytestlib` パッケージの中でさらに `dependency_links` が書かれている場合、それも `--find-links` で指定しなければなりません。 依存関係が複雑になってきた場合、これは現実的とは言えません。 ### 解決法3 `setup.py install` を使う 以下のように一度 `clone` してから、`python setup.py install` すると `dependency_links` が適切に処理されます。 ```console `gutter: false; $ git clone ssh://git@myserver.com/kokufu/mytestapp.git $ cd mytestapp $ python setup.py install ...略 Finished processing dependencies for mytestapp==0.1 ``` しかし、この方法、せっかく登場した `pip` の恩恵が受けられません。特に `mytestlib` パッケージの中でさらに `dependency_links` が書かれている場合はそれが適切に処理されません。 これは、`--find-links` と同様の問題です。 > 参考 > > [virtualenv - Difference between 'python setup.py install' and 'pip install' - Stack Overflow](https://stackoverflow.com/questions/15724093/difference-between-python-setup-py-install-and-pip-install) ### 解決法4 `--requirement` を使う この方法は解決法とは言えないのですが、一応書いておきます。 まず、以下のような `requirements.txt` を用意します。 ```text `title: "requirements.txt"; -e git+https://myserver.com/kokufu/mytestlib.git#egg=mytestlib -e git+https://myserver.com/kokufu/mytestapp.git#egg=mytestapp ``` `pip --requirement` に先の `requirements.txt` を指定すればインストール可能です。 ```console $ pip install --requirement requirements.txt ...略 Successfully installed mytestapp mytestlib ``` この `--requirement`、そもそも特定の環境をフリーズして別の場所で再現させることを目的とした機能なので、このように使うのが適切とは思えません。 さらに、この方法も `mytestlib` パッケージがさらに内部ライブラリに依存している場合、それらを自分で `requirements.txt` に列挙しなければなりませんそもそも、この方法は別の手段で正しくインストールされた環境があって、それをフリーズするのに使うので、自分で依存関係を探索して列挙するのは本末転倒。 ### 結局、どの方法を使うべきか 上記4つの方法の中で、多段の依存関係を適切に処理できるのは「解決法1 `--process-dependency-links` を使う」だけです。 そのため、現時点では `--process-dependency-links`を使っておくのが良いだろうと思います。 DEPRECATION の警告が出るのが気になるところですが、議論の様子からすると、他に有効な代替手段が出てこない限り削除されることは無いのではないでしょうか。 しばらくは、`--process-dependency-links` を使いながら、議論の行方を注意深く見守るのが良いのだろうと思いますただし、`dependency_links` にあまり信頼できないパッケージを指定するのは止めましょう

0 件のコメント: