扩展和嵌入Python之获取程序出错信息

接着我们上次的内容继续。简单回顾下,上次的这种嵌入方式在Python中称为纯嵌入,我们可以定义自己的模块,在模块中定义自己的函数,通过C API可以让Python解释器识别我们的自定义模块。

在程序调试的过程中,难免会有错误产生,谁也不希望程序出错后一点提示信息也没有,然后就挂了。就像程序员最不喜欢写文档,然后也很痛恨接手的项目没有文档一样~~~如何获取嵌入Python的报错信息,就是本次的主要内容。

回想当时在网上找了好久,终于完成了上一次的程序,还兴奋了好一会儿~~但接下来的问题就是如何获取程序的出错信息。在基于上一次的程序基础上,得出的最终结果是不行!惊不惊喜?刺不刺激?翻阅了网上大部分文章,得出一个非常一致的结论,要用下面的代码片段:PyObject *ptype = NULL, *pvalue = NULL, *ptraceback = NULL;

  PyErr_Fetch(&ptype,&pvalue,&ptraceback);

  PyErr_NormalizeException(&ptype,&pvalue,&ptraceback);(可有可无)

 

  if(pvalue)

  {

......

}

但是,并没有说在哪添加......试了N多次无果。最终读了N次stackoverflow(英语还是很重要),从前辈们的只言片语中发现了秘密...帖子的时间好像是2013年吧...

OK,老规矩,直接“上马”。

 

void Widget::on_pbn_runPython_clicked()

{

    qDebug() << "enter python !";

    PyImport_AppendInittab("dahe", &PyInit_math);

 

    Py_Initialize();

    if (!Py_IsInitialized())

    {

        qDebug() << "inital faild!";

    }

 

    PyRun_SimpleString("import dahe");

    QFile f("/root/Python/Article/compilePython/dhTest.py");

 

    if(!f.open(QFile::ReadOnly | QFile::Text))

    {

        qDebug() << "read file faild:" << qPrintable(f.errorString());

    }

    QTextStream stream(&f);

    QString test = stream.readAll();

    QByteArray ba = test.toLatin1();

    const char * script_source = ba.data();

 

    PyObject* main = PyModule_GetDict(PyImport_AddModule("__main__"));

    PyObject *res = PyRun_String(script_source,Py_file_input,main,main);

    if(res == NULL)

    {

        PyObject *ptype = NULL, *pvalue = NULL, *ptraceback = NULL;

        PyErr_Fetch(&ptype,&pvalue,&ptraceback);

        PyErr_NormalizeException(&ptype,&pvalue,&ptraceback);

 

        if(pvalue)

        {

            PyObject *pstr = PyObject_Str(pvalue);

            if(pstr) {

                const char* err_msg = PyUnicode_AsUTF8(pstr);

                if(pstr)

                {

                    printf("%s----\n",err_msg);

                }

            }

        }

 

        char *msg, *file, *text;

        int line, offset;

 

        int res = PyArg_ParseTuple(pvalue,"s(siis)",&msg,&file,&line,&offset,&text);

        Q_UNUSED(res);

 

        PyObject* line_no = PyObject_GetAttrString(pvalue,"lineno");

        PyObject* line_no_str = PyObject_Str(line_no);

        PyObject* line_no_unicode = PyUnicode_AsEncodedString(line_no_str,"utf-8", "Error");

        char *actual_line_no = PyBytes_AsString(line_no_unicode);

        printf("actual_line_no --%s\n",actual_line_no);

    }

 

    Py_Finalize();

}

 

上述代码是前一次内容的修改,重复部分不再赘述。

使用QFile读取存储文件的内容,该部分简单略过。

在这里看到了PyErr_Fetch(&ptype,&pvalue,&ptraceback)该函数是如何使用的,需要先“编译”python文件,在编译过程中出错才可以调用该函数捕获出错信息。PyObject *res = PyRun_String(script_source,Py_file_input,main,main)注意后面的两个main,如果传为NULL,有时测试出错会报出PyEval_EvalCodeEx: NULL globals这个出错信息,注意下。

PyErr_NormalizeException(&ptype,&pvalue,&ptraceback)该函数用于将异常信息格式化输出,根据需要来使用。不使用的话会捕获到更原始的信息。

PyObject *pstr = PyObject_Str(pvalue) 、const char* err_msg = PyUnicode_AsUTF8(pstr),python C API中的类型大多是PyObject *,这里提供了一种转为c中char*的方法。

Q_UNUSED(res),Qt中提供的一种消除无用参数警告的方式,该宏的函数原型是(void)()。

程序的最后部分是获取出错信息的位置,也就是行号。Pvalue捕获的是出错的内容,有时也会有行号。

至此,程序简单说明结束。下面给出脚本内容以及捕获的具体出错内容。

 

 

 

 

 

如果觉得还阔以,可以关注我的公众号,欢迎大家交流。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值