上下文(可以跳过,后面是真正的问题)
整个过程并不重要,但是我正在进行一项调查,这让我越来越困惑。
我的一个宠物项目具有一些依赖于Python异常消息(而不仅仅是类型)的逻辑。由于它非常脆弱,因此请确保我可以在Travis上运行大多数Python版本的程序。
最近,我意识到一段代码set.add(0)
导致了一个异常,该异常的消息可能类似于:
描述符'add'需要一个'set'对象,但接收到一个'int'
但是,在某些Python 3.7+版本上,在一些测试用例中,情况似乎开始有所不同。显然,该消息更像是:
“用于'set'对象的描述符'add'不适用于'int'对象”
只是因为我想确保这是Python开发人员想要的,所以我想找到依靠某些git bisect
魔术来更改此内容的确切提交,并开始寻找一种简化方法来重现此问题。不幸的是,我无法在本地重现这种行为,导致另一件事的我掉进了兔子洞,并以许多谜团告终,其中一个涉及unittest.assertRaisesRegex
。
意外的unittest.assertRaisesRegex
行为
我编写了以下测试,这些测试看起来与文档中的unittest.assertRaisesRegex
示例令人惊讶地相似-一个测试提供了可调用且相对应的参数,另一个测试依赖于上下文管理器:
DESCRIPT_REQUIRES_TYPE_RE = r"descriptor '\w+' requires a 'set' object but received a 'int'"
...
def test_assertRaisesRegex(self):
self.assertRaisesRegex(TypeError, DESCRIPT_REQUIRES_TYPE_RE, set.add, 0)
def test_assertRaisesRegex_contextman(self):
with self.assertRaisesRegex(TypeError, DESCRIPT_REQUIRES_TYPE_RE):
set.add(0)
我希望他们两个都有完全相同的行为,但是他们没有。
(使用python -VV
和python -c "import sys; print(sys._git)"
检索版本号)
在某些版本中,两个测试均通过:
在某些版本上,两个测试均失败:
在某些版本中,只有test_assertRaisesRegex_contextman
失败,这让我感到困惑:
当它们发生时,失败看起来像:
======================================================================
FAIL: test_assertRaisesRegex (didyoumean_sugg_tests.SetAddIntRegexpTests)
----------------------------------------------------------------------
TypeError: descriptor 'add' for 'set' objects doesn't apply to 'int' object
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/home/travis/build/.../didyoumean_sugg_tests.py", line 19, in test_assertRaisesRegex
self.assertRaisesRegex(TypeError, DESCRIPT_REQUIRES_TYPE_RE, set.add, 0)
AssertionError: "descriptor '\w+' requires a 'set' object but received a 'int'" does not match "descriptor 'add' for 'set' objects doesn't apply to 'int' object"
和
======================================================================
FAIL: test_assertRaisesRegex_contextman (didyoumean_sugg_tests.SetAddIntRegexpTests)
----------------------------------------------------------------------
TypeError: descriptor 'add' for 'set' objects doesn't apply to 'int' object
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/home/travis/build/.../didyoumean/didyoumean_sugg_tests.py", line 23, in test_assertRaisesRegex_contextman
set.add(0)
AssertionError: "descriptor '\w+' requires a 'set' object but received a 'int'" does not match "descriptor 'add' for 'set' objects doesn't apply to 'int' object"
为什么这两个外观相似的测试会有不同的行为?
让我感到困惑的其他地方
我无法在要签出并构建的cpython代码上本地重现该问题(即使使用正确的SHA1)
在Travis上运行python -c "set.add(0)"
总是导致相同(预期)的字符串:
TypeError: descriptor 'add' requires a 'set' object but received a 'int'
目前状态
所有内容都可能归结为一个简单的细节,我很想念,但此刻我一无所知。任何建议都欢迎。如果需要更多数据,我很高兴触发更多Travis构建。