ライブラリの配布について

Pythonのパッケージ管理はいろいろと変遷していて、なにがベストなのかよく分かりません……。

パッケージ管理ツールのいろいろ

とりあえずパッケージ管理の仕組みについてキーワードを上げてみると、

  • distutils (python標準だが機能不足。コマンドはなかった)
  • setuptools (distutilsの置き換え。コマンドeasy_install)
  • distribute (setuptoolsの機能強化クローン。setuptoolにマージされたことでdeprecatedになった)
  • pip (easy_installの便利コマンド版)
  • distutils2 (setuptools/distutilの仕組みを取り入れた→packagingに変更)
  • packaging (python3.3の標準でsetuptools, easy_install相当だったがやっぱりpython3.3には入らなかった)
  • distlib (python3.4に入る予定?)

らしい。間違っていたら指摘してください。

「distutilsは機能不足なので、setuptoolを使う」
→「setuptoolsはメンテされてないのでpython3なんかを考慮するとdistributeを使うべき」
→「distributeはsetuptoolsに結局マージされたからやっぱりsetuptoolsを使うべき」
→「python標準で運用されるべきだからdistuitls2/packaging使うべき」
→「packagingは削除された」

みたいな流れになっているように思う。

distributeはもうsetuptoolsにマージされてdeprecatedになったので使うべきではなくて、distutils2/packagingは公式として期待されていたもののこれも削除されてしまい使わないほうが良さそうなので、python2.7環境で安定して使えそうなのはsetuptoolsかと思う。(将来的にはdistlibなんでしょうか)

配布用のsetup.pyを記述する

Pythonはライブラリ配布用にsetup.pyというスクリプトを記述する。これは定義ファイルではなくて、これ自体がpythonのスクリプトになっている。スクリプト記述用のツールライブラリとして先ほど上げたようなsetuptoolsのようなパッケージがあるので、定義ファイルのようにスクリプトを記述できる。

配布物としてはpythonソースコード以外のビルド成果物など詳細な記述ができるが、ここでは最も簡単なソースコード配布物について記述する。

特定のフォルダにsrcというソース用ディレクトリがあるとする。

 ./
 ├── setup.py
 ├── src
     ├── __init__.py
     ├── foo.py
     └── hoge
         ├── __init__.py
         └── bar.py

このfooモジュール,hogeパッケージのbarモジュールを配布を考える。

python標準のdistutilsでの記述

distutilsよりはsetuptoolsを使ったほうが多機能なのだが、まずは公式ライブラリとしてのdistutilsについて説明する。
setup.pyは以下のようになる。

from distutils.core import setup

setup(name='foo',
        version='1.0',
        packages = ["hoge"],
        py_modules = ["foo"],
        package_dir = {'': 'src'}
    )

記述内容は最小限にしてあるので詳細は公式ドキュメントを参照。
http://docs.python.jp/2/distutils/introduction.html

packagesではパッケージを指定することでそのパッケージ内のすべてのモジュールをインストール対象にする。パッケージのないモジュールや小さいモジュールであれば、py_modulesでモジュールそのものを指定する。

今回の例であればpackagesの指定はなくして、pymodules=["foo", "hoge.bar"]と記述してもよい。パッケージ内に大量にモジュールがある場合はpackagesで指定する。

packageを取得するときにsrcフォルダをルートとして探す必要があるので、package_dirで検索位置を指定してある。「特定のパッケージ: このディレクトリ」というように複数の指定ができる。

これでソースコード配布物を生成するには、

$ python setup.py sdist

とすることで、distフォルダにfoo-1.0.tar.gzが生成さる。配布物を受け取ってインストールする側は、

$ gunzip -c foo-1.0.tar.gz | tar xf -    # unpacks into directory foo-1.0
$ cd foo-1.0
$ python setup.py install

のように展開後に同じsetup.pyを使ってinstallコマンドを実行する。

インストールはpythonのlib/site-packagesに入るので、システムpythonを使っていると書き込み権限がない可能性がある。virtualenvで仮想環境を作るとよい。

配布の方法については、「配布物をどうにかして渡す」「PyPIに登録する」「自前のPyPIを作成してそこに登録する」などが考えられるが、pipを使ってインストールする前提で、「リポジトリから直接インストールする」という方法を後述する。

setuptoolsでの記述

setuptoolsを使うことで、拡張された記述や実行スクリプトを登録したりできる。今回のモジュールではそれほどdistutilsに比べた差はないが、詳しくはドキュメントを参照。http://pythonhosted.org//setuptools/

setuptoolsではtestを実行することもできるので、srcディレクトリと同じ階層にtestディレクトリとコードを用意した。

 ./
 ├── setup.py
 ├── src
 │   ├── __init__.py
 │   ├── foo.py
 │   └── hoge
 │       ├── __init__.py
 │       └── bar.py
 └── test
     └── foo_test.py

foo_test.pyはfooモジュールのテストをする。

import foo
import unittest

class FooTest(unittest.TestCase):
    def test_hello(self):
        pass  #test code.

def suite():
    suite = unittest.TestSuite()
    suite.addTests(unittest.makeSuite(FooTest))
    return suite

setup.pyはdistuitlsから少し拡張した指定ができるようになる。

from setuptools import setup, find_packages
import sys

sys.path.append('./test')

setup(name='foo',
        version='1.0',
        packages = find_packages("src"),
        py_modules = ["foo"],
        test_suite = "foo_test.suite",
        package_dir = {'': 'src'}
    )

packagesでパッケージを列挙するのが面倒な場合は、find_packagesを使って、フォルダを指定して勝手に検索さえることができる。srcフォルダをルートしたが直下を検索する場合は引数指定は不要。除外条件なども指定ができる。
https://setuptools.readthedocs.io/en/latest/setuptools.html#using-find-packages

配布物の生成は、distutilsと同じように、python setup.py sdistで生成できる。

test_suiteはテストSuiteの指定になる。テストコードはtestディレクトリになるので、sys.pathに追加してある。

テストを実行する場合は、

$ python setup.py test

で実行できる。

配布の方法

setup.pyを記述して配布物を生成し、PyPIにアップして公開・配布するのが正当な方法であると思うが、社内ライブラリなど簡便に配布する仕組みを考えた場合にgitなどのvcs管理下からインストールする楽なので、ここではその方法を紹介する。

gitに登録されたプロジェクトからpip経由でインストールする。(この場合setup.pyで生成された配布成果物は使用しない)

gitリポジトリ http://git.example.com/my-library.git に登録されている場合、pipコマンドでインストールできる。

$ pip install git+http://git.example.com/my-library.git#egg=my-library

gitリポジトリ直下にsetup.pyが存在する必要がある。tagやbranchを指定することで特定のバージョンを取得するような設定も可能。

$ pip install git+http://git.example.com/my-library.git@mybranch#egg=my-library

詳細はドキュメント参照。http://www.pip-installer.org/en/latest/logic.html#vcs-support (ただ、subdiretoryの指定はよく分からなかった)

pythonでの環境構築で記載したようにrequirements.txtにも記載できる。
「社内ライブラリを作成」→「gitに登録」→「ライブラリを利用するモジュールで依存関係に追加」という利用の仕方が可能になる。

関連記事:

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)