NoseGAEを 使わずに nose + GAE をやる

そもそも昨日と一昨日の話は、GoogleAppengine のローカル環境でテストランナーを走らせたいけど、NoseGAEはなんかエラーでつまづく話が目についたのと、面倒だったので(おい) XMLTestRunnerでいいやーってなったのが発端。

先人達の足跡

ググるとNoseGAEは評判はあんま良くないイメージがある。けど偉大な先人達はちゃんと乗り越えて来ているのでNoseGAEを使いたい人は参考にどうぞ。

そもそも

noseを動かしてエラーになる良くあるケースは、SDKおよび、SDKのlibディレクトリ以下にあるライブラリ群にうまくパスが通って無い事によるimportエラーが挙げられる。NoseGAEはnoseプラグインとしてがんばって実装してその辺をゴニョゴニョしてるけど、オプションの使い方などが環境によって違ったりしてエラーになったりするらしい。

まずパスが通ってなきゃいけないのは、SDK自体があるディレクトリ。こんなファイル群があるところ。

google_appengine/
├── BUGS
├── LICENSE
├── README
├── RELEASE_NOTES
├── VERSION
├── appcfg.py
├── bulkload_client.py
├── bulkloader.py
├── demos
├── dev_appserver.py
├── dev_appserver.pyc
├── gen_protorpc.py
├── google
├── google_sql.py
├── lib
├── new_project_template
├── remote_api_shell.py
└── tools

次にパスが通ってなきゃあかんのは、ここの「lib」ディレクトリ以下にあるライブラリ群。

lib
├── antlr3
├── cacerts
├── django_0_96
├── django_1_2
├── enum
├── fancy_urllib
├── google-api-python-client
├── graphy
├── grizzled
├── httplib2
├── ipaddr
├── oauth2
├── prettytable
├── protorpc
├── python-gflags
├── simplejson
├── sqlcmd
├── webapp2
├── webob
└── yaml

ここのライブラリ群はパッケージとして置かれてる訳ではないので、それぞれでパスを通さなあかん場所が違う。例えば「antr3/antr3」であったり「yaml/lib/yaml」であったりと、それぞれのライブラリで違う。

1つ1つライブラリに合わせてパスを追加してもいいけどそれでは面倒。何よりもSDKのバージョンが上がったりすると、ここのライブラリ群は増えたりするのでさらに面倒。だけどSDKではちゃんとそれを対処するための方法がある。

dev_appserver.fix_sys_path() を使う

SDK(上でいうgoogle_appengineディレクトリ)にさえパスが通っていれば、下記のようなコードで、上のめんどくさいパスの設定を勝手にやってくれる。id:nullpobug(@tokibito) さんに教えてもらいました。ありがとうございます。

import dev_appserver
dev_appserver.fix_sys_path()

そんなこんなでこうした

誤解を恐れずに極論を言うと「SDKの必要な所に適切にパスを通せばNoseGAE使わんでもちゃんとnosetests動くんじゃね?」と思った。ただnosetestsはコマンドラインツールなので、どうやってパス通すかなと考えた結果こんなコードを書いた。

#!/usr/bin/env python
#-*- coding:utf8 -*-

import sys
from subprocess import call

sys.path.insert(0, 'google_appengine') #=> そもそもSDK自体にパスが通っているのであればこれはいらない
                                      #=> SDKのあるパスに適宜書き換えてくだしあ ><
import dev_appserver
dev_appserver.fix_sys_path()

argv = sys.argv
argv.pop(0)
call('(export PYTHONPATH=%s; nosetests %s)' % (':'.join(sys.path), ' '.join(argv)),shell=True)

簡単に説明すると,「dev_app_server.fix_sys_path()」でパスを適切に設定したら、それをPYTHONPATHにマルっとぶっ込んで、nosetestsコマンドを叩いてるだけ。

これを「fake-nosegae.py」とか適当にファイル名を付けて、下記のように実行する。 オプションはそのままnosetestsコマンドに渡してるので気にするな

python fake-nosegae.py -s -v -w apps

実際に動かしてみたら、ちゃんと動いたっぽい。

やったね。たえちゃん。これでnoseが使えるようになったよ!

おわりに

  • ぶっちゃけNoseGAEで事足りてる人には必要ないの話
  • 本記事は Google Appengine SDK 1.6.1 + Python 2.7.2 を使って試しました。OSはMac(Lion)です。
  • NoseGAE 使わずにやるにはどうしたらいいかなー的なノリでついカッとなって書いたので反省はしてないけど、特におすすめもしない。

余談

この記事は、新婚早々、こんな斬新な寝袋を買って、奥さんに「なにこれちょっと邪魔なんだけど?(怒)」と怒られて、泣きながらコレを来て出社してくる しみずかわ先生の姿を妄想しながら書きました。すいません。 #しみずかわ

f:id:tell-k:20120112000256p:plain
ref https://twitter.com/#!/shimizukawa/status/157072537312952320

f:id:tell-k:20120112000432p:plain
ref http://www.cgmguide.com/25/20061016012357.html