python 如何获取Python异常文本
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1418015/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to get Python exception text
提问by Anton Kiselev
I want to embed python in my C++ application. I'm using Boost library - great tool. But i have one problem.
我想在我的 C++ 应用程序中嵌入 python。我正在使用 Boost 库 - 很棒的工具。但我有一个问题。
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.
如果 python 函数抛出异常,我想捕获它并在我的应用程序中打印错误或获取一些详细信息,例如导致错误的 python 脚本中的行号。
How can i do it? I can't find any functions to get detailed exception information in Python API or Boost.
我该怎么做?我在 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() just prints error text to stderr and clears error so it can't be solution
PyErr_Print() 只是将错误文本打印到 stderr 并清除错误,因此无法解决
回答by Anton Kiselev
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
和 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
回答by mah
This is the most robust method I've been able to come up so far:
这是迄今为止我能想到的最强大的方法:
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);
}
回答by Alex Martelli
In the Python C API, PyObject_Str
returns a new reference to a Python string object with the string form of the Python object you're passing as the argument -- just like str(o)
in Python code. Note that the exception object does not have "information like line number" -- that's in the tracebackobject (you can use PyErr_Fetch
to get both the exception object and the traceback object). Don't know what (if anything) Boost provides to make these specific C API functions easier to use, but, worst case, you could always resort to these functions as they are offered in the C API itself.
在 Python C API 中,PyObject_Str
以您作为参数传递的 Python 对象的字符串形式返回对 Python 字符串对象的新引用——就像str(o)
在 Python 代码中一样。请注意,异常对象没有“行号之类的信息”——这在回溯对象中(您可以使用它PyErr_Fetch
来获取异常对象和回溯对象)。不知道 Boost 提供了什么(如果有的话)来使这些特定的 C API 函数更易于使用,但是,在最坏的情况下,您总是可以使用 C API 本身提供的这些函数。
回答by James
This thread has been very useful for me, but I had problems with the Python C API when I tried to extract the error message itself with no traceback. I found plenty of ways to do that in Python, but I couldn't find any way to do this in C++. I finally came up with the following version, which uses the C API as little as possible and instead relies much more on boost python.
这个线程对我非常有用,但是当我尝试在没有回溯的情况下提取错误消息本身时,我遇到了 Python C API 的问题。我在 Python 中找到了很多方法来做到这一点,但在 C++ 中我找不到任何方法来做到这一点。我终于想出了以下版本,它尽可能少地使用 C API,而是更多地依赖于 boost python。
PyErr_Print();
using namespace boost::python;
exec("import traceback, sys", mainNamespace_);
auto pyErr = eval("str(sys.last_value)", mainNamespace_);
auto pyStackTrace = eval("'\n'.join(traceback.format_exception(sys.last_type, sys.last_value, sys.last_traceback))", mainNamespace_);
stackTraceString_ = extract<std::string>(pyStackTrace);
errorSummary_ = extract<std::string>(pyErr);
The reason this works is because PyErr_Print()also sets the value for sys.last_value
, sys.last_type
, and sys.last_traceback
. Those are set to the same values as sys.exc_info
would give, so this is functionally similar to the following python code:
这部作品的原因是因为PyErr_Print()也设定了值sys.last_value
,sys.last_type
和sys.last_traceback
。这些设置为与给出的值相同的值sys.exc_info
,因此这在功能上类似于以下 python 代码:
import traceback
import sys
try:
raise RuntimeError("This is a test")
except:
err_type = sys.exc_info()[0]
value = sys.exc_info()[1]
tb = sys.exc_info()[2]
stack_trace = "\n".join(traceback.format_exception(err_type, value, tb))
error_summary = str(value)
print(stack_trace)
print(error_summary)
I hope someone finds this useful!
我希望有人觉得这很有用!