Hatena::ブログ(Diary)

logiqboard このページをアンテナに追加 RSSフィード Twitter

2011-01-17

デコレータを外す

おはこんばんちわ。情弱王子feizです。

最近とある方の影響で自動テストに凝っておりまして、それはもうセルフプレジャーを覚えた猿のようにテストを書いてるとかいないとかな毎日です。

さて

Pythonでテストをかいてると、たまにデコレータが邪魔になることがあります。

例えばjsonを返すAPIのビューをdjangoでこんなふうにかきました。

class Api(object):
    
    @require_GET
    @json_response
    @error_handle
    @validate(MyViewForm)
    def myview(self, request, params):
        return {
            "azuma": params["feiz"],
            "okano": params["tokibito"],
        }
require_GET
リクエストメソッドをチェック
json_response
辞書をjson.dumpsしてHTTPResponseに加工してヘッダとか設定
error_handle
Exceptionをキャッチしてエラーを示す辞書を返す
validate(Form)
リクエストパラメータをFormで検証して、cleaned_dataをparamsとしてviewに渡す

とまあjsonを返すのに必要な処理の大半をデコレータに投げてしまえば、viewの方は非常に簡潔に辞書だけ返せばいいよみたいな実装にできるわけです。

問題

このビューの出力をテストするとなると、理想的にはmyviewが返す辞書を検証出来れば万々歳なんですが、当然デコレータがかかっているのでmyviewを呼び出すとHttpResponseが返ります。

これをまたjson.loadsでパースしてうんたらかんたらというのはちょっとおばかすぎる。なんとか任意のタイミングでデコレータをなかった事にしたい。

がんばる

色々調べるとこんな記事が。

デコレータ式を適用した関数から元の関数名を探す - gumi Engineer’s Diary

どうやら関数オブジェクトのfunc_closure(python2.6からは__closure__でも同じものが得られる)というフィールドを覗くとクロージャの中身(?)が見れるらしい。情弱過ぎてさっぱり理解が追いついていない。

とにかくごちゃごちゃと試行錯誤した結果が以下のコード。

import types

def strip_decorators(func):
    naked = func    
    while naked.func_closure is not None:
        for cell in naked.func_closure:
            cell = cell.cell_contents
            if type(cell) is types.FunctionType:
                naked = cell
                break

    return naked

def deco1(func):
    def _deco1():
        print "deco1"
        return func()
    return _deco1

def deco2(msg):
    def _deco2(func):
        def _func():
            print msg
            return func()
        return _func
    return _deco2

@deco1
@deco2("jo_jaku")
def feiz():
    print "feiz"

print "call feiz()"
feiz()

naked_feiz = strip_decorators(feiz)

print "\ncall naked_feiz()"
naked_feiz()

出力

call feiz()
deco1
jo_jaku
feiz

call naked_feiz()
feiz

はずせたっぽいですね。

理解出来ていないところ

とりあえずそれっぽいことができたのはいいんですが、やっぱりきっちり理解しておきたい。

なので今のところ理解できてない部分をまとめておく。

func_closureの中のcellってオブジェクトはなんだ
とある方が教えてくれた記事を参考にする。 -> クロージャのひみつ - atsuoishimotoの日記
ほんとにこのコードで完璧に外せるのか
↑の記事を理解するか、いろんなパターンをためしまくる。
bound methodにstrip_decoratorsを適用するとfunctionになって返ってくるのはなぜか
bound methodはどこいった?

つづく

1/50

aodagaodag 2011/01/18 10:11 venusian

はてなユーザーのみコメントできます。はてなへログインもしくは新規登録をおこなってください。