Add and document py::error_already_set::discard_as_unraisable()

To deal with exceptions that hit destructors or other noexcept functions.

Includes fixes to support Python 2.7 and extends documentation on
error handling.

@virtuald and @YannickJadoul both contributed to this PR.
This commit is contained in:
James R. Barlow
2020-08-08 03:07:14 -07:00
committed by Ralf W. Grosse-Kunstleve
parent a876aac2cf
commit 3618bea2aa
5 changed files with 154 additions and 3 deletions

View File

@@ -65,6 +65,25 @@ struct PythonCallInDestructor {
py::dict d;
};
struct PythonAlreadySetInDestructor {
PythonAlreadySetInDestructor(const py::str &s) : s(s) {}
~PythonAlreadySetInDestructor() {
py::dict foo;
try {
// Assign to a py::object to force read access of nonexistent dict entry
py::object o = foo["bar"];
}
catch (py::error_already_set& ex) {
ex.discard_as_unraisable(s);
}
}
py::str s;
};
TEST_SUBMODULE(exceptions, m) {
m.def("throw_std_exception", []() {
throw std::runtime_error("This exception was intentionally thrown.");
@@ -183,6 +202,11 @@ TEST_SUBMODULE(exceptions, m) {
return false;
});
m.def("python_alreadyset_in_destructor", [](py::str s) {
PythonAlreadySetInDestructor alreadyset_in_destructor(s);
return true;
});
// test_nested_throws
m.def("try_catch", [m](py::object exc_type, py::function f, py::args args) {
try { f(*args); }