为测试目的访问原始装饰功能

问题描述 投票:4回答:2

我在使用一个装饰器(@render_to 来自 django_annoying 包)的视图函数中。

但问题是,我想得到view函数返回的原始dict,而不是用在测试上的 HttpResponse 对象,装饰器返回。

装饰器使用 @wraps (自 functools).

如果没有办法访问这个,那么你有什么办法可以测试这个吗?

python testing decorator python-decorators introspection
2个回答
9
投票

封装后的函数将以函数闭包单元格的形式存在。具体是哪个单元格,取决于有多少个闭包变量。

对于一个简单的封装器,其中唯一的闭包变量是函数-to-wrap,它将是第一个。

wrapped = decorated.func_closure[0].cell_contents

但你可能需要检查所有的 func_closure 值。

演示使用 functools.wraps() 样板间

>>> from functools import wraps
>>> def my_decorator(f):
...     @wraps(f)
...     def wrapper(*args, **kwds):
...         print 'Calling decorated function'
...         return f(*args, **kwds)
...     return wrapper
... 
>>> @my_decorator
... def example():
...     """Docstring"""
...     print 'Called example function'
... 
>>> example
<function example at 0x107ddfaa0>
>>> example.func_closure
(<cell at 0x107de3d70: function object at 0x107dc3b18>,)
>>> example.func_closure[0].cell_contents
<function example at 0x107dc3b18>
>>> example()
Calling decorated function
Called example function
>>> example.func_closure[0].cell_contents()
Called example function

观察到的情况 源码 @render_to 但你不必担心这个问题;封装函数将被存储在第一个闭包槽中,保证。

如果这是在 Python 3 中,可以使用 __wrapped__ 属性来代替。

>>> example.__wrapped__
<function example at 0x103329050>

如果你能访问装饰器代码本身, 你可以很容易地在Python 2代码中添加同样的引用。

def my_decorator(f):
    @wraps(f)
    def wrapper(*args, **kwds):
        # implementation

    wrapper.__wrapped__ = f
    return wrapper

让反省变得更加容易。


0
投票

这里有一段代码,它可以递归搜索在多个层次上被装饰的原始函数.其背后的逻辑和@Martin提到的答案是一样的。

def get_original_decorated_function(deco_func, org_func_name= None):
    if not deco_func.func_closure:
        if deco_func.__name__ == org_func_name:
            return deco_func
        else:
            return None
    for closure in deco_func.func_closure:
        func = closure.cell_contents
        if func.__name__ == org_func_name:
            # This is the original function name
            return func
        else:
            # Recursively call the intermediate function
            return get_original_decorated_function(func, org_func_name)
© www.soinside.com 2019 - 2024. All rights reserved.