Domanda

Voglio incorporare Python nella mia applicazione C ++. Sto usando la libreria Boost - ottimo strumento. Ma ho un problema.

Se la funzione python genera un'eccezione, desidero rilevarla e stampare un errore nella mia applicazione o ottenere informazioni dettagliate come il numero di riga nello script Python che ha causato l'errore.

Come posso farlo? Non riesco a trovare alcuna funzione per ottenere informazioni dettagliate sull'eccezione nell'API Python o 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 () stampa il testo dell'errore su stderr e cancella l'errore in modo che non possa essere una soluzione

È stato utile?

Soluzione

Bene, ho scoperto come farlo.

Senza boost (solo messaggio di errore, perché il codice per estrarre informazioni dal traceback è troppo pesante per pubblicarlo qui):

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);

E versione BOOST

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

Altri suggerimenti

Questo è il metodo più efficace che sono stato in grado di elaborare finora:

    try {
        ...
    }
    catch (bp::error_already_set) {
        if (PyErr_Occurred()) {
            msg = handle_pyerror(); 
        }
        py_exception = true;
        bp::handle_exception();
        PyErr_Clear();
    }
    if (py_exception) 
    ....


// decode a Python exception into a string
std::string handle_pyerror()
{
    using namespace boost::python;
    using namespace boost;

    PyObject *exc,*val,*tb;
    object formatted_list, formatted;
    PyErr_Fetch(&exc,&val,&tb);
    handle<> hexc(exc),hval(allow_null(val)),htb(allow_null(tb)); 
    object traceback(import("traceback"));
    if (!tb) {
        object format_exception_only(traceback.attr("format_exception_only"));
        formatted_list = format_exception_only(hexc,hval);
    } else {
        object format_exception(traceback.attr("format_exception"));
        formatted_list = format_exception(hexc,hval,htb);
    }
    formatted = str("\n").join(formatted_list);
    return extract<std::string>(formatted);
}

Nell'API Python C, PyObject_Str restituisce un nuovo riferimento a un oggetto stringa Python con la forma stringa dell'oggetto Python che stai passando come argomento, proprio come str (o) nel codice Python. Nota che l'oggetto dell'eccezione non ha "informazioni come il numero di riga" - è nell'oggetto traceback (puoi usare < code> PyErr_Fetch per ottenere sia l'oggetto eccezione sia l'oggetto traceback). Non so cosa (se non altro) fornisce Boost per rendere più facili da usare queste specifiche funzioni dell'API C, ma, nel peggiore dei casi, potresti sempre ricorrere a queste funzioni poiché sono offerte nell'API C stessa.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top