CUBE SUGAR CONTAINER

技術系のこと書きます。

Python: caniusepython3 で Python 3 非対応の依存パッケージを見つける

先日の記事で Python 2.x/3.x の互換性に関するツールをいくつか紹介したけど、詳しい使い方までは書くことができなかった。 今回は、その中のひとつ caniusepython3 について紹介してみる。

blog.amedama.jp

caniusepython3 とは

caniusepython3 は、プロジェクトの依存パッケージの中に Python 3 非対応のものがないかを見つけるためのツール。 自作パッケージを Python 3 に対応させる際、依存パッケージの中にひとつでも Python 3 対応していないものがあると Python 3 環境では動作させることができなくなる。

しかし、依存パッケージは更に別のパッケージに依存していたりする。 自分で対応状況を再帰的に確かめていくのは手間のかかる作業だ。 caniusepython3 は、その手間を大幅に減らしてくれる。

caniusepython3 をインストールする

caniusepython3 は PyPI に登録されているので pip や easy_install といったパッケージマネージャでインストールできる。

$ pip install caniusepython3

インストールすると、同名の caniusepython3 コマンドが使えるようになる。

$ caniusepython3 --help
usage: caniusepython3 [-h] [--requirements REQUIREMENTS [REQUIREMENTS ...]]
                      [--metadata METADATA [METADATA ...]]
                      [--projects PROJECTS [PROJECTS ...]] [--verbose]

Determine if a set of project dependencies will work with Python 3

optional arguments:
  -h, --help            show this help message and exit
  --requirements REQUIREMENTS [REQUIREMENTS ...], -r REQUIREMENTS [REQUIREMENTS ...]
                        path(s) to a pip requirements file (e.g.
                        requirements.txt)
  --metadata METADATA [METADATA ...], -m METADATA [METADATA ...]
                        path(s) to a PEP 426 metadata file (e.g. PKG-INFO,
                        pydist.json)
  --projects PROJECTS [PROJECTS ...], -p PROJECTS [PROJECTS ...]
                        name(s) of projects to test for Python 3 support
  --verbose, -v         verbose output (e.g. list compatibility overrides)

特定パッケージの対応状況を調べる

PyPI に登録されている特定のパッケージが Python 3 に対応しているか調べるには -p オプションにパッケージ名を指定する。

試しに Python 3 に対応していないパッケージのひとつ mysql-python をチェックしてみよう。

$ caniusepython3 -p mysql-python
Finding and checking dependencies ...
[WARNING] Stale overrides: set([u'botocore', u'rsa', u'unicodecsv', u'djangocms-admin-style', u'python-memcached', u'zc.recipe.egg'])

You need 1 project to transition to Python 3.
Of that 1 project, 1 has no direct dependencies blocking its transition:

  mysql-python

上記の通り mysql-python が Python 3 に対応していないことが表示された。

反対に Python 3 に対応しているパッケージとして requests を調べてみよう。

$ caniusepython3 -p requests
Finding and checking dependencies ...
[WARNING] Stale overrides: set([u'botocore', u'rsa', u'unicodecsv', u'djangocms-admin-style', u'python-memcached', u'zc.recipe.egg'])

🎉  You have 0 projects blocking you from using Python 3!

今度は Python 3 に対応していないパッケージは存在しない旨が表示された。

依存パッケージが記述されたテキストファイルから一度にチェックする

最近の Python プロジェクトでは、動作やテスト時に必要となるパッケージをテキストファイルの中に記述するのがデファクトスタンダードになりつつある。 これは、現在主流となっているパッケージマネージャの pip が、-r オプションでそのテキストファイルを引数にして動作できるためだろう。

例えば requests に関しては動作に必要なパッケージを requirements.txt というファイルに記述している。

https://github.com/kennethreitz/requests/blob/master/requirements.txt

では、その流儀に従って動作とテストに必要なパッケージを記述したテキストファイルをそれっぽく作ってみよう。

$ cat << EOF > requirements.txt
mysql-python
requests
EOF
$ cat << EOF > test-requirements.txt
nose
coverage
EOF

このテキストファイルに記述されているパッケージを調べるには caniusepython3 コマンドで -r オプションの後にファイルパスを指定する。

$ caniusepython3 -r requirements.txt test-requirements.txt
Finding and checking dependencies ...
[WARNING] Stale overrides: set([u'botocore', u'rsa', u'unicodecsv', u'djangocms-admin-style', u'python-memcached', u'zc.recipe.egg'])

You need 1 project to transition to Python 3.
Of that 1 project, 1 has no direct dependencies blocking its transition:

  mysql-python

テキストファイルに記述されたパッケージ名から Python 3 非対応の mysql-python が見つかった。

動作原理

caniusepython3 がどのようにして Python 3 に対応しているパッケージとしていないパッケージを判別しているか不思議に思った人もいるはずなので、それについても解説しておくことにする。

Python のパッケージをインストールするために作成するセットアップスクリプト (setup.py) には、そのパッケージに関する情報を登録しておくための classfiers というフィールドがある。 この中に Python 3 に対応しているか否かを表す 'Programming Language :: Python :: 3' という種別が用意されている。

例えば requests であれば以下の行がそれに当たる。 https://github.com/kennethreitz/requests/blob/master/setup.py#L67

PyPI に登録されているパッケージの classfiers の情報は API 経由で取得できるため、caniusepython3 はそれを利用してパッケージが Python 3 に対応しているか否かを判断している。

まとめ

今回は caniusepython3 を使って、依存パッケージの中に Python 3 非対応のものがないか調べる方法について書いた。 もし Python 3 対応していないものが見つかった場合には、対応したものに切り替えたりするなどしよう。 あるいは、対応パッチを送ることができるという点で日頃お世話になっているプロジェクトにコントリビュートするチャンスと捉えることもできる。