这个 DeprecationWarning ("callable is None") 是怎么回事?

What's with this DeprecationWarning ("callable is None")?

我正在编写一个模块,并且我正在使用 unittest 与实际代码一起编写单元测试。

有时(看起来几乎是不确定的),像下面这样的函数没有明确地 return 一个值,用 self.assertRaises(mymodule.MyEmptyException, myfunc()) 断言(其中 self 指的是子类unittest.TestCase) 提出了一个神秘的 DeprecationWarning.

下面是此类函数的示例:

def insertn(self, items, lidex):
    """( z y x -- z b y x )
    add a list of items to the stack at the given index"""
    iter(items)
    for idx, obj in enumerate(items):
        self.insert(lidex, obj)
        lidex += 1

其对应的单元测试:

def test_insertn_fail(self):
    """expect failure during multiple insertion"""
    self.assertRaises(mouse16.BadInternalCallException,
        stack.insertn([8, 4, 12], 16))
    with self.assertRaises(TypeError):
        stack.insertn(8, 16)

给出(例如):

./mousetesting.py:103: DeprecationWarning: callable is None

我认为使函数具有非 None return 值可能会解决问题(即 return 0),但后来我得到(例如):

======================================================================
ERROR: test_insertn_fail (__main__.CoreStack)
expect failure during multiple insertion
----------------------------------------------------------------------
Traceback (most recent call last):
  File "./mousetesting.py", line 103, in test_insertn_fail
    stack.insertn([8, 4, 12], 16))
  File "/usr/lib/python3.5/unittest/case.py", line 727, in assertRaises
    return context.handle('assertRaises', args, kwargs)
  File "/usr/lib/python3.5/unittest/case.py", line 176, in handle
    callable_obj(*args, **kwargs)
TypeError: 'int' object is not callable

----------------------------------------------------------------------

所以 unittest 模块正在尝试调用函数的 return 值...但不会抱怨 None 不是 callable 吗?

我不太了解 Python 的内部结构,无法理解这里发生的事情。我想避免我的测试以一种我不知道将来如何修复的方式中断,因为我忽略了 DeprecationWarning

我的函数(但只是其中的一部分,而不是所有函数?)return 必须使用(内存浪费)闭包或无意义的 lambda 表达式来避免这种情况?或者我应该制作一个检测测试是否正在进行的东西,然后 只有 return 一个空操作 lambda?为了避免 DeprecationWarning.

这似乎需要做很多工作

您使用的 self.assertRaises() 不正确。它必须为你调用测试函数,以捕获异常:

self.assertRaises(mouse16.BadInternalCallException,
    stack.insertn, [8, 4, 12], 16)

您传递了 stack.insertn() 调用的 结果(它没有引发异常,但 return 要么 None 或一个整数),并且 return 值不可调用。该方法的旧版本也接受了该参数的 None,但不再受支持,因此当传入 None 而不是整数时会出现弃用警告。

更好的方法是使用 self.assertRaises() 作为上下文管理器:

with self.assertRaises(mouse16.BadInternalCallException):
    stack.insertn([8, 4, 12], 16)