Как получить текст исключения Python
-
07-07-2019 - |
Вопрос
Я хочу встроить python в мое приложение C ++. Я использую библиотеку Boost - отличный инструмент. Но у меня есть одна проблема. Р>
Если функция python выдает исключение, я хочу перехватить его и напечатать ошибку в моем приложении или получить некоторую подробную информацию, например номер строки в скрипте python, вызвавшей ошибку.
Как я могу это сделать? Я не могу найти какие-либо функции для получения подробной информации об исключениях в Python API или 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 () просто печатает текст ошибки в stderr и очищает ошибку, чтобы она не могла быть решением
Решение
Ну, я узнал, как это сделать.
Без повышения (только сообщение об ошибке, потому что код для извлечения информации из трассировки слишком тяжел для размещения здесь):
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);
И 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
Другие советы
Это самый надежный метод, который я когда-либо мог придумать:
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);
}
В API Python C PyObject_Str
возвращает новую ссылку на строковый объект Python со строковой формой объекта Python, который вы передаете в качестве аргумента - точно так же, как str (o)
в коде Python. Обратите внимание, что объект исключения не имеет «информации, такой как номер строки». - это в объекте traceback (вы можете использовать < code> PyErr_Fetch , чтобы получить как объект исключения, так и объект трассировки). Не знаю, что (если вообще) предоставляет Boost, чтобы упростить использование этих конкретных функций C API, но, в худшем случае, вы всегда можете прибегнуть к этим функциям, так как они предлагаются в самом C API.