diff --git a/include/pybind11/cast.h b/include/pybind11/cast.h index 019c9340..438f7cf8 100644 --- a/include/pybind11/cast.h +++ b/include/pybind11/cast.h @@ -106,12 +106,17 @@ PYBIND11_NOINLINE inline handle get_type_handle(const std::type_info &tp) { } PYBIND11_NOINLINE inline std::string error_string() { - PyObject *type, *value, *traceback; - PyErr_Fetch(&type, &value, &traceback); + if (!PyErr_Occurred()) { + PyErr_SetString(PyExc_RuntimeError, "Unknown internal error occurred"); + return "Unknown internal error occurred"; + } - std::string errorString; + PyObject *type, *value, *traceback; + PyErr_Fetch(&type, &value, &traceback); + + std::string errorString; if (type) { - errorString += (std::string) handle(type).str(); + errorString += handle(type).attr("__name__").cast(); errorString += ": "; } if (value) diff --git a/tests/test_exceptions.cpp b/tests/test_exceptions.cpp index 534f23bf..67133a63 100644 --- a/tests/test_exceptions.cpp +++ b/tests/test_exceptions.cpp @@ -104,5 +104,23 @@ test_initializer custom_exceptions([](py::module &m) { m.def("throws3", &throws3); m.def("throws4", &throws4); m.def("throws_logic_error", &throws_logic_error); -}); + m.def("throw_already_set", [](bool err) { + if (err) + PyErr_SetString(PyExc_ValueError, "foo"); + try { + throw py::error_already_set(); + } catch (const std::runtime_error& e) { + if ((err && e.what() != std::string("ValueError: foo")) || + (!err && e.what() != std::string("Unknown internal error occurred"))) + { + PyErr_Clear(); + throw std::runtime_error("error message mismatch"); + } + } + PyErr_Clear(); + if (err) + PyErr_SetString(PyExc_ValueError, "foo"); + throw py::error_already_set(); + }); +}); diff --git a/tests/test_exceptions.py b/tests/test_exceptions.py index 24f9769b..a92300c3 100644 --- a/tests/test_exceptions.py +++ b/tests/test_exceptions.py @@ -1,6 +1,18 @@ import pytest +def test_error_already_set(msg): + from pybind11_tests import throw_already_set + + with pytest.raises(RuntimeError) as excinfo: + throw_already_set(False) + assert msg(excinfo.value) == "Unknown internal error occurred" + + with pytest.raises(ValueError) as excinfo: + throw_already_set(True) + assert msg(excinfo.value) == "foo" + + def test_custom(msg): from pybind11_tests import (MyException, throws1, throws2, throws3, throws4, throws_logic_error)