Cosmit following @YannickJadoul's comments

Note that detail::error_string() no longer calls PyException_SetTraceback
as it is unncessary for pretty-printing the exception.
This commit is contained in:
Sergei Lebedev 2019-08-29 14:33:18 +01:00
parent c935b73ba5
commit b48bc720e0
2 changed files with 20 additions and 29 deletions

View File

@ -403,40 +403,31 @@ PYBIND11_NOINLINE inline bool isinstance_generic(handle obj, const std::type_inf
return isinstance(obj, type); return isinstance(obj, type);
} }
PYBIND11_NOINLINE inline std::string error_string(PyObject* type, PyObject* value, PyObject *trace) { PYBIND11_NOINLINE inline std::string error_string(PyObject *type, PyObject *value, PyObject *trace) {
if (!type && !value && !trace) { if (!type) {
PyErr_SetString(PyExc_RuntimeError, "Unknown internal error occurred"); PyErr_SetString(PyExc_RuntimeError, "Unknown internal error occurred");
return "Unknown internal error occurred"; return "Unknown internal error occurred";
} }
// TODO(superbobry): is it safe to assume that exception has been std::string result = handle(type).attr("__name__").cast<std::string>();
// normalized by the caller? result += ": ";
std::string errorString;
if (type) {
errorString += handle(type).attr("__name__").cast<std::string>();
errorString += ": ";
}
if (value)
errorString += str(value).cast<std::string>();
#if PY_MAJOR_VERSION >= 3 if (value)
if (trace) result += str(value).cast<std::string>();
PyException_SetTraceback(value, trace);
#endif
#if !defined(PYPY_VERSION) #if !defined(PYPY_VERSION)
if (trace) { if (trace) {
PyTracebackObject *tb = (PyTracebackObject *) trace; PyTracebackObject *tb = (PyTracebackObject *) trace;
/* Get the deepest trace possible */ // Get the deepest trace possible.
while (tb->tb_next) while (tb->tb_next)
tb = tb->tb_next; tb = tb->tb_next;
PyFrameObject *frame = tb->tb_frame; PyFrameObject *frame = tb->tb_frame;
errorString += "\n\nAt:\n"; result += "\n\nAt:\n";
while (frame) { while (frame) {
int lineno = PyFrame_GetLineNumber(frame); int lineno = PyFrame_GetLineNumber(frame);
errorString += result +=
" " + handle(frame->f_code->co_filename).cast<std::string>() + " " + handle(frame->f_code->co_filename).cast<std::string>() +
"(" + std::to_string(lineno) + "): " + "(" + std::to_string(lineno) + "): " +
handle(frame->f_code->co_name).cast<std::string>() + "\n"; handle(frame->f_code->co_name).cast<std::string>() + "\n";
@ -445,12 +436,13 @@ PYBIND11_NOINLINE inline std::string error_string(PyObject* type, PyObject* valu
} }
#endif #endif
return errorString; return result;
} }
PYBIND11_NOINLINE inline std::string error_string() { PYBIND11_NOINLINE inline std::string error_string() {
error_scope scope; // Preserve error state error_scope scope; // Preserve error state.
PyErr_NormalizeException(&scope.type, &scope.value, &scope.trace); if (scope.type)
PyErr_NormalizeException(&scope.type, &scope.value, &scope.trace);
return error_string(scope.type, scope.value, scope.trace); return error_string(scope.type, scope.value, scope.trace);
} }

View File

@ -333,17 +333,16 @@ public:
inline ~error_already_set(); inline ~error_already_set();
virtual const char* what() const noexcept { virtual const char* what() const noexcept override {
try { if (m_lazy_what.empty()) {
if (m_lazy_what.empty()) { try {
if (m_type || m_value || m_trace)
PyErr_NormalizeException(&m_type.ptr(), &m_value.ptr(), &m_trace.ptr()); PyErr_NormalizeException(&m_type.ptr(), &m_value.ptr(), &m_trace.ptr());
m_lazy_what = detail::error_string(m_type.ptr(), m_value.ptr(), m_trace.ptr()); m_lazy_what = detail::error_string(m_type.ptr(), m_value.ptr(), m_trace.ptr());
} catch (...) {
return "Unknown internal error occurred";
} }
return m_lazy_what.c_str();
} catch (...) {
return "Unknown internal error occurred";
} }
return m_lazy_what.c_str();
} }
/// Give the currently-held error back to Python, if any. If there is currently a Python error /// Give the currently-held error back to Python, if any. If there is currently a Python error
@ -351,7 +350,7 @@ public:
/// error variables (but the `.what()` string is still available). /// error variables (but the `.what()` string is still available).
void restore() { void restore() {
what(); // Force-build `.what()`. what(); // Force-build `.what()`.
if (m_type || m_value || m_trace) if (m_type)
PyErr_Restore(m_type.release().ptr(), m_value.release().ptr(), m_trace.release().ptr()); PyErr_Restore(m_type.release().ptr(), m_value.release().ptr(), m_trace.release().ptr());
} }