在 init 中引发异常导致 SystemError:返回的结果在 Python C API 中设置了错误

问题描述 投票:0回答:1

我正在使用 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

这里有什么问题,我怎样才能让测试通过?

python error-handling pytest cpython python-c-api
1个回答
2
投票

您的

__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
)。

© www.soinside.com 2019 - 2024. All rights reserved.