将unittest.assertRaisesRegex称为上下文管理器时,会出现不同的错误消息

时间:2019-02-10 00:52:42

标签: python exception python-unittest

上下文(可以跳过,后面是真正的问题)

整个过程并不重要,但是我正在进行一项调查,这让我越来越困惑。

我的一个宠物项目具有一些依赖于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 -VVpython -c "import sys; print(sys._git)"检索版本号)

  • 在某些版本中,两个测试均通过:

    • Python 3.6及更高版本
    • Python 3.7.0a4 +(heads / master:4666ec5,2018年1月26日,04:14:24)-[GCC 4.8.4]-('CPython','heads / master','4666ec5'))
  • 在某些版本上,两个测试均失败:

    • Python 3.8.0a1 +(heads / master:8a03ff2,2019年2月9日,07:30:26) [GCC 5.4.0 20160609]-(“ CPython”,“ heads / master”,“ 8a03ff2”)
  • 在某些版本中,只有test_assertRaisesRegex_contextman失败,这让我感到困惑:

    • Python 3.7.1(默认,2018年12月5日,18:09:53)[GCC 5.4.0 20160609]-('CPython','','')
    • Python 3.7.2+(heads / 3.7:3fcfef3,2019年2月9日,07:30:09) [GCC 5.4.0 20160609]-(“ CPython”,“ heads / 3.7”,“ 3fcfef3”)

当它们发生时,失败看起来像:

======================================================================
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构建。

0 个答案:

没有答案