You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python C扩展__init__抛异常引发SystemError,pytest测试失败如何解决?

问题描述

我在用pytest测试自定义Python C扩展模块,想要验证当__init__方法传入无效类型参数时,能否正确抛出TypeError。

我的C实现代码如下:

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
问题原因

你的C扩展中__init__方法的实现违反了Python C API的规范:

  • Python对象的__init__方法对应C API中的tp_init成员,它的函数签名必须返回int类型,而非PyObject*。返回0表示初始化成功,返回-1表示初始化失败且已设置异常。
  • 你错误地使用了PyObject*作为返回类型,并在失败时返回NULL,这是tp_new(对应Python中的__new__)的返回逻辑。Python解释器调用tp_init时,无法识别这个返回值,因此会抛出SystemError,即使你已经正确设置了TypeError。
解决方法

修改C代码的函数签名和返回值,符合tp_init的规范:

  1. 调整函数的返回类型为int,并补充可选的关键字参数(kwds)参数:
// 注意签名:返回int,新增kwds参数(即使不用也要保留,符合API规范)
int myObject_init(myObject *self, PyObject *args, PyObject *kwds)
{
    // 替换成真实的参数校验逻辑,示例:检查是否为整数类型
    PyObject *arg;
    if (!PyArg_ParseTuple(args, "O", &arg) || !PyLong_Check(arg)) {
        PyErr_SetString(PyExc_TypeError, "Invalid Argument: expected integer");
        return -1; // 返回-1表示初始化失败
    }

    // 这里写正常的初始化逻辑

    return 0; // 返回0表示初始化成功
}
  1. 在类型对象定义中,确保tp_init指向这个正确的函数:
static PyTypeObject myObjectType = {
    PyVarObject_HEAD_INIT(NULL, 0)
    .tp_name = "mymodule.MyObject",
    .tp_basicsize = sizeof(myObject),
    .tp_init = (initproc)myObject_init, // 绑定正确的初始化函数
    // 其他类型定义字段...
};

修改完成后重新编译扩展模块,再运行pytest测试,就能正确捕获到TypeError,测试通过。


内容的提问来源于stack exchange,提问作者agongji

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 18:32:50