pipとwheelでテスト環境構築をスピードアップ

まず最初にお知らせ。 travisでtoxをつかうtips で、travisにpython3.4をインストールして、toxの環境振り分けをするってのを書きましたが、すでにtravisでpython3.4使えるようなので、事前のapt-getは不要となりました。

そして、 ubuntus 14.04 trusty では python3.4がデフォルトでインストールされているようですが、 ensure-pip が入っていないという罠により pyvenv するとエラーになります。 とりあえず debian系の python パッケージは変なパッチあたってるのも、そろそろいい加減にしてほしいところなので、もうしばらくはpython3.4はソースインストールでやっていくことにします。

ここから本題。 travisdrone.io などでciを動かしている場合、テストごとに環境を作成しているわけですが、依存ライブラリが増えてくるとこの部分で結構な時間がとられます。 下手するとテストよりも環境構築に時間がかかるわけで、時間の限られた条件の中で利用する貧乏人としては、本質的じゃないところのコストはできるだけ減らしたいもの。 ということでいろいろ試行錯誤の末、以下のようにしました。

  • 依存ライブラリはリポジトリに入れる
  • toxなどでリポジトリ内の依存ライブラリを参照するように調整する
  • toxにテストの詳細を記述し、travis.yml にはtox実行に必要なものだけ書く

3つ目はすでに travisでtoxをつかうtips にも書いたことなので細かい説明はしません。

依存ライブラリをリポジトリに入れる

リポジトリに入れる方法ですが、インストール時間の短縮まで狙うことにして、wheel形式のバイナリパッケージを保存するようにします。

個別に行う場合は以下のとおり

pip wheel -f wheelhouse <dist>

wheel サブコマンドは requirements.txt も使えるので、そのようにしてもOK

pip wheel -r requirements.txt -f wheelhouse

pip wheel したライブラリをインストールするには、 -f (find-links) オプションで wheelhouseディレクトリを参照するようにします。また、 --no-index オプションで、pypiを見に行かないようにします。

pip install -f wheelhouse --no-index -r requirements.txt

毎回指定するのは面倒なので、オプションこみのファイルを作ります。 dev-requires.txt という名前で作成してみましょう。

dev-requires.txt:

-f wheelhouse
--no-index
-r requirements.txt

これで、 pip install -r dev-requires.txt するだけですべてがそろいます。 ダウンロードなし、ソース展開なしのインストールの速さに驚くことでしょう。

toxなどでリポジトリ内の依存ライブラリを参照するように調整する

では、この dev-requires で tox の環境構築も行うようにしましょう。 toxでは tox.ini の testenv セクションで依存ライブラリを指定するようになっています。

[testenv]
deps = pytest
       pytest-cov
       mock

このように書いてある場合、 pip によって pypiからのダウンロードとインストールが行われます。 ここで先ほど用意した dev-requires.txt を使うには以下のように書きます。

[testenv]
deps = -rdev-requires.txt

-rdev-requires.txt の間を開けてはいけません。 (開けてしまうと pipが -r という名前のライブラリを探しにいってしまいます) このように指定すれば、toxがテスト環境を作る時間が一気に短縮できます。

travisでtoxを使う

toxにテストを書いてあるので、 script を tox にしておけば実行されます。 また、 matrix を使って、 tox の testenvを切り替えるようにしておけば、travis上でもtoxのtestenvごとの結果を確認できます。

サンプル

WebDispatch で使っている .travis.ymlとtox.ini です。

https://travis-ci.org/aodag/WebDispatch で実行結果を見れます。

.travis.yml:

language: python
python: 3.3
env:
  matrix:
    - TOXENV=py27
    - TOXENV=py33
    - TOXENV=py34
    - TOXENV=coverage
    - TOXENV=flake8
    - TOXENV=pylint

install:
  - pip install tox -f wheelhouse
  - if test "$TOXENV" = coverage ; then pip install python-coveralls ; fi
script: tox
after_success:
  - if test "$TOXENV" = coverage ; then coveralls ; fi

coverall 用の通知設定がありますが、それ以外はtoxを動かすためだけの設定になっています。 もちろんtox自体もwheel化してwheelhouseに保存してあるものからインストールします。

tox.ini:

[tox]
envlist = py27,py33,py34,pypy,coverage,flake8,pylint

[testenv]
deps = -rdev-requires.txt
commands = py.test webdispatch

[testenv:coverage]
basepython = python3.3
deps = -rdev-requires.txt
commands = py.test webdispatch --cov=webdispatch --cov-report=term-missing

[testenv:flake8]
basepython = python3.3
deps = -rdev-requires.txt
commands = flake8 webdispatch

[testenv:pylint]
basepython = python3.3
deps = -rdev-requires.txt
commands = pylint webdispatch

各種バージョンと、品質チェック系のテストなどをしています。 環境構築が速いので、ローカルでもばんばん実行しています。

まとめ

Wheel形式のパッケージをどう活用するかというアイディアは、PyCon Apac 2013 で すでに検討していたのですが、 pipやwheelなどのツールがバージョンアップしてきたことやtox、travisへの理解が深まったことで、上記のような方法に行き着きました。

Comments !

blogroll

social