我正在为Python库编写一些单元测试,并希望将某些警告作为异常引发,这可以通过simplefilter函数轻松完成。但是,对于一个测试,我想禁用警告,运行测试,然后重新启用警告。
我使用的是Python2.6,所以我应该可以使用catch_warnings上下文管理器来实现这一点,但它似乎对我不起作用。即使失败了,我也应该能够调用resetwarnings,然后重新设置过滤器。
下面是一个简单的例子来说明这个问题:
>>> import warnings
>>> warnings.simplefilter("error", UserWarning)
>>>
>>> def f():
... warnings.warn("Boo!", UserWarning)
...
>>>
>>> f() # raises UserWarning as an exception
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in f
UserWarning: Boo!
>>>
>>> f() # still raises the exception
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in f
UserWarning: Boo!
>>>
>>> with warnings.catch_warnings():
... warnings.simplefilter("ignore")
... f() # no warning is raised or printed
...
>>>
>>> f() # this should raise the warning as an exception, but doesn't
>>>
>>> warnings.resetwarnings()
>>> warnings.simplefilter("error", UserWarning)
>>>
>>> f() # even after resetting, I'm still getting nothing
>>>
有人能解释一下我是怎么做到的吗?
编辑:显然这是一个已知的错误:http://bugs.python.org/issue4180
Brian Luft关于问题的起因是
__warningregistry__
是正确的。但我想澄清一件事:这个warnings
模块的工作方式是为每个调用warn()
的模块设置module.__warningregistry__
。更复杂的是,warnings的stacklevel
选项会导致为发出警告的模块设置属性,而不一定是调用warn()
的模块。。。这取决于发出警告时的调用堆栈。这意味着您可能有很多不同的模块,其中存在
__warningregistry__
属性,并且根据您的应用程序,在您再次看到警告之前,它们可能都需要清除。我一直依赖下面的代码片段来完成这项工作。。。它清除名称与regexp匹配的所有模块的警告注册表(默认为everything):更新:CPythonissue 21724地址问题表明resetwarnings()未清除警告状态。我在这个问题上附加了一个扩展的“上下文管理器”版本,可以从reset_warning_registry.py下载。
读了几遍文档,翻了几遍源代码和外壳,我想我已经找到了。文档可能会有所改进,以便更清楚地了解行为是什么。
警告模块在warnings registry保存一个注册表,以跟踪显示了哪些警告。如果在设置“error”筛选器之前注册表中没有列出警告(消息),则对warn()的任何调用都不会导致将消息添加到注册表中。此外,在第一次调用warn之前,似乎不会创建警告注册表:
现在,如果忽略警告,它们将被添加到警告注册表:
因此,错误筛选器将只应用于警告注册表中尚未出现的警告。要使代码正常工作,您需要在使用上下文管理器之后(或者通常在使用忽略筛选器并需要prev之后的任何时候)从警告注册表中清除相应的条目。用于提取错误筛选器的消息)。似乎有点不自然。。。
布赖恩对这件事很在行。所以您需要扩展
catch_warnings
来保存/恢复全局__warningregistry__
像这样的事情可能行得通
相关问题 更多 >
编程相关推荐