diff --git a/include/pybind11/cast.h b/include/pybind11/cast.h index 5783c1a60..080b2e092 100644 --- a/include/pybind11/cast.h +++ b/include/pybind11/cast.h @@ -106,10 +106,15 @@ 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 += handle(type).attr("__name__").cast(); errorString += ": "; diff --git a/tests/test_exceptions.cpp b/tests/test_exceptions.cpp index 534f23bf8..67133a637 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 24f9769b4..a92300c32 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)