From b48bc720e073588b28eb433e09daf72935f1b475 Mon Sep 17 00:00:00 2001 From: Sergei Lebedev Date: Thu, 29 Aug 2019 14:33:18 +0100 Subject: [PATCH] Cosmit following @YannickJadoul's comments Note that detail::error_string() no longer calls PyException_SetTraceback as it is unncessary for pretty-printing the exception. --- include/pybind11/cast.h | 34 +++++++++++++--------------------- include/pybind11/pytypes.h | 15 +++++++-------- 2 files changed, 20 insertions(+), 29 deletions(-) diff --git a/include/pybind11/cast.h b/include/pybind11/cast.h index 8bcf81761..8ff1871e7 100644 --- a/include/pybind11/cast.h +++ b/include/pybind11/cast.h @@ -403,40 +403,31 @@ PYBIND11_NOINLINE inline bool isinstance_generic(handle obj, const std::type_inf return isinstance(obj, type); } -PYBIND11_NOINLINE inline std::string error_string(PyObject* type, PyObject* value, PyObject *trace) { - if (!type && !value && !trace) { +PYBIND11_NOINLINE inline std::string error_string(PyObject *type, PyObject *value, PyObject *trace) { + if (!type) { PyErr_SetString(PyExc_RuntimeError, "Unknown internal error occurred"); return "Unknown internal error occurred"; } - // TODO(superbobry): is it safe to assume that exception has been - // normalized by the caller? - std::string errorString; - if (type) { - errorString += handle(type).attr("__name__").cast(); - errorString += ": "; - } - if (value) - errorString += str(value).cast(); + std::string result = handle(type).attr("__name__").cast(); + result += ": "; -#if PY_MAJOR_VERSION >= 3 - if (trace) - PyException_SetTraceback(value, trace); -#endif + if (value) + result += str(value).cast(); #if !defined(PYPY_VERSION) if (trace) { PyTracebackObject *tb = (PyTracebackObject *) trace; - /* Get the deepest trace possible */ + // Get the deepest trace possible. while (tb->tb_next) tb = tb->tb_next; PyFrameObject *frame = tb->tb_frame; - errorString += "\n\nAt:\n"; + result += "\n\nAt:\n"; while (frame) { int lineno = PyFrame_GetLineNumber(frame); - errorString += + result += " " + handle(frame->f_code->co_filename).cast() + "(" + std::to_string(lineno) + "): " + handle(frame->f_code->co_name).cast() + "\n"; @@ -445,12 +436,13 @@ PYBIND11_NOINLINE inline std::string error_string(PyObject* type, PyObject* valu } #endif - return errorString; + return result; } PYBIND11_NOINLINE inline std::string error_string() { - error_scope scope; // Preserve error state - PyErr_NormalizeException(&scope.type, &scope.value, &scope.trace); + error_scope scope; // Preserve error state. + if (scope.type) + PyErr_NormalizeException(&scope.type, &scope.value, &scope.trace); return error_string(scope.type, scope.value, scope.trace); } diff --git a/include/pybind11/pytypes.h b/include/pybind11/pytypes.h index 87ddf4838..2945d9133 100644 --- a/include/pybind11/pytypes.h +++ b/include/pybind11/pytypes.h @@ -333,17 +333,16 @@ public: inline ~error_already_set(); - virtual const char* what() const noexcept { - try { - if (m_lazy_what.empty()) { - if (m_type || m_value || m_trace) + virtual const char* what() const noexcept override { + if (m_lazy_what.empty()) { + try { 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()); + } 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 @@ -351,7 +350,7 @@ public: /// error variables (but the `.what()` string is still available). void restore() { 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()); }