3

この質問は、 Python のデコレータに関するこのすばらしい回答 のフォローアップです。

与えられた「スニペットを使用して、デコレーターが一般的に任意の引数を受け入れるようにします」。

それから私はこの(ここでは簡略化された)デコレータを持っています:

@decorator_with_args
def has_permission_from_kwarg(func, *args, **kwargs):
    """Decorator to check simple access/view rights by the kwarg."""
    def wrapper(*args_1, **kwargs_1):
        if 'kwarg' in kwargs_1:
            kwarg = kwargs_1['kwarg']
        else:
            raise HTTP403Error()

        return func(*args_1, **kwargs_1)

    return wrapper
  1. このデコレータを使用すると、問題なくうまく機能します。
  2. kwargs をまったく必要としない同様のデコレータをテストしても、同じ結果になります。
  3. しかし、次のモックでこのデコレータをテストしてもうまくいきません:

    def test_can_access_kwarg(self):
        """Test simple permission decorator."""
        func = Mock(return_value='OK')
        decorated_func = has_permission_from_slug()(func(kwarg=self.kwarg))
        # It will raise at the following line, whereas the kwarg is provided...
        response = decorated_func()
        self.assertTrue(func.called)
        self.assertEqual(response, 'OK')
    

「kwarg」キーワード引数がない場合に発生する例外を返します...

関数に渡されたキーワード引数の1つへのアクセスを必要とする別のデコレータによって装飾されたそのようなデコレータをテストする方法の手がかりはありますか?

4

1 に答える 1

2
decorated_func = has_permission_from_slug()(func(kwarg=self.kwarg))

この意志:

  1. 実行するfunc(kwarg=self.kwarg)
  2. 実際のデコレータのインスタンスを生成します。
  3. 関数呼び出しの結果 (つまり結果)でデコレータを呼び出します。
  4. 後で手順 3 の結果を呼び出そうとするラッパーを返します (これは失敗します)。

    応答 = 装飾された_関数()

これは、返されたラッパーを引数なしで呼び出すため、**kwargs_1空です。また、この場合にラッパーが例外を発生させない場合、(元の値) の戻り値はおそらく呼び出し可能ではないため、後続の の呼び出しでfunc(..)例外がスローされます(上記を参照)。func

おそらく代わりにやりたいこと、または少なくともデコレーターがサポートしていることは次のとおりです。

decorated_func = has_permission_from_kwarg()(func)
response = decorated_func(kwarg=self.kwarg)

kwargまたは、次のようにデコレータに渡したい場合:

decorated_func = has_permission_from_kwarg(kwarg=self.kwarg)(func)
response = decorated_func()

kwargs次に、チェックではなく、実際に使用するようにまたはデコレータを調整する必要がありますkwargs_1(後者は、装飾された関数への引数です)。


元のデコレータ定義(変更なし)とdecorator_with_args、リンクされた回答で定義されているものを次のコードでテストしています:

class HTTP403Error (Exception):
    pass

def func (*args, **kwargs):
    print('func {}; {}'.format(args, kwargs))

my_kwarg = 'foo'
decorated_func = has_permission_from_kwarg()(func)
decorated_func(kwarg=my_kwarg)
decorated_func(not_kwarg=my_kwarg)

予想どおり、func (); {'kwarg': 'foo'}最初の呼び出しでは出力され、2 回目の呼び出しでは HTTP403 例外が出力されます。

于 2012-11-13T11:40:42.633 に答える