webappをベースに携帯電話用のウェブサイト構築のフレームワークを作成中。
ハンドラの定義を簡略化させたいので、
app.yamlか、メインとなるハンドラを自動生成させる仕組みを構想中。
こんな感じの構成で、
/framework/__init__.py
/sites/admin/__init__.py
/sites/admin/main.py
/sites/__init__.py
/sites/index.py
/sites/login.py
/app.yaml
/mainhandler.py
案1:app.yamlをこんな感じで自動生成させる。
------------------
- url: /index\.html
script: sites/index.py
- url: /login\.html
script: sites/login.py
・・・以下同様に続く。
------------------
案2:mainhandler.pyをこんな感じで自動生成させる。
------------------
import sites
from google.appengine.ext import webapp
from google.appengine.ext.webapp.util import run_wsgi_app
application = webapp.WSGIApplication(
[('/index.html', sites.index.Html),('/login.html', sites.login.Html),・・・以下同様に続く], debug=True)
def main():
run_wsgi_app(application)
if __name__ == "__main__":
main()
------------------
案1は、(importの範囲を絞れるので)たぶん起動速度が速い。
その代償にapp.yamlをいじり辛くなってしまうので、
フォルダごとに管理者ユーザのみのアクセスを設定したりするのは難しい。
案1と案2の折衷案がよさそうな気もする・・・
まずは案1と案2のパフォーマンスの差を調べよう。
トレーディングカードゲーム「Magic:The Gathering」の攻略サイト MTG-Guild の 開発日誌です。 Google App Engine - Python で構築スタート! ・・・どうなることやら
2010年12月28日火曜日
2010年12月16日木曜日
2010年11月30日火曜日
開発進捗(11/30)
htmlのレンダリング部分はだいぶ満足がいくようになってきた。
あとは、form関連のテンプレート化をしたい:
・リクエストからの変数の取得
・入力内容のチェック
・エラー時の動作
・htmlのキャッシュ
・レスポンスの作成:
・キャッシュ期間の指定
・文字コードの指定
ほかにやりたいこと:
その1、BigTableへの操作のテンプレート化:
・検索時のキャッシュの利用
・更新時にタスクキューを使う
・メンテナンス用のフォームの生成
その2、よく使いそうな動作のテンプレート化:
・掲示板機能
・ログイン・ログアウト・パスワードの変更
・ユーザ登録
・定期ジョブによるデータ削除
やれることはいっぱいあるなぁ。
それにしても、テストケースを作成しておくと、
本当にリファクタリングが楽ですね。
あとは、form関連のテンプレート化をしたい:
・リクエストからの変数の取得
・入力内容のチェック
・エラー時の動作
・htmlのキャッシュ
・レスポンスの作成:
・キャッシュ期間の指定
・文字コードの指定
ほかにやりたいこと:
その1、BigTableへの操作のテンプレート化:
・検索時のキャッシュの利用
・更新時にタスクキューを使う
・メンテナンス用のフォームの生成
その2、よく使いそうな動作のテンプレート化:
・掲示板機能
・ログイン・ログアウト・パスワードの変更
・ユーザ登録
・定期ジョブによるデータ削除
やれることはいっぱいあるなぁ。
それにしても、テストケースを作成しておくと、
本当にリファクタリングが楽ですね。
2010年11月19日金曜日
Pythonのシングルトン
httpレスポンス作成で、htmlテンプレートを毎回生成するのが微妙なので、
シングルトンについて調べてみる。
hasatttrは遅そうなので、try~exceptで例外をキャッチする方法にしたところ、10%高速になった。
そのままだと、__init__(self, *vals, **kwds)が、毎回呼ばれてしまうので、
__init__を上書きする処理を追記。
さらに、__slots__ = ()を入れて、1%高速化。
シングルトンについて調べてみる。
hasatttrは遅そうなので、try~exceptで例外をキャッチする方法にしたところ、10%高速になった。
class Singleton(object): def __new__(cls, *args, **kwds): try: return cls.__instance except AttributeError: instance = super(Singleton, cls).__new__(cls, *args, **kwds) cls.__instance = instance return instance
そのままだと、__init__(self, *vals, **kwds)が、毎回呼ばれてしまうので、
__init__を上書きする処理を追記。
さらに、__slots__ = ()を入れて、1%高速化。
class Singleton(object): __slots__ = () @staticmethod def _nodo(self,*args, **kwds): pass def __new__(cls, *args, **kwds): try: return cls.__instance except AttributeError: instance = super(Singleton, cls).__new__(cls, *args, **kwds) cls.__instance = instance cls.__init__(instance, *args, **kwds) cls.__init__ = Singleton._nodo return instance
2010年11月17日水曜日
Python:親クラスへのアクセスする手段について
子クラスから親クラスのメソッドを使う場合、
superより、親クラスを指定するほうが13%くらい速いみたいですね。
多重継承の場合や、階層が多段の場合は、面倒なので未調査です。
でもたぶん親クラスを直に指定したほうが速そうですね。
今はsuperを使っているのですが、
固まってきたら親クラス指定に変えようかな。
from timeit import Timer
setup = u"""
class Test1(list):
def __init__(self,*vals,**kwds):
list.__init__(self,*vals,**kwds)
class Test2(list):
def __init__(self,*vals,**kwds):
super(Test2,self).__init__(*vals,**kwds)
a=['a']
"""
do1 = u"""
Test1(a)
"""
do2 = u"""
Test2(a)
"""
time1 = Timer(do1, setup).repeat(20, 2000)
time2 = Timer(do2, setup).repeat(20, 2000)
persent = (sum(time1)) * 100 / (sum(time2))
print str(persent) + '%'
86.4219560341%
superより、親クラスを指定するほうが13%くらい速いみたいですね。
多重継承の場合や、階層が多段の場合は、面倒なので未調査です。
でもたぶん親クラスを直に指定したほうが速そうですね。
今はsuperを使っているのですが、
固まってきたら親クラス指定に変えようかな。
from timeit import Timer
setup = u"""
class Test1(list):
def __init__(self,*vals,**kwds):
list.__init__(self,*vals,**kwds)
class Test2(list):
def __init__(self,*vals,**kwds):
super(Test2,self).__init__(*vals,**kwds)
a=['a']
"""
do1 = u"""
Test1(a)
"""
do2 = u"""
Test2(a)
"""
time1 = Timer(do1, setup).repeat(20, 2000)
time2 = Timer(do2, setup).repeat(20, 2000)
persent = (sum(time1)) * 100 / (sum(time2))
print str(persent) + '%'
86.4219560341%
2010年11月16日火曜日
Pythonのコーディングスタイル(PEP8)をチェック
参照元
なるほどー。そんな便利なコマンドがあったとは。
さっそく、nosetests起動用バッチコマンドに組み込みました。
1.pep8チェック
2.pep8チェックでエラー無:nosetestsを実行して終了。
3.pep8チェックでエラー有:pauseしてからnosetestsを別ウィンドウで実行。並行して1に戻る。
そのうち公開します。
なるほどー。そんな便利なコマンドがあったとは。
さっそく、nosetests起動用バッチコマンドに組み込みました。
1.pep8チェック
2.pep8チェックでエラー無:nosetestsを実行して終了。
3.pep8チェックでエラー有:pauseしてからnosetestsを別ウィンドウで実行。並行して1に戻る。
そのうち公開します。
2010年11月10日水曜日
Google App Engine for Python:データストアにデータが保存されない?
初歩的なミスで、1日ほどはまってました。
間違いソース:
正解ソース:
putとput()は、大違い。
putは、putメソッドへの参照。
put()だと、putで指されているメソッドの実行。
蛇さんは、すっきりした書き方ができるのが魅力ですが、
その冗長性の低さは、気をつけないとダメですね。
間違いソース:
class Usersa(db.Model): userid = db.StringProperty(required=True, multiline=False) one_record = DataModel(userid=userid) one_record.put
正解ソース:
class Usersa(db.Model): userid = db.StringProperty(required=True, multiline=False) one_record = DataModel(userid=userid) one_record.put()
putとput()は、大違い。
putは、putメソッドへの参照。
put()だと、putで指されているメソッドの実行。
蛇さんは、すっきりした書き方ができるのが魅力ですが、
その冗長性の低さは、気をつけないとダメですね。
2010年11月5日金曜日
pythonの文字列編集
いちおう、個人的な結論が出ました:
普通のサイズなら+=で十分。listを育てて''.join(list)するのはナンセンス。
多少大きいなら、''.join([i for i in ジェネレータ])
本当に大きいなら、''.join(ジェネレータ)
ジェネレータをリスト内包表記でリストにしたほうが たいてい 速いというのは、意外な結果でした。
以下が検証につかったプログラムです。
普通のサイズなら+=で十分。listを育てて''.join(list)するのはナンセンス。
多少大きいなら、''.join([i for i in ジェネレータ])
本当に大きいなら、''.join(ジェネレータ)
ジェネレータをリスト内包表記でリストにしたほうが たいてい 速いというのは、意外な結果でした。
以下が検証につかったプログラムです。
from timeit import Timer #リストを育てて、join str_test1 = """ for num in _gen: str_list.append(num) _join(str_list) """ #stringIOに追記 str_test2 = """ for num in _gen: file_str.write(num) file_str.getvalue() """ #charのarrayに追加 str_test3 = """ for num in _gen: char_array.fromstring(num) char_array """ # += で 育てていく str_test4 = """ for num in _gen: out_str += num out_str """ # リスト内包表記をjoin str_test5 = """ ret = _join([i for i in _gen]) ret """ # ジェネレータを直にjoin str_test6 = """ ret = _join(_gen) ret """ setup = """ loop_count = 30 out_str = '' from array import array char_array = array('c') str_list = [] from cStringIO import StringIO file_str = StringIO() _join = ''.join _name = 'test' _gen=('<test' + ' name="' + _name + '"' + '>' + `num` + '</test>' for num in xrange(loop_count)) """ print Timer(str_test1, setup).repeat(3, 100) print Timer(str_test2, setup).repeat(3, 100) print Timer(str_test3, setup).repeat(3, 100) print Timer(str_test4, setup).repeat(3, 100) print Timer(str_test5, setup).repeat(3, 100) print Timer(str_test6, setup).repeat(3, 100)
loop_count=30
[0.00024053336528595537, 0.00023634288663743064, 0.00023606352260685526]
[0.00015420954332512338, 0.0001477841469750274, 0.00015532700490439311]
[8.7441281721112318e-005, 8.353016892215237e-005, 8.2692073192447424e-005]
[7.2076200012816116e-005, 6.7326993303140625e-005, 6.7885723183280788e-005]
[8.0177787822321989e-005, 7.5987310992786661e-005, 7.5707945143221878e-005]
[0.00047128894948400557, 0.00047352387082355563, 0.00047156831351458095]
# +=が一番速い!
# ''.join(ジェネレータ)は一番遅い!
loop_count=300
[0.0019653335821203655, 0.0020566859766404377, 0.0019753907254198566]
[0.00092833027701999526, 0.00092358107031031977, 0.00092413980019045994]
[0.00075568263673631009, 0.00067997468977409881, 0.00062019055440032389]
[0.00051794292267004494, 0.00050229847693117335, 0.00050257784096174873]
[0.00045676196350541431, 0.00043832386472786311, 0.00044111751776654273]
[0.00082524454956001136, 0.00080149851419264451, 0.0007970286733325338]
# ''.join(i for i in ジェネレータ)の順位が上昇。一番速い!
# ''.join(ジェネレータ)の順位が上昇。
loop_count=3000
[0.024607876141089946, 0.024106695123919053, 0.023980701458640397]
[0.017470097456680378, 0.019163050053975894, 0.021411380497738719]
[0.009339734519016929, 0.0092833027665619738, 0.0093380583293765085]
[0.0081722677041398128, 0.0050972958852071315, 0.0080621978486306034]
[0.0041698037039168412, 0.0040753782959654927, 0.0040725846429268131]
[0.0043092068972327979, 0.004270654510037275, 0.0042558481600281084]
# ''.join(ジェネレータ)が2位に。
loop_count=30000
[0.32366962840205815, 0.33386114715540316, 0.33299315974545607]
[0.19254905302113912, 0.19246356729672698, 0.19229231648205314]
[0.18879075413315149, 0.14344420869201713, 0.18765234128841257]
[0.13475986473167723, 0.16792050386175106, 0.1337812487345218]
[0.054552184705244144, 0.055729149933540612, 0.055441683231038041]
[0.046381872556594317, 0.05237118125478446, 0.052848616234768997]
# ''.join(ジェネレータ)が1位に。
# でも、''.join(i for i in ジェネレータ)とあんまり変わらない。なぜに?
loop_count=300000
[3.215461741645413, 3.1868516808699496, 3.1819172548475763]
[2.0470207805756218, 2.0494777967596747, 2.0539613274868316]
[16.015020065398858, 16.072113355188776, 16.03753214444987]
[15.98263103271529, 15.960840553758317, 15.985554309276267]
[0.47812361627075006, 0.46673641482448147, 0.48726667774826637]
[0.46456016057891247, 0.45079220962543332, 0.46201709993874829]
# += と char_array が、一番遅くなった。
2010年11月4日木曜日
開発進捗(11/4)
下の調査結果を元に、htmlの生成部分のリファクタリングをしてました。
・無理に''.joinは使わない。
・速度を理由に文字を定数化しない。
明日は、ログインフォームを作ろう。
・無理に''.joinは使わない。
・速度を理由に文字を定数化しない。
明日は、ログインフォームを作ろう。
Pythonの文字列結合のパフォーマンス
Python2.5.4で、文字列結合の速度についていろいろ試してみました。
あらかじめb='b'、c='c'となっている場合:
a='b'+'c'
a=b+c
これはどちらも、ほぼ同じ時間でした。
変数に入れているほうが、オブジェクトの生成がなくて速そうですが、意外にもそうではありませんでした。
a=''.join(['b','c'])
a=''.join(('b','c'))
当然、下が速いです。リスト内包表記を使わないなら、タプルを使ったほうが良いですね。
あらかじめ_join=''.joinとなっている場合:
a=''.join(('b','c'))
a=_join(('b','c'))
これも、下が速いです。3回以上''.join(iter)を使うようでしたら、変数に入れておいたほうが速かったです。
あらかじめ_join=''.joinとなっている場合:
a='b'+'c'
a=_join(('b','c'))
これは、上のほうが速かったです。文字列が長かったり、何度も結合する場合は、_join(iter)のほうが速いはずなのですが、それは調査中です。
あらかじめb='b'、c='c'となっている場合:
a='b'+'c'
a=b+c
これはどちらも、ほぼ同じ時間でした。
変数に入れているほうが、オブジェクトの生成がなくて速そうですが、意外にもそうではありませんでした。
a=''.join(['b','c'])
a=''.join(('b','c'))
当然、下が速いです。リスト内包表記を使わないなら、タプルを使ったほうが良いですね。
あらかじめ_join=''.joinとなっている場合:
a=''.join(('b','c'))
a=_join(('b','c'))
これも、下が速いです。3回以上''.join(iter)を使うようでしたら、変数に入れておいたほうが速かったです。
あらかじめ_join=''.joinとなっている場合:
a='b'+'c'
a=_join(('b','c'))
これは、上のほうが速かったです。文字列が長かったり、何度も結合する場合は、_join(iter)のほうが速いはずなのですが、それは調査中です。
2010年11月3日水曜日
開発進捗
''.join(list)のlistは、イテレート可能であればlistで無くても良いみたい。
listに間違ってジェネレータをそのまま指定したら、そのまま動いたので気がつきました。
試行錯誤した結果、''.join(ジェネレータ)で、単純な文字結合の約1.3倍の速度になりました。(ローカル環境での実測。本番環境ではどうなのかは未検証)
unittestのテストケースのメソッドにコメントを入れたら、noseの出力結果にコメントが出力された。
そんな小便利な機能があるのですね。
ただ、通常は「メソッド名(テストケースのクラス名)」と表示されたところが、「コメント」と出力されるので、どこの結果なのかがわかりにくいと思いました。
半端にコメントいれると、かえってまずそうなので、今はコメントを入れない方向です。
listに間違ってジェネレータをそのまま指定したら、そのまま動いたので気がつきました。
試行錯誤した結果、''.join(ジェネレータ)で、単純な文字結合の約1.3倍の速度になりました。(ローカル環境での実測。本番環境ではどうなのかは未検証)
unittestのテストケースのメソッドにコメントを入れたら、noseの出力結果にコメントが出力された。
そんな小便利な機能があるのですね。
ただ、通常は「メソッド名(テストケースのクラス名)」と表示されたところが、「コメント」と出力されるので、どこの結果なのかがわかりにくいと思いました。
半端にコメントいれると、かえってまずそうなので、今はコメントを入れない方向です。
2010年11月2日火曜日
開発進捗とか
今何している?:
・Htmlを生成する俺ライブラリを作成中:
・最近気がついてションボリ:
・標準ライブラリのxml.etree.ElementTreeと中身がほとんど被っていた!
・でも俺ライブラリのほうが表記が短くて済むのでよしとする。
・それにちらっと覗いた感じでは標準ライブラリも大した事をやっていない。
・xml文字列作成部分では、高速化する余地がありそう。
今後何をしたい?
・Htmlを生成する俺ライブラリの改善:
・サービスを広げようと思うと、やっぱり速くしたい。
・文字列の結合は、やっぱり''.join(list)が速いみたい。
・イッシー環境では、listをリスト内包表記にすると、小さな文字列でもだいぶ違った。
・listを育ててから''.join(list)すると、あんまり差が出ないことも多い。
・html文字列生成時は、今は文字列連結でやっているので、高速化の余地がある。
・リストを育てていくと、リストの再生成で時間がかかるはずなので、
全体をなめるイテレーター処理を定義して、それをリスト内包表記にして、join(list)とさせよう。
・html文字列生成時の文字コードの指定は、内部的にはグローバル変数を介してやろう。
そのほうが引数のやり取りが減って速そう。
・エスケープ処理がないので改善が必要
・Formのhtmlは作成できるけど、それだけ。
・ブラウザから返ってきたrequestデータをパースしてFormで受け取る処理が欲しい
・スタイルクラスをうまく定義できるようにしたい
・responseのヘッダーに文字コードを設定する処理をうまくやりたい
・ログインフォームの作成:
・具体的に使ってみないと、ライブラリの使い勝手がわからない
・テーブル操作もやりたい
・そろそろセッション維持についても実装しながら考えたい
ここ数ヶ月を振りかえって思ったこと:
・テスト駆動開発はすばらしい。リファクタリングが思う存分出来る。
・不必要に下調べはしないほうが良い。調べたことを忘れてしまう。
すぐに実装しようと思っていることに対してのみ調べるべき。
・フレームワークは、一度自作すると良い。
ほとんどが既存の仕組みで代用できますが、勉強になる。
そうして初めて、既存のフレームワークのありがたさが良くわかる。
・Htmlを生成する俺ライブラリを作成中:
・最近気がついてションボリ:
・標準ライブラリのxml.etree.ElementTreeと中身がほとんど被っていた!
・でも俺ライブラリのほうが表記が短くて済むのでよしとする。
・それにちらっと覗いた感じでは標準ライブラリも大した事をやっていない。
・xml文字列作成部分では、高速化する余地がありそう。
今後何をしたい?
・Htmlを生成する俺ライブラリの改善:
・サービスを広げようと思うと、やっぱり速くしたい。
・文字列の結合は、やっぱり''.join(list)が速いみたい。
・イッシー環境では、listをリスト内包表記にすると、小さな文字列でもだいぶ違った。
・listを育ててから''.join(list)すると、あんまり差が出ないことも多い。
・html文字列生成時は、今は文字列連結でやっているので、高速化の余地がある。
・リストを育てていくと、リストの再生成で時間がかかるはずなので、
全体をなめるイテレーター処理を定義して、それをリスト内包表記にして、join(list)とさせよう。
・html文字列生成時の文字コードの指定は、内部的にはグローバル変数を介してやろう。
そのほうが引数のやり取りが減って速そう。
・エスケープ処理がないので改善が必要
・Formのhtmlは作成できるけど、それだけ。
・ブラウザから返ってきたrequestデータをパースしてFormで受け取る処理が欲しい
・スタイルクラスをうまく定義できるようにしたい
・responseのヘッダーに文字コードを設定する処理をうまくやりたい
・ログインフォームの作成:
・具体的に使ってみないと、ライブラリの使い勝手がわからない
・テーブル操作もやりたい
・そろそろセッション維持についても実装しながら考えたい
ここ数ヶ月を振りかえって思ったこと:
・テスト駆動開発はすばらしい。リファクタリングが思う存分出来る。
・不必要に下調べはしないほうが良い。調べたことを忘れてしまう。
すぐに実装しようと思っていることに対してのみ調べるべき。
・フレームワークは、一度自作すると良い。
ほとんどが既存の仕組みで代用できますが、勉強になる。
そうして初めて、既存のフレームワークのありがたさが良くわかる。
2010年11月1日月曜日
WindowsXP(eclipse)でGAE/Pのテスト駆動開発(nose)
WindowsXP環境でeclipse(PyDev)を使ってGoogle App Engine の開発をしているのですが、
・テストコードを簡単に実行したい
・エラーの有無を実行結果の色で判別したい
という思いから、以下のようなバッチを作ってみました。
<nosetest.bat>
@ECHO OFF
CD /D %~dp0
REM ========================================
REM nosetests 起動バッチ
REM ①nosetests にパラメータを指定して起動、出力結果を一時ファイルに保存
REM ②テストでエラーなし:テスト結果を標準出力に出力
REM テストでエラーあり:テスト結果をエラー出力に出力
REM ③30秒間(パラメータ1で変更可能)そのままポーズして終了
REM ========================================
REM 起動パラメータ:
REM パラメータ1=指定された秒数だけ表示(デフォルトは30秒)
REM パラメータ2=nosetestsの追加パラメータ
REM ========================================
IF "%1"=="" (SET WAIT_TIME=30) ELSE (SET WAIT_TIME=%1)
SET EXTENDS = %~2
SET /A WAIT_TIME=%WAIT_TIME%+1 >NUL
REM ======================================
REM 内部パラメータ:
REM EXE_COMAND=nosetest.exeの起動コマンド(必要に応じてpathも指定)
REM SRC_PATH=ソースディレクトリの相対パス
REM NOSETESTS_RESULT_FILE=noseの実行結果の保存ファイル
REM ======================================
SET EXE_COMAND=nosetests.exe -v --with-gae --gae-lib-root="C:\Program Files\Google\google_appengine" --without-sandbox
SET SRC_PATH=..\src
SET NOSETESTS_RESULT_FILE=nosetests_result.txt
REM ======================================
REM 実処理
REM ======================================
SET EXE_COMAND=%EXE_COMAND% %EXTENDS%
TITLE %EXE_COMAND%
CD /D %SRC_PATH%
%EXE_COMAND% 2>%~dp0\%NOSETESTS_RESULT_FILE%
CD /D %~dp0
FINDSTR "FAILED (*" %NOSETESTS_RESULT_FILE% > NUL
SET ERROR_CODE=%ERRORLEVEL%
IF "%ERROR_CODE%"=="0" (color 4F & type %NOSETESTS_RESULT_FILE% 1>&2 & SET RETURN_CODE=1) ELSE (color 27 & type %NOSETESTS_RESULT_FILE% 2>&1 & SET RETURN_CODE=0)
@PING -n %WAIT_TIME% localhost >NUL
EXIT /B %ERROR_CODE%
動作確認環境:WindowsXP SP3 + eclipse3.5.2 ( +PyDev 1.6.3 + Nose 0.11.4+ NoseGAE 0.1.7)
配置はこんな感じを前提にしてます。
[workspace]\[project]\bat\nosetest.bat
[workspace]\[project]\src\app.yaml
[workspace]\[project]\src\app.yaml
[workspace]\[project]\src\main.py
[workspace]\[project]\src\test_main.py
[workspace]\[project]\src\htmlgenerator\base.py
[workspace]\[project]\src\htmlgenerator\test_base.py
使い方:
その1: 外部ツールにnosetests.batを登録、起動時のパラメータに0を指定。
登録した外部ツールを、一度実行。
「前回実行した外部ツールを起動」のメニューに、Ctrl+Tを割り当て。
その2:
ショートカットを作成して、スタートメニューに登録。
Windowsキーを押してスタートメニューを表示させて、Nを押す。
・テストコードを簡単に実行したい
・エラーの有無を実行結果の色で判別したい
という思いから、以下のようなバッチを作ってみました。
<nosetest.bat>
@ECHO OFF
CD /D %~dp0
REM ========================================
REM nosetests 起動バッチ
REM ①nosetests にパラメータを指定して起動、出力結果を一時ファイルに保存
REM ②テストでエラーなし:テスト結果を標準出力に出力
REM テストでエラーあり:テスト結果をエラー出力に出力
REM ③30秒間(パラメータ1で変更可能)そのままポーズして終了
REM ========================================
REM 起動パラメータ:
REM パラメータ1=指定された秒数だけ表示(デフォルトは30秒)
REM パラメータ2=nosetestsの追加パラメータ
REM ========================================
IF "%1"=="" (SET WAIT_TIME=30) ELSE (SET WAIT_TIME=%1)
SET EXTENDS = %~2
SET /A WAIT_TIME=%WAIT_TIME%+1 >NUL
REM ======================================
REM 内部パラメータ:
REM EXE_COMAND=nosetest.exeの起動コマンド(必要に応じてpathも指定)
REM SRC_PATH=ソースディレクトリの相対パス
REM NOSETESTS_RESULT_FILE=noseの実行結果の保存ファイル
REM ======================================
SET EXE_COMAND=nosetests.exe -v --with-gae --gae-lib-root="C:\Program Files\Google\google_appengine" --without-sandbox
SET SRC_PATH=..\src
SET NOSETESTS_RESULT_FILE=nosetests_result.txt
REM ======================================
REM 実処理
REM ======================================
SET EXE_COMAND=%EXE_COMAND% %EXTENDS%
TITLE %EXE_COMAND%
CD /D %SRC_PATH%
%EXE_COMAND% 2>%~dp0\%NOSETESTS_RESULT_FILE%
CD /D %~dp0
FINDSTR "FAILED (*" %NOSETESTS_RESULT_FILE% > NUL
SET ERROR_CODE=%ERRORLEVEL%
IF "%ERROR_CODE%"=="0" (color 4F & type %NOSETESTS_RESULT_FILE% 1>&2 & SET RETURN_CODE=1) ELSE (color 27 & type %NOSETESTS_RESULT_FILE% 2>&1 & SET RETURN_CODE=0)
@PING -n %WAIT_TIME% localhost >NUL
EXIT /B %ERROR_CODE%
動作確認環境:WindowsXP SP3 + eclipse3.5.2 ( +PyDev 1.6.3 + Nose 0.11.4+ NoseGAE 0.1.7)
配置はこんな感じを前提にしてます。
[workspace]\[project]\bat\nosetest.bat
[workspace]\[project]\src\app.yaml
[workspace]\[project]\src\app.yaml
[workspace]\[project]\src\main.py
[workspace]\[project]\src\test_main.py
[workspace]\[project]\src\htmlgenerator\base.py
[workspace]\[project]\src\htmlgenerator\test_base.py
使い方:
その1: 外部ツールにnosetests.batを登録、起動時のパラメータに0を指定。
登録した外部ツールを、一度実行。
「前回実行した外部ツールを起動」のメニューに、Ctrl+Tを割り当て。
その2:
ショートカットを作成して、スタートメニューに登録。
Windowsキーを押してスタートメニューを表示させて、Nを押す。
2010年10月27日水曜日
PythonによるGoogle App Engingeのテスト駆動開発
GAE/P で、テスト駆動開発をeclipseで効率よく進める方法を自分なりに模索してました。
個人的な結論:
doctestは便利だけど、ソースが見づらくなりがちなので、無し。
unitttest + nose(+NoseGAE)のほうが、テストコードと本番コードを分離できるので良い。
さらに、GAETestBase(+gaeunit.py)は、便利そうなので、解読中。
ただ、どうもkayにバンドルされているものの方が一部よさそうなので、
標準のものと見比べながら都合の良いテストモジュールを作成中。
試行錯誤の際につまったこと:
問題1:
ただnosetestsを実行すると、PYTHONPATHが足らなくて盛大にこける。
解決1:
実行前にSET PYTHONPATH=???;???・・・で適当に足すと通るようになる。
問題2:
でもどうせならNoseGAEという便利なものがあるらしいので入れてみる。
しかし、nosegaeをいれて、nosetests --with-gaeとやると、
エラー(ImportError: No module named dev_appserver)が発生。
解決2:
http://d.hatena.ne.jp/sinsoku/20100714/1279036364
google_appengineのデフォルトのパスの指定がunix用になっているので、指定する。
指定方法1:
nosetests --with-gae --gae-lib-root="C:\Program Files\Google\google_appengine"
指定方法2:
D:\Documents and Settings\自分のWindowsID\.nosercに、以下のように記載する:
[nosetests]
gae-lib-root=C:\Program Files\Google\google_appengine
問題3:
単体実行すると動作するテストコード達が、
nosetests --with-gae --gae-lib-root="C:\Program Files\Google\google_appengine"
から実行すると、なにやら盛大に全部エラーになる。
解決3:
イッシーのテストコードの書き方がおかしいのかもしれませんが、
以下のように起動すると、とりあえず普通にテストしてくれました。
nosetests --with-gae --gae-lib-root="C:\Program Files\Google\google_appengine" --without-sandbox
でも、sandbox環境を使わないと、NoseGAEの意味が半減しているような?
問題4:
nosetestsをEclipseから実行するのがめんどう
解決4:
その1:
WindowsXPのショートカット・キー登録機能を使う:
http://www.atmarkit.co.jp/fwin2k/win2ktips/150use_shortcut/use_shortcut.html
その2:
WindowsXPのスタートメニューを利用:
http://www.geocities.co.jp/SiliconValley/4900/s-cut.html
その3:
eclipseの外部ツール登録して起動:
①nosetestsを外部ツールとして登録
②外部ツールを実行
③「最後に起動された外部ツールを実行」にショートカットを設定
http://www.ryuzee.com/contents/blog/553
その4:
eclipseのプロジェクトのビルド設定に組み込んで起動:
http://d.hatena.ne.jp/Nilfs/20100413
イッシーは、その2とその3にしました。
その4は、他の処理(カバレッジの取得とか)でも勝手に動いてしまったりするのが気になりました。
問題5:
nosetestsの実行結果がしょぼくて、ぱっと見てエラーかどうかがわからない。
Red/Green/Refactor、っていうけど、赤くもならないし緑にもならない。赤くらい欲しいな。
red-noseを入れても、XPのコマンドラインでは、ansiエスケープシーケンスを処理できないので、色がつかない。
Eclipseから実行すると、みんなエラー扱いになる。
解決5:
以下のようなバッチファイルを作成。
①nosetestsの実行し、出力結果を一時ファイルに出力させる
②一時ファイルを見て、中身にエラーが含まれていた場合:
コマンドラインの背景色を赤に変える
エラー出力に一時ファイルの内容を出力する
③一時ファイルを見て、中身にエラーが含まれていなかった場合:
コマンドラインの背景色を緑に変える
標準出力に一時ファイルの内容を出力する
④一定時間(デフォルト30秒)たってからコマンドラインを閉じる
具体例は、次のエントリで書きます。
検討中の課題:
課題1:
バッチから起動したnosetestsが、なんか重い
対策1:
原因は、一時ファイルに対して、ウィルスチェックが走っていることらしい。
回避策を検討。(たぶん拡張子を変えればいける)
あと、テストが完了してからでないと結果を見れないのは、標準出力を使っているから仕方が無い。
その点は色をつけるのとトレードオフなので、あきらめる。
課題2:
nosetestsで実行したカバレッジは、eclipseではうまく使えない?
対策2:
どうもnoseとeclipseで使っているカバレッジの仕様が違うようなので、仕方が無い?
カバレッジの取得は、eclipseの機能を使うかな。
http://zakizaki.cocolog-nifty.com/software/2010/10/pydevtrac-plugi.html
特に、
ウィンドウ→設定→実行/デバッグ→起動→起動操作=常に前回起動したアプリケーションを実行する
とやると、簡単にこれで起動できる。
んー。カバレッジはこっちでやろう。
色にこだわらなければ、テストの実行もeclipseの機能でよいかも。
個人的な結論:
doctestは便利だけど、ソースが見づらくなりがちなので、無し。
unitttest + nose(+NoseGAE)のほうが、テストコードと本番コードを分離できるので良い。
さらに、GAETestBase(+gaeunit.py)は、便利そうなので、解読中。
ただ、どうもkayにバンドルされているものの方が一部よさそうなので、
標準のものと見比べながら都合の良いテストモジュールを作成中。
試行錯誤の際につまったこと:
問題1:
ただnosetestsを実行すると、PYTHONPATHが足らなくて盛大にこける。
解決1:
実行前にSET PYTHONPATH=???;???・・・で適当に足すと通るようになる。
問題2:
でもどうせならNoseGAEという便利なものがあるらしいので入れてみる。
しかし、nosegaeをいれて、nosetests --with-gaeとやると、
エラー(ImportError: No module named dev_appserver)が発生。
解決2:
http://d.hatena.ne.jp/sinsoku/20100714/1279036364
google_appengineのデフォルトのパスの指定がunix用になっているので、指定する。
指定方法1:
nosetests --with-gae --gae-lib-root="C:\Program Files\Google\google_appengine"
指定方法2:
D:\Documents and Settings\自分のWindowsID\.nosercに、以下のように記載する:
[nosetests]
gae-lib-root=C:\Program Files\Google\google_appengine
問題3:
単体実行すると動作するテストコード達が、
nosetests --with-gae --gae-lib-root="C:\Program Files\Google\google_appengine"
から実行すると、なにやら盛大に全部エラーになる。
解決3:
イッシーのテストコードの書き方がおかしいのかもしれませんが、
以下のように起動すると、とりあえず普通にテストしてくれました。
nosetests --with-gae --gae-lib-root="C:\Program Files\Google\google_appengine" --without-sandbox
でも、sandbox環境を使わないと、NoseGAEの意味が半減しているような?
問題4:
nosetestsをEclipseから実行するのがめんどう
解決4:
その1:
WindowsXPのショートカット・キー登録機能を使う:
http://www.atmarkit.co.jp/fwin2k/win2ktips/150use_shortcut/use_shortcut.html
その2:
WindowsXPのスタートメニューを利用:
http://www.geocities.co.jp/SiliconValley/4900/s-cut.html
その3:
eclipseの外部ツール登録して起動:
①nosetestsを外部ツールとして登録
②外部ツールを実行
③「最後に起動された外部ツールを実行」にショートカットを設定
http://www.ryuzee.com/contents/blog/553
その4:
eclipseのプロジェクトのビルド設定に組み込んで起動:
http://d.hatena.ne.jp/Nilfs/20100413
イッシーは、その2とその3にしました。
その4は、他の処理(カバレッジの取得とか)でも勝手に動いてしまったりするのが気になりました。
問題5:
nosetestsの実行結果がしょぼくて、ぱっと見てエラーかどうかがわからない。
Red/Green/Refactor、っていうけど、赤くもならないし緑にもならない。赤くらい欲しいな。
red-noseを入れても、XPのコマンドラインでは、ansiエスケープシーケンスを処理できないので、色がつかない。
Eclipseから実行すると、みんなエラー扱いになる。
解決5:
以下のようなバッチファイルを作成。
①nosetestsの実行し、出力結果を一時ファイルに出力させる
②一時ファイルを見て、中身にエラーが含まれていた場合:
コマンドラインの背景色を赤に変える
エラー出力に一時ファイルの内容を出力する
③一時ファイルを見て、中身にエラーが含まれていなかった場合:
コマンドラインの背景色を緑に変える
標準出力に一時ファイルの内容を出力する
④一定時間(デフォルト30秒)たってからコマンドラインを閉じる
具体例は、次のエントリで書きます。
検討中の課題:
課題1:
バッチから起動したnosetestsが、なんか重い
対策1:
原因は、一時ファイルに対して、ウィルスチェックが走っていることらしい。
回避策を検討。(たぶん拡張子を変えればいける)
あと、テストが完了してからでないと結果を見れないのは、標準出力を使っているから仕方が無い。
その点は色をつけるのとトレードオフなので、あきらめる。
課題2:
nosetestsで実行したカバレッジは、eclipseではうまく使えない?
対策2:
どうもnoseとeclipseで使っているカバレッジの仕様が違うようなので、仕方が無い?
カバレッジの取得は、eclipseの機能を使うかな。
http://zakizaki.cocolog-nifty.com/software/2010/10/pydevtrac-plugi.html
特に、
ウィンドウ→設定→実行/デバッグ→起動→起動操作=常に前回起動したアプリケーションを実行する
とやると、簡単にこれで起動できる。
んー。カバレッジはこっちでやろう。
色にこだわらなければ、テストの実行もeclipseの機能でよいかも。
2010年10月15日金曜日
携帯サイト向けのPythonのフレームワーク
日本の携帯電話用のサイト構築するためのフレームワークってないものですかね?少なくともGAE/P 用のものは無いと信じているので、作成中です。
作成のポイント
・ドコモは、クッキーを使えない。
→セッションIDは、フォームに埋め込む必要がある
→パスワード認証は、入力が大変→ID・パスワードのハッシュのアドレスでログイン可能にする
・パソコンと携帯電話で表示を分けられるようにする。
というか、表示テンプレートを、使用者が自由に選べるようにする。
・文字コードは基本的にshift-jisのみOK
・機種によって使えるタグが違うので、そこをうまく吸収したい
制限事項:
・小規模サイトでの使用を前提とする
・セキュリティレベルが低くても良いように、重要な情報はシステム内に保持しない。
作成のポイント
・ドコモは、クッキーを使えない。
→セッションIDは、フォームに埋め込む必要がある
→パスワード認証は、入力が大変→ID・パスワードのハッシュのアドレスでログイン可能にする
・パソコンと携帯電話で表示を分けられるようにする。
というか、表示テンプレートを、使用者が自由に選べるようにする。
・文字コードは基本的にshift-jisのみOK
・機種によって使えるタグが違うので、そこをうまく吸収したい
制限事項:
・小規模サイトでの使用を前提とする
・セキュリティレベルが低くても良いように、重要な情報はシステム内に保持しない。
2010年10月4日月曜日
GAE開始でつまったこと その1、アカウントの取得
Google App EngineでPythonを始める際につまったこと、その1
「アカウントの取得で失敗」
イッシーがつまったのは、携帯電話へのSMSの送信です。
日本のSMSって、同じ会社にか送信できなくて、電話番号を指定して送付するものだと思います(少なくともソフトバンク的にはそうだったはず)。
ですので、携帯電話番号を指定して送信させたのですが、いっこうにつかない。
イッシーの場合、解決のポイントはいかの二つでした。
・普通のインターネット用のメアド(MMS)に送信する。
・迷惑メールフィルタは解除しておく。
基本的に指示通りに進めれば問題ないのですが、SMSのところだけイッシーには判りにくかったです。
「アカウントの取得で失敗」
イッシーがつまったのは、携帯電話へのSMSの送信です。
日本のSMSって、同じ会社にか送信できなくて、電話番号を指定して送付するものだと思います(少なくともソフトバンク的にはそうだったはず)。
ですので、携帯電話番号を指定して送信させたのですが、いっこうにつかない。
イッシーの場合、解決のポイントはいかの二つでした。
・普通のインターネット用のメアド(MMS)に送信する。
・迷惑メールフィルタは解除しておく。
基本的に指示通りに進めれば問題ないのですが、SMSのところだけイッシーには判りにくかったです。
ミニゲーム集
誰でも思いついていることかもしれないけど、
Take It Easy!とか、Hey! that's my fish!とか、ロストシティとか、軽めのボードゲームをGoogle App Engineでつくるのは良いかも?と思ってIDを取ろうとしてみました。
toy_boxとか、game_centerとかにチャレンジするも、既に取られてました。
良いのはとられちゃっているみたいだったので、適当なIDを取得。
(そのうち良いIDを売りに出す人とか出てきたりして?)
気が向いたら開発しよう。
でも版権とか良くわからないから身内専用になっちゃうんだろうなー。
2010年9月29日水曜日
Google AdSense 開始
いずれ開発したサイトでも広告を取ろうと思っていたので、
練習がてら Google AdSense を 始めてみました。
検索向けAdSenseは面白い機能ですね。
キーワードを設定できるので、関連する検索結果が出やすくて便利。
最初検索結果が文字化けしまくってあせりましたが、
文字コードがshift-jisになっていたことが原因でした。
レイアウトには満足いっていないので、もう少し直します。
練習がてら Google AdSense を 始めてみました。
検索向けAdSenseは面白い機能ですね。
キーワードを設定できるので、関連する検索結果が出やすくて便利。
最初検索結果が文字化けしまくってあせりましたが、
文字コードがshift-jisになっていたことが原因でした。
レイアウトには満足いっていないので、もう少し直します。
2010年9月28日火曜日
MTG-GUILDSの開発環境とか
OS:Windows XP SP3
PC:会社のNote PC
開発時間:平日の12:00~13:00
サーバ:Google App Engine
言語:Python
フレームワーク:Webapp
言語がPythonを選択したのは、
・昔から存在を知っていて、気になっていた
・インデントでブロック化するのがかっこいい(最新のPythonはそうじゃないみたいですね)
・Javaを仕事で使っていない
フレームワークがWebappなのは、
・英語ができないのでフレームワークを勉強するのが大変
・Kayは、日本語でヘルプがあってすばらしかったけど、
テンプレートエンジンのJinja2の使い方がいまいちよくわからなかった
・基礎知識が足りないので、フレームワークを自作しながら勉強したかった
・携帯電話にうまくつかえるフレームワークがみつからなかった
(そんなに複雑なことはしないけど、htmlタグを
動的に変えようとすると、既存のテンプレートはうまくはまらない気がした)
PC:会社のNote PC
開発時間:平日の12:00~13:00
サーバ:Google App Engine
言語:Python
フレームワーク:Webapp
言語がPythonを選択したのは、
・昔から存在を知っていて、気になっていた
・インデントでブロック化するのがかっこいい(最新のPythonはそうじゃないみたいですね)
・Javaを仕事で使っていない
フレームワークがWebappなのは、
・英語ができないのでフレームワークを勉強するのが大変
・Kayは、日本語でヘルプがあってすばらしかったけど、
テンプレートエンジンのJinja2の使い方がいまいちよくわからなかった
・基礎知識が足りないので、フレームワークを自作しながら勉強したかった
・携帯電話にうまくつかえるフレームワークがみつからなかった
(そんなに複雑なことはしないけど、htmlタグを
動的に変えようとすると、既存のテンプレートはうまくはまらない気がした)
2010年9月27日月曜日
Google App Engine用のPythonの開発環境について
効率の良いGAE/P開発環境を探しているのですが、
現時点での僕の結論は Eclipse(Pleiades)+ PyDevです。
ちょっと重いのですが、なにやらデバッグも動くので安心です。
参考までに構築手順をメモ書きします。ご参考までにどうぞ。
(なお、環境は、Microsoft XP SP3です)
<01>
http://www.python.org/download/releases/2.5.4/
→python-2.5.4.msi
をダウンロードして実行。
マイコンピュータ→プロパティ→詳細設計-環境変数で、
PATHに
C:\python25;C:\python25\Scripts;
を追加
<02>
http://pypi.python.org/pypi/setuptools
→setuptools-0.6c11.win32-py2.5.exe (md5)
をダウンロードして実行
<03>
http://www.pythonware.com/products/pil/
→Python Imaging Library 1.1.7 for Python 2.5 (Windows only)
をダウンロードして実行
<04>
http://pypi.python.org/pypi/ssl-py2.5-win32/
→ssl-py2.5-win32-1.15.exe
をダウンロードして実行。
回答されたSSLフォルダを、
python25\Lib\site-packagesに置く
<05>
http://code.google.com/intl/ja/appengine/downloads.html
→GoogleAppEngine-1.3.7.msi
プロキシ接続をしている人は、
マイコンピュータ→プロパティ→詳細設計-環境変数で、
HTTP_PROXYとHTTPS_PROXYを追加。
例)
HTTP_PROXY=hogehoge.ne.jp:8080
HTTPS_PROXY=hogehoge.ne.jp:8080
<06>
http://mergedoc.sourceforge.jp/
→プラットフォームのJREありをダウンロード
(http://mergedoc.sourceforge.jp/pleiades-redirect/3.5/pleiades_platform_jre.zip.html)
→ダウンロードしたファイルを実行してインストール
起動後、
「ヘルプ」-「新規ソフトウェアのインストール」
→追加
Eclipse PyDev
http://pydev.org/updates/
※Djangoを使うので、PyDev Django Templates Editorが使いたい!という人は、
3.6のプレアデスに、
Aptena
http://update.aptana.com/install/studio
を入れると、いっしょに使えるようになります。
ただ、安定性が低いように感じたのと、
Djangoを使わない方向なので、私は3.5を使っています。
<おまけ>
コマンドプロンプトから
easy_install nose
easy_install pylint
easy_install nosegae
nosegaeを入れると動きがおかしい気が。
どうもインストールに失敗しているみたいなのですが、
なんで失敗するのでしょうね?
現時点での僕の結論は Eclipse(Pleiades)+ PyDevです。
ちょっと重いのですが、なにやらデバッグも動くので安心です。
参考までに構築手順をメモ書きします。ご参考までにどうぞ。
(なお、環境は、Microsoft XP SP3です)
<01>
http://www.python.org/download/releases/2.5.4/
→python-2.5.4.msi
をダウンロードして実行。
マイコンピュータ→プロパティ→詳細設計-環境変数で、
PATHに
C:\python25;C:\python25\Scripts;
を追加
<02>
http://pypi.python.org/pypi/setuptools
→setuptools-0.6c11.win32-py2.5.exe (md5)
をダウンロードして実行
<03>
http://www.pythonware.com/products/pil/
→Python Imaging Library 1.1.7 for Python 2.5 (Windows only)
をダウンロードして実行
<04>
http://pypi.python.org/pypi/ssl-py2.5-win32/
→ssl-py2.5-win32-1.15.exe
をダウンロードして実行。
回答されたSSLフォルダを、
python25\Lib\site-packagesに置く
<05>
http://code.google.com/intl/ja/appengine/downloads.html
→GoogleAppEngine-1.3.7.msi
プロキシ接続をしている人は、
マイコンピュータ→プロパティ→詳細設計-環境変数で、
HTTP_PROXYとHTTPS_PROXYを追加。
例)
HTTP_PROXY=hogehoge.ne.jp:8080
HTTPS_PROXY=hogehoge.ne.jp:8080
<06>
http://mergedoc.sourceforge.jp/
→プラットフォームのJREありをダウンロード
(http://mergedoc.sourceforge.jp/pleiades-redirect/3.5/pleiades_platform_jre.zip.html)
→ダウンロードしたファイルを実行してインストール
起動後、
「ヘルプ」-「新規ソフトウェアのインストール」
→追加
Eclipse PyDev
http://pydev.org/updates/
※Djangoを使うので、PyDev Django Templates Editorが使いたい!という人は、
3.6のプレアデスに、
Aptena
http://update.aptana.com/install/studio
を入れると、いっしょに使えるようになります。
ただ、安定性が低いように感じたのと、
Djangoを使わない方向なので、私は3.5を使っています。
<おまけ>
コマンドプロンプトから
easy_install nose
easy_install pylint
easy_install nosegae
nosegaeを入れると動きがおかしい気が。
どうもインストールに失敗しているみたいなのですが、
なんで失敗するのでしょうね?
開発日誌のはじまり
こんにちは、はじめまして。イッシーと申します。
Magic:the Gathering というゲームを攻略するためのサイト構築を行っています。
Google App EngineにてPythonを使って構築を進めているのですが、
日本語のソースが少なくて、結構きついなぁと思っています。
同じような悩みを持ったPython初心者、GAE初心者のためになるような記事を書いていくつもりです。
開発して困っていることも書いていくので、
有識者の方は、アドバイスやご指摘をいただけると助かります。
Magic:the Gathering というゲームを攻略するためのサイト構築を行っています。
Google App EngineにてPythonを使って構築を進めているのですが、
日本語のソースが少なくて、結構きついなぁと思っています。
同じような悩みを持ったPython初心者、GAE初心者のためになるような記事を書いていくつもりです。
開発して困っていることも書いていくので、
有識者の方は、アドバイスやご指摘をいただけると助かります。
登録:
投稿 (Atom)