From 392f16ccb8a96b4cc6eb74465fdbe61ea0e00041 Mon Sep 17 00:00:00 2001 From: Ivan Smirnov Date: Sun, 28 Aug 2016 21:25:25 +0100 Subject: [PATCH 1/2] Properly format type name in error_already_set() --- include/pybind11/cast.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/pybind11/cast.h b/include/pybind11/cast.h index b4698d81..5783c1a6 100644 --- a/include/pybind11/cast.h +++ b/include/pybind11/cast.h @@ -111,7 +111,7 @@ PYBIND11_NOINLINE inline std::string error_string() { std::string errorString; if (type) { - errorString += (std::string) handle(type).str(); + errorString += handle(type).attr("__name__").cast(); errorString += ": "; } if (value) From 67b54894b2e590279493270af7e859e3d0107e93 Mon Sep 17 00:00:00 2001 From: Ivan Smirnov Date: Wed, 7 Sep 2016 21:10:16 +0100 Subject: [PATCH 2/2] Set error if it's not set in error_already_set() --- include/pybind11/cast.h | 11 ++++++++--- tests/test_exceptions.cpp | 20 +++++++++++++++++++- tests/test_exceptions.py | 12 ++++++++++++ 3 files changed, 39 insertions(+), 4 deletions(-) diff --git a/include/pybind11/cast.h b/include/pybind11/cast.h index 5783c1a6..080b2e09 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 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)