Search code examples
c++pythonexceptionboost-python

How to get Python exception text


I want to embed python in my C++ application. I'm using Boost library - great tool. But i have one problem.

If python function throws an exception, i want to catch it and print error in my application or get some detailed information like line number in python script that caused error.

How can i do it? I can't find any functions to get detailed exception information in Python API or Boost.

try {
module=import("MyModule"); //this line will throw excetion if MyModule contains an   error
} catch ( error_already_set const & ) {
//Here i can said that i have error, but i cant determine what caused an error
std::cout << "error!" << std::endl;
}

PyErr_Print() just prints error text to stderr and clears error so it can't be solution


Solution

  • Well, I found out how to do it.

    Without boost (only error message, because code to extract info from traceback is too heavy to post it here):

    PyObject *ptype, *pvalue, *ptraceback;
    PyErr_Fetch(&ptype, &pvalue, &ptraceback);
    //pvalue contains error message
    //ptraceback contains stack snapshot and many other information
    //(see python traceback structure)
    
    //Get error message
    char *pStrErrorMessage = PyString_AsString(pvalue);
    

    And BOOST version

    try{
    //some code that throws an error
    }catch(error_already_set &){
    
        PyObject *ptype, *pvalue, *ptraceback;
        PyErr_Fetch(&ptype, &pvalue, &ptraceback);
    
        handle<> hType(ptype);
        object extype(hType);
        handle<> hTraceback(ptraceback);
        object traceback(hTraceback);
    
        //Extract error message
        string strErrorMessage = extract<string>(pvalue);
    
        //Extract line number (top entry of call stack)
        // if you want to extract another levels of call stack
        // also process traceback.attr("tb_next") recurently
        long lineno = extract<long> (traceback.attr("tb_lineno"));
        string filename = extract<string>(traceback.attr("tb_frame").attr("f_code").attr("co_filename"));
        string funcname = extract<string>(traceback.attr("tb_frame").attr("f_code").attr("co_name"));
    ... //cleanup here