YAMAGUCHI::weblog

土足で窓から失礼いたします。今日からあなたの息子になります。 当年とって92歳、下町の発明王、エジソンです。

2012.05版 Python開発のお気に入り構成(ポロリもあるよ)

はじめに

こんにちは、Python界の情弱です。最近は色々とPythonの開発環境も変化してきていて、ようやくPython2.xとPython3.xを行き来しながら開発する体制が整ってきたという印象を受けています。ここしばらくは色々と試していたのですが、ようやく鉄板っぽい方法にたどり着いたのでメモしておきます。
なお、後半はPythonに限らない内容なので、他のLLを使っていても使えそうかなと思っています。この環境を設定すると何ができるのかというと、以下のことすべてが、無料で、自鯖を立てることなく行えます。

  • 開発環境の整理(virtualenv)
  • ローカルでの複数環境のテスト容易化(tox+pytest)
  • CIによるテスト(Travis-CI)
  • ドキュメントの自動ビルドおよびドキュメントの公開(ReadTheDocs)

概要

とりあえず全体像を先に共有しておきます。ちょっとでかいですがご了承ください。
f:id:ymotongpoo:20120515233306p:image
ここで、下の2つ、Travis-CIとReadTheDocsはGitHubからのWebフックでほぼリアルタイムにビルドが始まります。さらにこの2つは無料で利用できます。
またレポジトリの構成は、レポジトリルートにsetup.pyを置いて、その並びでモジュール用ディレクトリ、テスト用ディレクトリ、ドキュメント用ディレクトリ、と置いとくのが一般的っぽい。サンプルとして自分がいま作ってるプロジェクトを晒しておく。

% tree -L 2 . 
.
├── LICENSE
├── README.rst
├── docs
│   ├── Makefile
│   ├── conf.py
│   ├── index.rst
│   └── make.bat
├── hatena2rst
│   ├── __init__.py
│   ├── constants.py
│   ├── main.py
├── pavement.py
├── requirements.txt
├── setup.py
├── test
│   ├── __init__.py
│   └── test_converts.py
└── tox.ini

メイン開発環境

普段コードを書く環境は素の環境を使うのではなく、virtualenvとかを使って開発用メイン環境を用意してやるのがいいんじゃないでしょうか。
ここしばらく色々と紆余曲折してましたが、個人的には次のような形に落ち着きました。

  • Mac OS
    • MacPorts/homebrew/自前ビルド + virtualenvwrapper
  • Linux
    • apt/yum/自前ビルド + virtualenvwrapper
メインのPython自体の管理

通常の開発はどこか1つの仮想環境を使うことになると思うのですが、メインとなるPythonにはとりあえずvirtualenvを入れておく必要があります。2012年5月現在では2.7 (2.7.3)だと思います。自分はMacPorts使ってるのでこんな感じ。

% sudo port install python27
% python -V
Python 2.7.3
% sudo easy_install virtualenv
% sudo easy_install virtualenvwrapper

次は環境変数の設定とかをする。これはMac OSの場合。Linuxは適宜読み替え。自分はzshを使ってるのでこんな感じに設定しておく。関数mkvenvは異なるバージョンのPythonでvirtualenvを作成するためのもの。

PYTHON_VER=2.7
export MACPORTS_PREFIX=/opt/local
export VIRTUALENV_BIN=$MACPORTS_PREFIX/Library/Frameworks/Python.framework/Versions/$PYTHON_VER
export PYTHONPATH=$MACPORTS_PREFIX/lib/python$PYTHON_VER/:$PYTHONPATH
export WORKON_HOME=$HOME/.virtualenvs
. $VIRTUALENV_BIN/bin/virtualenvwrapper.sh

mkvenv () {
	base_python=`which python$1` 
	mkvirtualenv --distribute --python=$base_python $2
}

bashも関数をつくらないと動かないようです。tcshとかだとaliasでいけるんですか?

複数バージョンのPythonの管理

自前ビルドでもOSのパッケージ管理システムでもいいんですが、管理がしやすいやり方でやるのがいいです。
自分はマイナーバージョンさえ合ってれば大体大丈夫なものしか書いてないのでMacPortsで管理します。今日日Python 3.1とか入れなくてもいいという話もあるけど一応。これは主にローカルテスト用です。

% sudo port install python26
% sudo port install python31
% sudo port install python32
メイン開発環境の作成

さっきいろいろとvirtualenvwrapperの設定(mkvenv)とかしたので仮想環境は割と楽に出来ます。
メインの仮想環境はこんな感じで作りました。

% mkvenv 2.7 dev
...
(dev)% python -V
Python 2.7.3

あとは必要なパッケージとかをpipで入れればいい。

(dev)% pip install sphinx flask paver requests lxml tox

その他virtualenv (virtualenvwrapper) 周りの操作はこのエントリで。

ローカルテスト環境

まずテスト管理ツールとしてはtoxが一番楽かなあと思います。toxは複数の環境(異なるPythonのバージョン、異なるパッケージのバージョン)などを一気にテストしてくれるツールで、こいつもvirtualenvを使ってテスト用の環境を作ってくれます。
先程のようにメインの開発環境にtoxをインストールしておいて、こんな感じでtox.iniをレポジトリに置いておきます。

[tox]
envlist = py26, py27, py31, py32

[testenv:py26]
basepython = /opt/local/bin/python2.6

[testenv:py27]
basepython = /opt/local/bin/python2.7

[testenv:py31]
basepython = /opt/local/bin/python3.1

[testenv:py32]
basepython = /opt/local/bin/python3.2

[testenv:docs]
basepython = python
changedir = docs
deps = sphinx
commands =
  sphinx-build -W -b html -d {envtmpdir}/doctrees . {envtmpdir}/html

[testenv]
deps = 
  pytest
  pytest-cov
  mock
  distribute
  lxml

commands =
  py.test \
    --cov-report term-missing \
    --cov hatena2rst \
    --junitxml=junit-{envname}.xml \
    test

これでtoxを走らせればPython2.6からPython3.2まで一気にテストしてくれて楽ですね。テストランナーはpytestでもnoseでもいいんですが、toxを入れれば一緒に入ってくる点、JUnitのレポート吐かせたりするのに余計なモジュール入れなくて済む点、テストが失敗した時の表示が丁寧な点からpytestを使ってます。

VCS + BTS

Travis-CIを使う関係でGitHub一択となっています。Travis-CIが野良VCSとかも含めて対応してくれたらここもbitbucketやGoogle Codeを使うという選択肢が増えるのですが、とりあえず今はそれはできないのでGitHub一択。

CI環境

OSSならTravis-CIで、プロプライエタリなら社内サーバでJenkinsというのがとりあえず楽かなあ、という印象です。
JenkinsとGitHubを連携させてtoxを走らせる話は前に書いたので、ここではTravis-CIの設定について触れます。Travis-CIはRuby界隈の方々には有名なのですが、Pythonでは余り使われていない印象です。無料で使えるCIホスティングサービスで、CIを使ったことなくても気軽に使えるし、テストが通るか確認するだけなら十分な機能を持っています。
GitHubアカウントでログインすれば、レポジトリをトグルでOn/Off切り替えるだけで登録可能という情弱仕様なので、ありがたいです。
Python用のYAMLの例はこんな感じ。設定ファイル名を .travis.yml にしとかないと動かない罠にハマったのは内緒です。(拡張子を .yaml にしてた)

language: python
python:
  - "2.6"
  - "2.7"
  - "3.1"
  - "3.2"
install: 
  - pip install -r requirements.txt --use-mirrors
script:
  - py.test test

ここでrequirements.txtはpipで使ういつものやつです。内容は必要なパッケージ名を改行区切りで書くだけ。例えばこんな感じ。バージョンの指定もできます。

% cat requirements.txt
distribute
lxml>=2.3
pytest>=2.2
pytest-cov>=1.5
mock>=0.8.0

ドキュメントホスティング

バージョン管理、バグトラッキング、テスト、CIまで来たので、最後にドキュメントの部分。ドキュメント生成ツールとしてはPythonにはSphinxという超絶便利ツールがありますが、さらにそのビルドや公開まで自動でやってくれるサービスのReadTheDocsを使っています。サービス登録の方法なんかは以前のエントリで書いたとおりです。

このサービスの良いところは、レポジトリ自体がSphinxプロジェクトになっていなくても、レポジトリ内にSphinxプロジェクトがあれば、ちゃんとそれをビルドしてくれるところです。また生成されたHTML化されたドキュメントのホスティングまでしてくれます。
さらに、きちんとconf.pyを設定しておけばPDF, ePub, HTML zip, manpageまで生成してホスティングしてくれるという太っ腹ぶり。ただしPDFは日本語はフォントがないため消えちゃいます。(ただし通常のHTMLドキュメントページからはそのリンクには辿れない。 http://readthedocs.org/projects//downloads/ が各フォーマットのダウンロードページとなっている)
f:id:ymotongpoo:20120516001858p:image
Sphinxの使い方に関してはこちらを参照してください。

GitHub pagesを使うという手ももちろんあるのですが、xxxx.github.comのレポジトリだとコードとドキュメントが分離しちゃうし、gh-pagesブランチを作る場合でも、Sphinxを使う場合はビルドしたHTMLの出力先とか諸々気を遣うので、気軽にできるReadTheDocsの方がいいかなあと思います。
ちなみに「ReadTheDocsなんて聞いたことねえよ」っていうことで心配になるかもしれませんが、PSFやMozillaも出資したりしてるので、当面はサービス終了したりは無いと思います。

まとめ

とりあえず、いまはこんな感じの環境を使っています。

  • Pythonの管理 : MacPorts/homebrew または自前ビルド
  • 仮想環境管理 : virtualenv + virtualenvwrapper
  • ローカルテスト : tox + pytest
  • VCS+BTS : GitHub
  • CI : Travis-CI
  • ドキュメント : ReadTheDocs

VCS以降は言語関係ないので、とりあえずSphinxのドメイン*1Travis-CIが対応しているところで言うと、RubyPHPErlang、Node.jsなんかも使えます。*2
とりあえずこれだけのことが労せずできちゃうので、もうテストしてませんとか、CIしてませんとか、ドキュメント書いてません、とか言えねえなあ、という感じ。大変だ。
プロプライエタリなプロジェクトの場合はPythonプロフェッショナルプログラミングのほうに事細かに載っているので割愛。

Pythonプロフェッショナルプログラミング

Pythonプロフェッショナルプログラミング


ポロリ。

*1: [http://sphinx-users.jp/doc10/domains.html] 参照

*2:RubyErlangは追加でsphinx-contribからドメインに対応するためのパッケージを入れないといけない