[英]Get function or class method name from inside decorator in Python
我有一个以下装饰器。
def allow_disable_in_tests(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
version = ??? # name of the func of method’s class name
need_to_switch_off_in_tests = cache.get('switch_off_in_tests', version=version)
if settings.IM_IN_TEST_MODE and need_to_switch_off_in_tests:
return None
value = func(*args, **kwargs)
return value
return wrapper
这个装饰器可以接受 2 种类型的对象作为func
:
独立 function。
类的方法(绑定方法,static 方法和 class 方法都可能)
问题是如何从内部装饰器名称中获取:
function 在func
的情况下是独立的 function。
在func
的情况下,方法的 class 名称是 class 的方法
这将在version
中使用。
装饰器应该能够处理这两种类型的对象。
谢谢
您可以使用__qualname__
和__module__
来获取此信息。 __qualname__
将描述根据 class 或 function 在模块中定义 class 的位置。
但是,您将测试逻辑放入生产代码中,这有点代码味道。 在运行测试套件时,最好使用测试框架的猴子修补功能来修补这些功能。 例如,对于 pytest:
import pytest
from functools import wraps
from inspect import signature
class FuncPatch:
def __init__(self, parent, name, retval=None):
self.parent = parent
self.name = name
self.retval = retval
def get_things_to_patch():
import mymodule
return (
FuncPatch(mymodule, 'my_func'),
FuncPatch(mymodule.MyClass, 'method'),
FuncPatch(mymodule.MyClass, 'static'),
FuncPatch(mymodule.MyClass, 'class_', retval='special'),
)
def create_test_function(func, retval, decorator=None):
func = getattr(func, '__func__', func) # unwrap if classmethod or normal method
sig = signature(func)
@wraps(func)
def f(*args, **kwargs):
# check func was called with correct params raises TypeError if wrong
sig.bind(*args, **kwargs)
return retval
if decorator:
f = decorator(f)
return f
@pytest.fixture
def patch_all_the_things(monkeypatch):
for patch in get_things_to_patch():
decorator = None
if (isinstance(patch.parent, type)
and not callable(patch.parent.__dict__[patch.name])
):
# quick hack to detect staticmethod or classmethod
decorator = type(patch.parent.__dict__[patch.name])
to_patch = getattr(patch.parent, patch.name)
func = create_test_function(to_patch, patch.retval, decorator)
monkeypatch.setattr(patch.parent, patch.name, func)
# things to test
def my_func():
return 'my_func'
class MyClass:
@staticmethod
def static():
return 'static'
@classmethod
def class_(cls):
return 'class'
def method(self):
return 'method'
# actual tests
def test_my_func(patch_all_the_things):
assert my_func() is None
def test_my_class(patch_all_the_things):
assert MyClass().method() is None
assert MyClass.method(MyClass()) is None
assert MyClass.static() is None
assert MyClass.class_() == 'special'
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.