diff --git a/include/pybind11/cast.h b/include/pybind11/cast.h index fae8d89cf..638e4245f 100644 --- a/include/pybind11/cast.h +++ b/include/pybind11/cast.h @@ -111,18 +111,16 @@ PYBIND11_NOINLINE inline std::string error_string() { return "Unknown internal error occurred"; } - PyObject *type, *value, *traceback; - PyErr_Fetch(&type, &value, &traceback); + error_scope scope; // Preserve error state std::string errorString; - if (type) { - errorString += handle(type).attr("__name__").cast(); + if (scope.type) { + errorString += handle(scope.type).attr("__name__").cast(); errorString += ": "; } - if (value) - errorString += (std::string) handle(value).str(); + if (scope.value) + errorString += (std::string) handle(scope.value).str(); - PyErr_Restore(type, value, traceback); return errorString; } diff --git a/include/pybind11/common.h b/include/pybind11/common.h index 255cc79a3..ef92daff7 100644 --- a/include/pybind11/common.h +++ b/include/pybind11/common.h @@ -420,6 +420,13 @@ template struct format_descriptor constexpr const char format_descriptor< T, typename std::enable_if::value>::type>::value[2]; +/// RAII wrapper that temporarily clears any Python error state +struct error_scope { + PyObject *type, *value, *trace; + error_scope() { PyErr_Fetch(&type, &value, &trace); } + ~error_scope() { PyErr_Restore(type, value, trace); } +}; + PYBIND11_DECL_FMT(float, "f"); PYBIND11_DECL_FMT(double, "d"); PYBIND11_DECL_FMT(bool, "?"); diff --git a/include/pybind11/pybind11.h b/include/pybind11/pybind11.h index d3be7e214..4a50b3353 100644 --- a/include/pybind11/pybind11.h +++ b/include/pybind11/pybind11.h @@ -1309,6 +1309,7 @@ NAMESPACE_END(detail) template void print(Args &&...args) { + error_scope scope; // Preserve error state auto c = detail::collect_arguments(std::forward(args)...); detail::print(c.args(), c.kwargs()); }