Python C++ API:如何检索 NameError 的 lineno 属性

Posted

技术标签:

【中文标题】Python C++ API:如何检索 NameError 的 lineno 属性【英文标题】:Python C++ API: How to retrieve lineno attribute of NameError 【发布时间】:2017-10-19 08:28:50 【问题描述】:

我正在使用用于 C/C++ 的 python API,我想检索 发生 NameError 时的行号。

我按照以下问题中的说明进行操作:

How to retrieve filename and lineno attribute of SyntaxError

我写了以下代码:

PyObject *ptype = NULL, *pvalue = NULL, *ptraceback = NULL;
PyObject *comp = NULL, *eval = NULL;
char code[] = "A=undef_var";

comp = Py_CompileString(code, "", Py_file_input);
if (comp) 
    eval = PyEval_EvalCode(comp, PyEval_GetBuiltins(), NULL);

if (!comp || !eval) 
     PyErr_PrintEx(1); // inside this function the PyErr_Fetch(ptype, pvalue, ptraceback) is called

     // retrieve the information gained from PyErr_Fetch() called inside PyErr_PrintEx(1) 
     pvalue     = PySys_GetObject("last_value"); 
     ptype      = PySys_GetObject("last_type");  
     ptraceback = PySys_GetObject("last_traceback");  
     PyErr_NormalizeException(ptype, pvalue, ptraceback);

    PyObject* line_no = PyObject_GetAttrString(pvalue,"lineno");
    if (line_no) 
         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);
    

上面的代码返回正确的行号,以防python代码 包含一个 SyntaxError(例如,对于像“A =”这样的简单 python 代码), 但在出现 NameError 的情况下,行号未正确设置为 pvalue 对象(例如,对于 python 代码:“A=undefined_var”)。

有什么办法可以解决这个问题吗?

【问题讨论】:

你不能为此使用 boost 库吗?然后你可以查看这个 *** 链接:How to get Python exception text 很遗憾,我无法使用 boost 库。感谢您的回答! 请注意,您绝对必须检查每个Py_*函数的返回值,分别并采取相应措施。跨度> 您会注意到NameError 甚至没有lineno 属性。 如果你做对了,你会知道 NameError 没有属性lineno 就是原因它不起作用。您需要访问traceback 【参考方案1】:

在@Antti Haapala 的帮助下,并考虑了发布到此question 的解决方案,我得出以下解决方案:

PyObject *ptype = NULL, *pvalue = NULL, *ptraceback = NULL;
PyObject *compile_obj = NULL, *eval_obj = NULL;
PyObject *line_no = NULL, *line_no_str = NULL, *line_no_unicode = NULL;
char *actual_line_no = NULL;
char code[] =  "A=undef_var" ;
int line_num = 0;

compile_obj = Py_CompileString(code, "", Py_file_input);
if (compile_obj) 
    eval_obj = PyImport_ExecCodeModule((char *)"", compile_obj);

if (!compile_obj || !eval_obj) 
    PyErr_PrintEx(1); // inside this function the PyErr_Fetch(ptype, pvalue, ptraceback) is called
                      // retrieve the information gained from PyErr_Fetch() called inside PyErr_PrintEx(1) 
    pvalue     = PySys_GetObject("last_value");
    ptype      = PySys_GetObject("last_type");
    ptraceback = PySys_GetObject("last_traceback");
    if (ptype) 
        PyErr_NormalizeException(&ptype, &pvalue, &ptraceback);
    
    if (compile_obj)  // NameError
        if (ptraceback) 
            PyTracebackObject *tb_o = (PyTracebackObject *)ptraceback;
            line_num = tb_o->tb_lineno;
        
     else  //Syntax Error
        line_no = PyObject_GetAttrString(pvalue, "lineno");
        if (line_no) 
            line_no_str = PyObject_Str(line_no);
            if (line_no_str)     line_no_unicode = PyUnicode_AsEncodedString(line_no_str, "utf-8", "Error");
            if (line_no_unicode) actual_line_no = PyBytes_AsString(line_no_unicode);
            if (actual_line_no)  line_num = atoi(actual_line_no);

            Py_XDECREF(line_no);
            Py_XDECREF(line_no_str);
            Py_XDECREF(line_no_unicode);
        
    

Py_XDECREF(compile_obj);
Py_XDECREF(eval_obj);

return line_num;

【讨论】:

您在此代码中缺少 至少 8 个返回值检查 - 此外,您这里还有几个泄漏。 此外,您只是假设返回值。

以上是关于Python C++ API:如何检索 NameError 的 lineno 属性的主要内容,如果未能解决你的问题,请参考以下文章

如何将数组从 c++ 传递给 python 函数并将 python 返回的数组检索到 c++

如何使用 Gmail API (python) 检索整个邮件正文

如何使用纯 Python 扩展 API (python3) 包装 C++ 对象?

如何通过 Python/C API 将 Python 实例传递给 C++

MXNET C++ 代码如何与其 python API 绑定?

从 C++ 中检索 Python 类型