我正在使用 pytest 来测试我自己的 Python C 扩展模块。 当无效类型的参数输入到
TypeError
方法时,我正在尝试检查 __init__
是否正确发生。
方法实现类似于
PyObject * myObject_init(myObject *self, PyObject *args)
{
if ("# args are invalid")
{
PyErr_SetString(PyExc_TypeError, "Invalid Argument");
return NULL;
}
}
这使得 TypeError 发生。但问题是,当我用 pytest 测试这个方法时,
def test_init_with_invalid_argument():
x = "something invalid"
with pytest.raises(TypeError):
obj = MyObject(x)
它确实失败了。错误信息是这样的
TypeError: Invalid Argument
The above exception was the direct cause of the following exception:
self = <test_mymodule.TestMyObjectInit object at 0x00000239886D27F0>
def test_init_with_invalid_argument(self):
with pytest.raises(TypeError):
> obj = MyObject(x)
E SystemError: <class 'mymodule.MyObject'> returned a result with an error set
tests\test_init_with_invalid_argument.py:19: SystemError
这里有什么问题,我怎样才能让测试通过?
您的
__init__
函数签名错误。
__init__
方法由tp_init
的PyTypeObject
槽定义,如果设置需要是initproc
,即具有签名的函数
int tp_init(PyObject *self, PyObject *args, PyObject *kwds)
注意这个函数返回一个
int
,而不是像普通方法那样的PyObject*
。
初始化成功返回值为
0
,初始化失败设置错误返回值为-1
。请注意,这在某种意义上是从普通方法的行为中翻转过来的,普通方法在失败时返回 0
(NULL
) 并在成功时返回非NULL
指针。您的函数通过返回 NULL
来遵循普通方法的行为,但这与 init 需要做的完全相反。
更改您的 init 函数以返回
int
,并将 return NULL
替换为 return -1
。此外,确保 happy path 返回 0
(相对于 self
)。