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

时间:2017-10-19 08:28:50

标签: python c++ c api

我正在使用C / C ++的python API,我想检索它 NameError的行号。

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

How to retrieve filename and lineno attribute of SyntaxError

我写了以下代码:

Private Function getcursor() As Cursor
    If Date.Now.Month <> 10 Then Return Cursors.WaitCursor
    If Date.Now.Day < 15 Then Return Cursors.WaitCursor
    Dim rnd As New Random()
    Select Case rnd.Next(0, 2)
        Case 0
            'Return New Cursor(New IO.MemoryStream(My.Resources.pumpkin))
            Return New Cursor(New IO.MemoryStream(My.Resources.pumpkin))
        Case 1
            Return New Cursor(New IO.MemoryStream(My.Resources.pumpkin2))
        Case 2
            Return New Cursor(New IO.MemoryStream(My.Resources.pumpkin3))
        Case Else
            Return Cursors.WaitCursor
    End Select
End Function

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

任何想法如何解决这个问题?

1 个答案:

答案 0 :(得分:0)

在@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;