tox で環境変数をセットする方法

先日リリースされた tox-2.0.0 から、コマンドを実行する際に環境変数がフィルタされるようになりました。

(new) introduce environment variable isolation: tox now only passes the PATH and PIP_INDEX_URL variable from the tox invocation environment to the test environment and on Windows also SYSTEMROOT, PATHEXT, TEMP and TMP whereas on unix additionally TMPDIR is passed.
http://tox.readthedocs.org/en/latest/changelog.html

いままでテストの制御に環境変数を使ったりすることがありましたが、
tox-2.0.0 ではそのままでは動作しないことになりました。

$ RUN_ALL_TESTS=1 tox   # すべてのテストを実行する
...
$ SKIP_FOOBAR_TEST=1 tox   # あるテストをスキップする
...

ここで登場したのが ``passenv`` という設定です。
参照する環境変数を tox.ini に列挙します。

[testenv]
passenv= RUN_ALL_TESTS SKIP_FOOBAR_TEST

* などを用いた glob マッチにも対応しているそうです。
なお、複数列挙する場合はスペース区切りで並べる必要があります。
他の設定項目のように空行区切りをしてしまうと正しく反映されません。

余談

Travis CI 上で coveralls を実行するとトークンの設定とかそういったものが不要で簡単なのですが、
coveralls コマンドは環境変数を見て情報を得ているらしく、tox 経由で実行する場合は tox.ini に

[testenv]
passenv= TRAVIS*

という設定をしておかないと

You have to provide either repo_token in .coveralls.yml, or launch via Travis

と言われてカバレッジデータをアップロードしてくれないことに気づきました。
oh...

古い pip で --use-wheel を指定してパッケージを入れるとコマンドが生成されないことがある件。

古い pip には wheel まわりの扱いに問題があるようで、
--use-wheel オプションを指定してパッケージを入れたときに
コマンドが生成されないことがあるようです。

具体的には drone.io の環境に入っている pip-1.4.1 では問題が発生しました。
そのため、

pip install --use-mirrors --upgrade wheel
pip install --use-mirrors --use-wheel detox

detox

のようなスクリプトを実行すると

/home/ubuntu/.build.sh: line 52: detox: command not found

などと言われてしまいます。

解決策は pip を新しくすることなので、wheel を入れるときに pip も新しくするとよいでしょう。

pip install --use-mirrors --upgrade pip wheel

ちなみに新しい pip を --use-wheel でアップデートすると、
pip コマンドが使えなくなるというオチが待っているので、
pip の更新は wheel を使わずに行いましょう。

sphinxcontrib-googleanalytics-0.1 と sphinx-1.3 の組み合わせで Sphinx が落ちる件。

表題の組み合わせだと、こんなエラーを吐いて Sphinx さんが死ぬ。

Traceback (most recent call last):
File "/Users/tkomiya/work/blockdiag.com/lib/python2.7/site-packages/sphinx/cmdline.py", line 244, in main
opts.warningiserror, opts.tags, opts.verbosity, opts.jobs)
File "/Users/tkomiya/work/blockdiag.com/lib/python2.7/site-packages/sphinx/application.py", line 143, in __init__
self.setup_extension(extension)
File "/Users/tkomiya/work/blockdiag.com/lib/python2.7/site-packages/sphinx/application.py", line 449, in setup_extension
if not ext_meta.get('version', None):
AttributeError: 'Sphinx' object has no attribute 'get'

Sphinx-1.3 から、Sphinx 拡張の `setup()` 関数は「拡張モジュールのメタデータ(dict)」か
「何も返さない」ことを期待しているのだけど、
sphinxcontrib-googleanalytics はなぜか Sphinx オブジェクトを返しているので
こんなエラーを吐くことになる。
Sphinx-1.3 以前は返り値はとくに見ていなかったので何も起きなかったのだけど、
バージョンアップですれ違いが起きてしまった。

根本的な解決は sphinxcontrib-googleanalytics が Sphinx-1.3 に対応して、
いい感じの返り値を返すように修正されることなんだけど、
このモジュール、長らくメンテされていないのでいつになるのかとても怪しい…。

というわけで、conf.py でさっくり monkey patch を当てることにした。

# adhoc: Fix sphinxcontrib-googleanalytics does not work with Sphinx-1.3
from sphinxcontrib import googleanalytics
original_setup = googleanalytics.setup

googleanalytics.setup = lambda app: original_setup(app) and None

とてもひどい。けど動く。でもひどい。

しかたがないので、あとで Sphinx 側を直すことにしよう。

rails-erd でいい感じの ER図を出す

諸事情で ER図をとても作りたくなることってよくありますよね。

rails で開発しているプロジェクトだと rails-erd というツールを使うと
モデル定義から簡単に ER図っぽいものを生成できるのですが、
なにもオプション指定をしないと複雑で読みづらいものができてしまうことがあります。

  • Form オブジェクトが表示されてしまう
  • 使っている gem のクラス (audit など) が表示されてしまう
  • created_by や updated_by など、users モデルの参照がごちゃごちゃしてしまう
  • has_many :through の関係が点線で表示されている
  • カラムの表示がアルファベット順になっている

また、表示されている内容をよく見ると id や created_at などの標準カラムや、
foreign_key が貼られている参照カラムなども表示されていません。

このあたり、ちょっと整理しないと **ER図** としてはちょっと読みづらいですよね。

というわけで、ちょっと手を入れて見やすい図にする工夫をしてみました。

bundle exec rake erd filetype=dot attributes=foreign_keys,primary_keys,timestamps,inheritance,content indirect=false sort=false
ruby -e '\
    dot = open("erd.dot").read
    dot.gsub!(/^\s*".*?::.*?;\n/m, "")  # remove Ruby classes (Form, Audit, ...)
    dot.gsub!(/^.*? -> ".*?::.*?;\n/, "")  # remove relation to Ruby classes
    dot.gsub!(/^(\s*m_User -> .*?;\n)\1{2}/m, "")  # remove created/updated/deleted_by releations
    print dot
' > output.dot
dot -Tpdf -o erd.pdf output.dot
dot -Tpng -o erd.png output.dot

工夫してるところは以下のとおりです。

  • rails_erd
    • 出力内容を加工するために画像ではなく dot 形式で出力
    • attributes オプションを指定して、すべてのカラムを表示させる
    • indirect=False を指定して、has_many :throught の点線を表示しない
    • sort=False を指定して、カラムをソートさせない
  • フィルタ処理
    • Form オブジェクトや gem など、Ruby のクラスっぽいもの (:: を含むもの)を除外
    • User モデルへの参照は読みづらいので削除


大したことはやってないのですが、あとで忘れそうなので備忘として。

※ 諸事情でお手伝いしたやつなので、具体的なサンプルはお見せできません。あしからず。

flake8 で coding: utf-8 の有無をチェックする flake8-coding を作った

# -*- coding: utf-8 -*-

というファイルエンコーディングを示す magic comment の有無を lint しようと思ったのだけど
調べてみると Jenkins でやる方法ぐらいしか見当たりませんでした。

drone.io やら travis ci やらでサクッとチェックできるように flake8-coding という flake8 plugin を作りました。
このプラグインを入れると flake8 を実行するだけで magic comment の有無をチェックできます。

$ flake8 setup.py
setup.py:0:1: C101 Coding magic comment not found

Jenkins + Warnings Plugin + flake8 で静的解析

ざっとググってもそれっぽい記事が見当たらなかったのでメモを残しておきます。

Jenkins の Warnings Plugin で flake8 の静的解析の結果を集計するには次のように設定します。

flake8 用のパーサーを追加する

Jenkins の管理 > システム設定 ページの コンパイラの警告 セクションで flake8 用のパーサーを追加します。

項目
名前 flake8
リンク名 flake8
推移レポート名 flake8
正規表現 (.):(\d+):(\d+): (.)
マッピングスクリプト (下記参照)
import hudson.plugins.warnings.parser.Warning
import hudson.plugins.analysis.util.model.Priority

String fileName = matcher.group(1);
int lineNumber = Integer.parseInt(matcher.group(2));
String category = null;
String type = "flake8";
String message = matcher.group(4);
Priority priority = null;

if (message.startsWith('E')) {
    category = "pep8 errors";
    priority = Priority.HIGH;
} else if (message.startsWith('W')) {
    category = "pep8 warnings";
    priority = Priority.NORMAL;
} else if (message.startsWith('F')) {
    category = "PyFlakes codes";
    priority = Priority.NORMAL;
} else if (message.startsWith('C9')) {
    category = "McCabe complexity plugin mccabe";
    priority = Priority.LOW;
} else if (message.startsWith('N8')) {
    category = "Naming Conventions plugin pep8-naming";
    priority = Priority.HIGH;
} else {
    category = "Unknown Error";
    priority = Priority.HIGH;
}

return new Warning(fileName, lineNumber, category, type, message, priority);

priority を決めるところは適当に決めたので、導入時にアレンジしてください。

  • E ではじまるエラー(PEP8 Error) は HIGH
  • W ではじまるエラー(PEP8 Warning) は NORMAL
  • F ではじまるエラー (PyFlakes Error) は NORMAL
  • C9 ではじまるエラー (McCabe) は LOW
  • N8 ではじまるエラー (pep8-naming error) は HIGH
  • その他のエラー(未知)は HIGH

プロジェクトの設定で flake8 を呼び出す

シェルの実行 やその他の方法で、いい感じに flake8 コマンドを実行します。

flake8 src/ --max-complexity=12 --exclude=path/to/tests/ > flake8.log || :
cat flake8.log

flake8 でエラーが検出されても、そのまま処理を進めるように || : とかを挟んでいます。 あと、console output を見て何が起きているのか把握するため、ログを cat しています。

  • プロジェクトの設定でコンパイラ警告の集計を設定する

同じくプロジェクトの設定ページで、Warnings plugin の設定を進めます。

項目
集計するファイル flake8.log
パーサー flake8

flake8 コマンドの出力結果ファイルと、システム設定で追加したパーサーを指定します。

さらに静的解析の結果で通知を制御するために、 高度な設定で ビルドステータスの閾値 を次のように設定してみました。f:id:tk0miya:20150309163845p:plain

まとめ

flake8 の解析内容によって success と unstable、 failure を切り替えたかったので、 Jenkins を細かく設定してみました。

追記

Warnings Plugin に PR した方がいいかしら、とリポジトリを眺めていたところ、 パッケージに含まれている PEP8 パーサーは既に flake8 に対応しているようです。

上記で登録したスクリプトとの違いは priority の決め方ぐらいです。

  • E ではじまるエラー(PEP8 Error) は HIGH
  • W ではじまるエラー(PEP8 Warning) は HIGH
  • F ではじまるエラー (PyFlakes Error) は HIGH
  • R ではじまるエラー (??) は NORMAL
  • その他のエラー(未知)は LOW

なんだかぞわぞわする…

SphinxCon JP を開催しました

つい先日、SphinxCon JP 2014 が開催されました。
僕は所用があったため、午後の発表と懇親会だけ参加しました。
Sphinx をはじめよう」というテーマの通り Sphinx 初心者/中級者に向けた発表がメインでしたが、
本家のアップデート報告、事例紹介、拡張、テーマ、おとなりさん紹介と幅広い内容で
(スタッフなのに)いち参加者として楽しませていただきました。

Sphinx 拡張についてまとめました

また、発表者のひとりとして Sphinx 拡張について整理しました。
スライドはこちらです。

まとめた成果についてはこちらで公開しています。
Survey of Sphinx extensions

Sphinx 拡張の整理については、以前からやろうとは思っていたものの
手間を考えるとなかなか踏みだせないテーマだったのでいい機会ではありました。

r_rudi さんの Sphinx 拡張 探訪 2012 の時点では
Sphinx 拡張は 100個以上あるとあったので、ある程度覚悟はしていたのですが、
実際にリストアップすると 230個も拡張が出てきました。
2年の間に随分増えたものです。おかげで骨が折れました…。


実はもう一本、話したいテーマとして markdown と reST を比較して
拡張性と多様性、方言について思うところを話してみたかったのですが、
他のセッションとややネタがかぶってしまっていたのと、
カンファレンスのテーマ(Sphinx をはじめよう)とも少しズレが有るよね、ということで
今回は不採用となっていました。
これはどこかの機会にまとめられるといいなとは思ってます。

これからのドキュメント(ツール)の話をしよう

懇親会で何人かの方と相談しながら、ドキュメント全般について話す場の相談をしていました。

現在、ドキュメント関連のコミュニティはいくつかありますが、個人的な印象ではそれぞれがバラバラに活動しているような気がしています。

例えば Sphinx と Re:VIEW では別のコミュニティとして動いていますし、
翻訳をしている人たちもプロジェクトごとに集まっていることが多いように思います。
マークアップ言語やツールプログラミング言語や活動内容(出版、翻訳、リファレンスなど)など
それぞれのテーマごとに幾つものグループに分かれてしまっているため、
知識や問題などがお互いにシェアされず、似たような落とし穴にはまったり、
車輪の再発明が繰り返されているような節があります。

翻訳ひとつ取っても、Jekyllrb-ja プロジェクトと Rails Guides プロジェクト、
そして Sphinx プロジェクトでは翻訳に使っているツールがそれぞれ異なっています。
向き不向きもあるので一概には言えませんが、こうした部分でナレッジやツールが共有されると
やりたいことにもっと注力できるようになるかもしれません。

こうしたテーマを話す場として、なんらかのイベントをやろうと画策しています。
まずは 版管理+自動組版 で版や組版について
議論や相互理解が深まると良いなあと考えています。
そして、できればテーマを変えて第二弾、第三弾と広げられると良いなあと思っています。

まとめ

これからもがんばりましょう。