俺的モダンなPythonのOSS開発環境

趣味プログラマです、こんにちわ。一応生きてます。

さて、Pythonista各位におかれましてはmoratoriumをエンジョイされていますでしょうか。そろそろライブラリも著名なものはPython3に対応してきましたし、そろそろ本格的にPython3、となっているころ合いですね。というか、Python3に対応してないとちょっと恥ずかしくなってきましたね。

とはいえ、Python2は根強く残るでしょう。というわけでPython2とPython3両方で動くコードを書きましょう。テストも書くのは当たり前ですし、せっかくなのでCIもしましょう。

と私も最近思ったので快適に開発を進めるための環境についてメモです。

  • github : 言わずもがなですね。
  • travis : githubと連携してCIできるサービス。P言語にも対応していて、最近アツいです。
  • tox : 複数のPython処理系でvirtualenvを作りテストを流せる。
  • distribute : 改良版setuptools。
  • pytest : toxと親和性の高いテストツール。noseでもよいですが私はpytestを押します。

Python2とPython3のインストール

あたりまえですが、Python2系とPython3系両方入れておきましょう。

toxのインストール

さて、早速toxを入れていくわけですがこれにはPython2系を使います。

$ wget http://python-distribute.org/distribute_setup.py 
$ python27 distribute_setup.py
$ easy_install virtualenv tox

簡単ですね。

プロジェクトを始める - ファイル・ディレクトリ構成

次に、プロジェクトの基本形を作りましょう。私は以下のような構成にしています。

/
  + - .tox                        : toxにより生成されるディレクトリ。
  + - docs                        : ドキュメント系はココ。
           + - source             : ドキュメントのソース。
           + - build
                     + - html(link to gh-pages)
                                  : sphinxで生成されたHTMLドキュメント。
                                    gh-pagesブランチへのリンク。
  + - src                         : ソースファイル類。
           + - プロジェクト名
           + - tests
  - tox.ini                       : tox設定ファイル。
  - .travis.yml                   : travis設定ファイル。
  - setup.py                      : セットアップスクリプト。
  - MANIFEST.in                   : 配布パッケージ生成用定義ファイル。
  - README.rst                    : 私を読んで。
  - CHANGES.rst                   : 変更履歴。

普通です。ポイントは docs/build/html をgh-pagesへのリンクにすること。これでドキュメントの管理が非常に楽になります。

tox.iniの作成

tox.iniに依存関係と、どの処理系でテストするか、テストはなにを使ってやるかを書きましょう。だいたいの場合、それだけで十分です。

[tox]
envlist = py27,py32

[testenv]
changedir=src/tests
deps=pytest
     pytest-cov
     その他依存パッケージ
commands=
  py.test \
    -rxs \
    --cov-report term-missing \
    --cov テスト対象パッケージ名\
    --basetemp={envtmpdir}  \ 
    []                        

見ての通りの内容です。Pytnon27とPython32でテストします、と。この時処理系のパス(python.exeやpython27などのパス)はOSごとに デフォルト の場所が使われます。 --configure でprefixを指定していたり、Windowsで別フォルダにインストールしている場合は以下のようにします。

[tox]
envlist = py27,py32

[testenv:py27]
basepython=処理系へのパス

[testenv:py32]
basepython=処理系へのパス

[testenv]
changedir=src/tests
deps=pytest
     pytest-cov
     その他依存パッケージ
commands=
  py.test \
    -rxs \
    --cov-report term-missing \
    --cov テスト対象パッケージ名\
    --basetemp={envtmpdir}  \ 
    []                        

とりあえず開発

とりあえず何かコードを書いて、テストも書きましょう。

toxでテスト

ではtoxでテストしましょう。tox.iniがあるディレクトリに移動してから

$ tox

これで

  • それぞれの処理系のvirtualenvの作成
  • 依存ライブラリのインストール
  • テストの実行

が行われ、結果が表示されます。py27だけ流したい場合は tox -e py27 とするか環境変数 TOXENV=py27 を設定したうえで tox とすればOK.

拙作のwebフレームワーク rays ですと以下のような感じです(長いのでpy32の結果のみ)。pytest-covを入れているのでC0カバレッジも表示されます。

_________________________________________________________________________________________ [tox sdist] __________________________________________________________________________________________
[TOX] ***creating sdist package
[TOX] /home/yuin/github/rays$ /opt/python2.7.2/bin/python2.7 setup.py sdist --formats=zip --dist-dir .tox/dist >.tox/log/0.log
[TOX] ***copying new sdistfile to '/home/yuin/.tox/distshare/rays-0.4.0.zip'
______________________________________________________________________________________ [tox testenv:py32] ______________________________________________________________________________________
[TOX] ***creating virtualenv py32
[TOX] /home/yuin/github/rays/.tox$ /opt/python3.2.2/bin/python3.2 /opt/python2.7.2/lib/python2.7/site-packages/virtualenv-1.7.1.2-py2.7.egg/virtualenv.py --no-site-packages py32 >py32/log/0.log
[TOX] ***installing dependencies: pytest, pytest-cov, webtest, sphinx
[TOX] /home/yuin/github/rays/.tox/py32/log$ ../bin/pip install --download-cache=/home/yuin/github/rays/.tox/_download pytest pytest-cov webtest sphinx >1.log
[TOX] ***installing sdist
[TOX] /home/yuin/github/rays/.tox/py32/log$ ../bin/pip install --download-cache=/home/yuin/github/rays/.tox/_download /home/yuin/github/rays/.tox/dist/rays-0.4.0.zip >2.log
[TOX] /home/yuin/github/rays/src/tests$ ../../.tox/py32/bin/py.test -rxs --cov-report term-missing --cov rays --basetemp=/home/yuin/github/rays/.tox/py32/tmp
===================================================================================== test session starts ======================================================================================
platform linux2 -- Python 3.2.2 -- pytest-2.2.3
collected 120 items

test_application.py ........................
test_async_extension.py sss
test_database.py .......
test_defaultattrdict.py .....
test_extension.py .
test_functions.py .........
test_hookable.py .....
test_request.py .....................
test_response.py ...............
test_session.py ............
test_staticfile_extension.py .....
test_templating.py .............
----------------------------------------------------------------------- coverage: platform linux2, python 3.2.2-final-0 ------------------------------------------------------------------------
Name                                           Stmts   Miss  Cover   Missing
----------------------------------------------------------------------------
/home/yuin/github/rays/src/rays/__init__    1648    190    88%   82, 259, 807-808, 824-839, 842-888, 892-901, 909-917, 925-933, 946-954, 1408, 1509, 1595-1597, 1934-1943, 1973, 2033-2063, 2088-2089, 2547-2560, 2563-2571, 2574-2575, 2579-2585, 2589, 2593-2596, 2600, 2604-2615
/home/yuin/github/rays/src/rays/compat        98     42    57%   11-13, 17, 19-20, 67-118
----------------------------------------------------------------------------
TOTAL                                           1746    232    87%
=================================================================================== short test summary info ====================================================================================
SKIP [3] /home/yuin/github/rays/.tox/py32/lib/python3.2/site-packages/_pytest/skipping.py:118: condition: SkipIf._no_gevent

============================================================================ 117 passed, 3 skipped in 14.81 seconds ============================================================================
________________________________________________________________________________________ [tox summary] _________________________________________________________________________________________

.travis.ymlの作成

無事、複数のインタプリタでテストできました。次はCIです。 Travis CI を使うと、githubにpushしたタイミングでビルド&テストが自動でできます。

まずは、Travis CIにgithubのアカウントでログインして、対象のレポジトリでCIを有効にします。

次に、Travis CIでのビルド&テスト設定を.travis.ymlに書きます。ここではtoxを使っていますから、以下のようになります。

language: python
env:
  - TOXENV=py27
  - TOXENV=py32
install: 
  - pip install --use-mirrors tox
script: tox

TOXENV でテストする環境を指定します。今回の例ではpy27とpy32です。

これでgithubにpushするとTravis CIが動くようになりました。

Travis CI + tox快適です

ガンガンPython3対応をしましょう!

comments powered by Disqus