Skip to content

Commit 83a8a97

Browse files
Roman Miroshnychenkodean0x7d
Roman Miroshnychenko
authored andcommitted
Add a method to check Python exception types (#772)
This commit adds `error_already_set::matches()` convenience method to check if the exception trapped by `error_already_set` matches a given Python exception type. This will address #700 by providing a less verbose way to check exceptions.
1 parent 37ef74c commit 83a8a97

File tree

3 files changed

+23
-0
lines changed

3 files changed

+23
-0
lines changed

include/pybind11/common.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -597,6 +597,9 @@ class error_already_set : public std::runtime_error {
597597
/// Clear the held Python error state (the C++ `what()` message remains intact)
598598
void clear() { restore(); PyErr_Clear(); }
599599

600+
/// Check if the trapped exception matches a given Python exception class
601+
bool matches(PyObject *ex) const { return PyErr_GivenExceptionMatches(ex, type); }
602+
600603
private:
601604
PyObject *type, *value, *trace;
602605
};

tests/test_exceptions.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,20 @@ void throws_logic_error() {
8686
throw std::logic_error("this error should fall through to the standard handler");
8787
}
8888

89+
// Test error_already_set::matches() method
90+
void exception_matches() {
91+
py::dict foo;
92+
try {
93+
foo["bar"];
94+
}
95+
catch (py::error_already_set& ex) {
96+
if (ex.matches(PyExc_KeyError))
97+
ex.clear();
98+
else
99+
throw;
100+
}
101+
}
102+
89103
struct PythonCallInDestructor {
90104
PythonCallInDestructor(const py::dict &d) : d(d) {}
91105
~PythonCallInDestructor() { d["good"] = true; }
@@ -140,6 +154,7 @@ test_initializer custom_exceptions([](py::module &m) {
140154
m.def("throws5", &throws5);
141155
m.def("throws5_1", &throws5_1);
142156
m.def("throws_logic_error", &throws_logic_error);
157+
m.def("exception_matches", &exception_matches);
143158

144159
m.def("throw_already_set", [](bool err) {
145160
if (err)

tests/test_exceptions.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,11 @@ def test_python_call_in_catch():
2121
assert d["good"] is True
2222

2323

24+
def test_exception_matches():
25+
from pybind11_tests import exception_matches
26+
exception_matches()
27+
28+
2429
def test_custom(msg):
2530
from pybind11_tests import (MyException, MyException5, MyException5_1,
2631
throws1, throws2, throws3, throws4, throws5, throws5_1,

0 commit comments

Comments
 (0)