PyPI に無いパッケージを自作パッケージの依存ライブラリにしようとしたら色々と苦労したので、そこで得られた知見を共有しておく。 どうやら現状では setuptools と pip で対応方法が異なっているために、それぞれで微妙に異なるやり方を取る必要があるようだ。
今回使った環境は次の通り。
$ sw_vers ProductName: Mac OS X ProductVersion: 10.11.3 BuildVersion: 15D21 $ python --version Python 3.5.1 $ pip list pip (8.0.2) setuptools (20.1.1) wheel (0.24.0)
自作パッケージを用意する
まずは動作確認に使う自作パッケージを用意する。 名前は mypackage にしよう。 パッケージは枠だけ用意して中身は空っぽにする。 今回、パッケージ自体は関心の外にあるため。
$ mkdir mypackage $ touch mypackage/__init__.py
次にパッケージに対してセットアップスクリプトを書く。 これでパッケージ mypackage がインストール可能になる。
$ cat << 'EOF' > setup.py #!/usr/bin/env python # -*- coding: utf-8 -*- from setuptools import setup def main(): setup( name='mypackage', version='0.0.1', zip_safe=False, packages=['mypackage'], ) if __name__ == '__main__': main() EOF
早速セットアップスクリプトを使って今の環境に mypackage をインストールしよう。
$ python setup.py install
パッケージをインストールすると pip list サブコマンドで mypackage が見えるようになる。
$ pip list | grep mypackage mypackage (0.0.1)
もちろん Python でインポートして使うこともできる。 まあ、中身は空っぽだけど。
$ python -c "import mypackage"
PyPI にない依存パッケージを追加する
さて、ここまででやっとスタートラインに立てた。 作成した mypackage に PyPI には置かれていない依存パッケージを追加してみよう。 追加するのは自分で作った以下のジョークパッケージにする。
PyPI にないパッケージを依存パッケージに追加するには次のドキュメントが参考になる。
Specifying Dependencies — Python Packaging Tutorial
通常であれば依存パッケージは setuptools.setup() 関数の install_requires 引数に名前を追加して終わりだ。 しかし、追加したいパッケージが PyPI に無いときは dependency_links の指定も必要になる。 ここにインストールに使うリンクを記述する。
$ cat << 'EOF' > setup.py #!/usr/bin/env python # -*- coding: utf-8 -*- from setuptools import setup def main(): setup( name='mypackage', version='0.0.1', zip_safe=False, packages=['mypackage'], install_requires=[ 'wehatemtg==0.0.1', ], dependency_links=[ 'git+https://github.com/momijiame/wehatemtg.git#egg=wehatemtg-0.0.1', ] ) if __name__ == '__main__': main() EOF
セットアップスクリプトを修正したら、もう一度 mypackage をインストールし直そう。
$ python setup.py install
今度は依存パッケージの wehatemtg が一緒にインストールされるようになった。
$ pip list | grep wehatemtg wehatemtg (0.0.1)
これで、セットアップスクリプトを使ったインストールで PyPI にないパッケージを依存パッケージに追加できるようになった。
pip で PyPI にない依存パッケージを扱う
めでたしめでたし、と行きたいところだけど残念ながらそうはいかない。 実は問題は pip を使ったときに発生する。
まずは一旦依存パッケージの wehatemtg をアンインストールしておこう。
$ pip uninstall -y wehatemtg
次に mypackage をソース配布物としてビルドする。
$ python setup.py sdist
できあがったソース配布物を pip コマンドでインストールしてみよう。
$ pip install dist/mypackage-0.0.1.tar.gz Processing ./dist/mypackage-0.0.1.tar.gz Requirement already satisfied (use --upgrade to upgrade): mypackage==0.0.1 from file:///Users/amedama/Documents/temporary/package-not-on-pypi in /Users/amedama/.virtualenvs/temporary/lib/python3.5/site-packages Collecting wehatemtg==0.0.1 (from mypackage==0.0.1) Could not find a version that satisfies the requirement wehatemtg==0.0.1 (from mypackage==0.0.1) (from versions: ) No matching distribution found for wehatemtg==0.0.1 (from mypackage==0.0.1)
見事にエラーになった。 wehatemtg をインストールしようとしたけど見つからないらしい。
何故エラーになるのだろうか? pip のソースコードを調べたところ原因が判明した。 次を見てもらいたい。
ここには次のようなコメントがある。
# We trust every url that the user has given us whether it was given # via --index-url or --find-links # We explicitly do not trust links that came from dependency_links # We want to filter out any thing which does not have a secure origin.
つまり pip はセットアップスクリプトの dependency_links を信用しないらしい。 PyPI にないパッケージをインストールするときは --index-url か --find-links オプションを明示的に指定する必要があるようだ。
ではそのコメントにしたがってオプションをつけて実行してみよう。
$ pip install dist/mypackage-0.0.1.tar.gz --find-links=git+https://github.com/momijiame/wehatemtg.git#egg=wehatemtg-0.0.1 ...(省略)... Successfully installed wehatemtg-0.0.1
今度は上手くいった。
$ pip list | grep wehatemtg wehatemtg (0.0.1)
まとめ
今回は PyPI にないパッケージを依存パッケージにする方法について書いた。 基本的には setuptools.setup() 関数の dependency_links 引数にパッケージのインストール元 URL を記述すれば良い。 ただし、どうやら pip はそこに書いてある内容を信用しないのでコマンド実行時にオプションで渡してやる必要がある点に注意が必要だ。

スマートPythonプログラミング: Pythonのより良い書き方を学ぶ
- 作者: もみじあめ
- 発売日: 2016/03/12
- メディア: Kindle版
- この商品を含むブログを見る