Python のパッケージを作っていると、特定の環境だけで必要となるパッケージが大抵はでてくる。 例えばデータベースを扱うアプリケーションなら、使う RDBMS によってデータベースドライバのパッケージが異なる。 あるいは、インストール先の Python のバージョンによっては標準ライブラリに用意されていないパッケージのバックポート版をインストールしなきゃいけない。 今回は、そんなときに便利なセットアップスクリプト (setup.py) の extras_require 引数を使ってみる。
使った環境は次の通り。
$ sw_vers ProductName: Mac OS X ProductVersion: 10.11.5 BuildVersion: 15F34 $ python --version Python 3.5.1
下準備
まず最初に題材とするのはデータベースを扱うアプリケーションにしよう。 前述した通り、この状況では使う RDBMS によって異なるデータベースドライバをインストールしなきゃいけない。 今回は RDBMS に MySQL と Postgresql を使い分ける状況を想定しよう。
データベースドライバをビルドするために MySQL と Postgresql をインストールしておく。
$ brew install mysql postgresql
次に、題材とするアプリケーション本体のソースコード。 これには SQLAlchemy を使ってモデルを定義したモジュールを mydbapp という名前で保存しておく。 ただし、今回これはあくまで単なる例に過ぎないので実際に動かしたりすることはない。
$ cat < 'EOF' > mydbapp.py #!/usr/bin/env python # -*- coding: utf-8 -*- from sqlalchemy.ext.declarative.api import declarative_base from sqlalchemy.sql.schema import Column from sqlalchemy.sql.sqltypes import BigInteger from sqlalchemy.sql.sqltypes import Text Base = declarative_base() class User(Base): """データベースのスキーマの元になるモデル""" __tablename__ = 'users' id = Column(BigInteger, primary_key=True) name = Column(Text, nullable=False) EOF
サンプルコードにセットアップスクリプトを書く
それでは、今回の本題となるセットアップスクリプト (setup.py) を書いてみることにする。
アプリケーションが共通で必要とするパッケージについては通常どおり install_requires に記述しよう。 今回においては SQLAlchemy がこれに当たる。 そして、環境に依存するデータベースドライバは extras_require に辞書の形で渡す。 辞書のキーは環境の名前で、バリューにはパッケージの入ったリストを指定することになる。 今回であれば mysql には mysqlclient を、そして postgresql には psycopg2 を指定している。
$ cat << 'EOF' > setup.py #!/usr/bin/env python # -*- coding: utf-8 -*- from setuptools import setup def main(): setup( name='mydbapp', version='0.0.1', zip_safe=False, py_modules=['mydbapp'], install_requires=[ # どのような環境でも SQLAlchemy は必要になる 'SQLAlchemy', ], extras_require={ # 使う RDBMS ごとに、それ専用のドライバが必要になる 'mysql': ['mysqlclient'], 'postgresql': ['psycopg2'], }, ) if __name__ == '__main__': main() EOF
これで mydbapp モジュールをインストールできるようになった。
環境を指定してインストールする
pip install サブコマンドでは setup.py のあるディレクトリを指定することで、そのパッケージ (モジュール) をインストールできる。 このとき extras_require を使ったものであれば、角括弧で環境を指定する。
それでは、環境として mysql を指定してインストールしてみよう。
$ pip install .[mysql] ...(省略)... Running setup.py install for mydbapp ... done Successfully installed SQLAlchemy-1.0.13 mydbapp-0.0.1 mysqlclient-1.3.7
インストールされたパッケージを確認すると SQLAlchemy や mydbapp に混じって mysqlclient が見つかる。
$ pip list mydbapp (0.0.1) mysqlclient (1.3.7) pip (8.1.2) setuptools (23.0.0) SQLAlchemy (1.0.13) wheel (0.29.0)
同じように postgresql を指定したときはどうなるだろうか。
$ pip install .[postgresql] ...(省略)... Running setup.py install for mydbapp ... done Successfully installed SQLAlchemy-1.0.13 mydbapp-0.0.1 psycopg2-2.6.1
先ほどとは異なり psycopg2 がインストールされている。 ちなみに Python の仮想環境は作りなおしている。
$ pip list mydbapp (0.0.1) pip (8.1.2) psycopg2 (2.6.1) setuptools (23.0.0) SQLAlchemy (1.0.13) wheel (0.29.0)
もちろん、環境の指定は pip install 以外のサブコマンドにも有効になっている。 例えば Wheel をビルドするときも指定すれば環境ごとの内容になる。
$ pip wheel .[mysql] $ ls | grep whl$ SQLAlchemy-1.0.13-cp35-cp35m-macosx_10_11_x86_64.whl mydbapp-0.0.1-py3-none-any.whl mysqlclient-1.3.7-cp35-cp35m-macosx_10_11_x86_64.whl
Python のバージョンごとに依存ライブラリを切り替える
extras_require には、環境の名前を指定してインストールする以外にも便利な使い方がある。 例えば Python のバージョンごとにインストールする依存ライブラリを切り替えることができる。
それでは、例としてアプリケーションが ipaddress モジュールに依存している場合を考えてみよう。 ipaddress モジュールは Python 3.3 で新たに標準ライブラリの仲間入りを果たしたモジュールだ。 つまり、それ以前のバージョンでは使うことができない。 ただし、バックポート版を PyPI からダウンロードしてインストールすることはできる。
次のセットアップスクリプトでは Python のバージョンが 3.3 未満のときだけ ipaddress モジュールをインストールするようにしよう。 これには「:python_version<"3.3"」といった書式で extras_require のキーを指定する。
$ cat << 'EOF' > setup.py #!/usr/bin/env python # -*- coding: utf-8 -*- from setuptools import setup def main(): setup( name='mydbapp', version='0.0.1', zip_safe=False, py_modules=['mydbapp'], install_requires=[ # どのような環境でも SQLAlchemy は必要になる 'SQLAlchemy', ], extras_require={ # 使う RDBMS ごとに、それ専用のドライバが必要になる 'mysql': ['mysqlclient'], 'postgresql': ['psycopg2'], # Python 3.3 未満には ipaddress が標準ライブラリにない ':python_version<"3.3"': [ 'ipaddress', ], }, ) if __name__ == '__main__': main() EOF
それでは、上記を Python 2.7 の環境にインストールしてみよう。
$ python --version Python 2.7.10 $ pip install . ...(省略)... Running setup.py install for mydbapp ... done Successfully installed SQLAlchemy-1.0.13 ipaddress-1.0.16 mydbapp-0.0.1
ipaddress モジュールがインストールされていることがわかる。
$ pip list ipaddress (1.0.16) mydbapp (0.0.1) pip (8.1.2) setuptools (23.0.0) SQLAlchemy (1.0.13) wheel (0.29.0)
次に Python 3.5 にもインストールしてみる。
$ python --version Python 3.5.1 $ pip install . ...(省略)... Running setup.py install for mydbapp ... done Successfully installed SQLAlchemy-1.0.13 mydbapp-0.0.1
今度は ipaddress モジュールはインストールされていない!
$ pip list mydbapp (0.0.1) pip (8.1.2) setuptools (23.0.0) SQLAlchemy (1.0.13) wheel (0.29.0)
ちなみに、上記で登場したバージョンの指定方法は PEP 426 という仕様で規定されているらしい。 具体的には、その中の Environment Markers だ。
Environment Markers については、次のブログ記事が詳しかった。 ちなみに、システムのプラットフォーム (Linux だとか Windows だとか) やアーキテクチャ (i386 や x86_64) まで判定できるようだ。
2014/07/10 PEP-0426 Environment Markers の調査 - 清水川Web
スマートPythonプログラミング: Pythonのより良い書き方を学ぶ
- 作者: もみじあめ
- 発売日: 2016/03/12
- メディア: Kindle版
- この商品を含むブログを見る