Python:如何在单元(鼻子)测试期间忽略装饰器?
Posted
技术标签:
【中文标题】Python:如何在单元(鼻子)测试期间忽略装饰器?【英文标题】:Python: How to ignore decorators during unit (nose) tests? 【发布时间】:2018-06-05 23:26:51 【问题描述】:我想忽略我的代码中的某些装饰器以跳过相关的功能,但仅在作为单元测试的一部分运行时。这个可以吗?
例如,我有一个函数 f,使用 numba 装饰器定义如下:
@numba.jit
def f(a, b):
return a + b
当我运行调用上述函数的单元测试时,我不希望 numba 魔法发生,因为它会减慢速度并在某些平台上导致错误。是否可以在某个地方进行设置,告诉鼻子在不应用任何 numba 即时(和/或所有 numba)装饰器的情况下运行测试?
【问题讨论】:
我不知道,我不知道它会如何工作;我想你必须自己写。例如,您可以使用f = numba.jit(f)
表单在模块中的更高级别公开该函数,然后直接在您的测试中导入原始的解包版本。
【参考方案1】:
仅适用于 numba,您可以设置环境变量(例如 export NUMBA_DISABLE_JIT=1
)以使 jit 装饰器无操作。
http://numba.pydata.org/numba-doc/dev/user/troubleshoot.html#disabling-jit-compilation
【讨论】:
这个标志会在进程级别禁用 JIT,对吧? 你会在哪里指定export NUMBA_DISABLE_JIT=1
?我在我的项目存储库中添加了一个 .numba_config.yaml 文件,但这会全局禁用 NUMBA,这不是我想要的。我只想为 pytest 会话禁用 NUMBA(或至少只为覆盖率报告禁用)。你有什么想法吗?
@merowinger。这可能已经晚了,但是对于以后阅读此内容的任何人,您可以在 conftest.py 中指定 os.environ["NUMBA_DISABLE_JIT"] = "1"
并且它可以工作。【参考方案2】:
您也许可以欺骗鼻子使用您自己的装饰器来保持功能不变。
编写一个包含此函数的文件numba.py
:
def jit(func):
return func
并放置在您的 PYTHONPATH 中。 要么从这个文件所在的目录运行你的测试,要么在 您的测试文件作为第一行:
import sys
sys.path.insert(0, 'path/to/dir/with/myfile')
或者,您可以将环境变量PYTHONPATH
设置为您的文件所在的目录。
窗户:
set PYTHONPATH=%PYTHONPATH%;path/to/dir/with/myfile
Unix/Mac:
export PYTHONPATH=$PYTHONPATH$:path/to/dir/with/myfile
【讨论】:
为我的测试工作。 是的,它可能不适用于混合了装饰器和其他东西的库。但是对于numba
,这是一个很好的解决方案。也许对于其他图书馆,它会类似于module.decorator = lambda f:f
。【参考方案3】:
你可以用你可以控制的新装饰器来修补装饰器:
import functools
def patch(parent, obj_name, switch_reg, switch_name):
def gen_switcher():
def wrapper(func):
ori_wrapped = ori_decorator(func)
@functools.wraps(func)
def _(*args, **kwargs):
if switch_reg.get(switch_name, False):
func_to_call = func
else:
func_to_call = ori_wrapped
print(func_to_call)
return func_to_call(*args, **kwargs)
return _
return wrapper
ori_decorator = getattr(parent, obj_name)
setattr(parent, obj_name, gen_switcher())
与:
# have to patch the decorator before applying it
import numba
switchs =
patch(numba, 'jit', switchs, 'DISABLE_NUMBA_JIT')
@numba.jit
def f(a, b):
return a + b
f(1, 2)
产量:
CPUDispatcher(<function f at 0x10a5f90d0>)
然后用:
# this part could be rewrited as a context manager
switchs['DISABLE_NUMBA_JIT'] = True
f(1, 2)
得到:
<function f at 0x10a5f90d0>
【讨论】:
这比我想进入的更神奇,因为看起来有更简单的解决方案,但是“好样的!”尽管如此。感谢您的帮助。 @JamesAdams 我没想到你的问题可以通过简单的谷歌和阅读文档来解决。【参考方案4】:我会将函数分成一个非装饰部分进行单元测试——然后让你的真实函数具有装饰器并简单地调用辅助函数:
@numba.jit
def f(a, b):
return f_undecorated(a, b)
def f_undecorated(a, b):
return a + b
仅为f_undecorated
编写单元测试。
【讨论】:
这是一种有趣/聪明的方法,很好,因为它使您无需对环境中的任何东西进行胡思乱想,一切都在代码中。然而,还有更多的代码/复杂性(实际上是名义上的),所以就是这样。不知道它与上面对我有用的答案相比如何(请告知)。无论如何感谢您的帮助,感谢您的努力。【参考方案5】:如果您使用coverage
,您可以通过在coverage
命令之前添加NUMBA_DISABLE_JIT=1
来修改您的CI .yml
文件:
NUMBA_DISABLE_JIT=1 coverage run -p "test_*.py"
【讨论】:
以上是关于Python:如何在单元(鼻子)测试期间忽略装饰器?的主要内容,如果未能解决你的问题,请参考以下文章