From bd47fd6d39a61b4517c34a959fbe81bea0c2f17c Mon Sep 17 00:00:00 2001 From: Kevin Eady <8634912+KevinEady@users.noreply.github.com> Date: Mon, 6 Jan 2025 20:13:19 +0100 Subject: [PATCH] fix pybind11 implementation for error_already_set --- 3rd/numpy/tests/test_numpy.cpp | 2 +- include/pybind11/internal/builtins.h | 2 ++ include/pybind11/internal/error.h | 7 ++++++- include/pybind11/internal/function.h | 2 ++ include/pybind11/tests/error.cpp | 25 +++++++++++++++++++++++++ 5 files changed, 36 insertions(+), 2 deletions(-) diff --git a/3rd/numpy/tests/test_numpy.cpp b/3rd/numpy/tests/test_numpy.cpp index dc75f300..a082c0e3 100644 --- a/3rd/numpy/tests/test_numpy.cpp +++ b/3rd/numpy/tests/test_numpy.cpp @@ -28,7 +28,7 @@ int main() { py::exec(script); std::cout << "Numpy script executed successfully." << std::endl; } - catch (const py::error_already_set& e) { + catch (const py::python_error& e) { // Catch and print Python exceptions std::cerr << "Python error: " << e.what() << std::endl; return 1; diff --git a/include/pybind11/internal/builtins.h b/include/pybind11/internal/builtins.h index 52f65218..1e842bc4 100644 --- a/include/pybind11/internal/builtins.h +++ b/include/pybind11/internal/builtins.h @@ -76,6 +76,8 @@ inline bool isinstance(handle obj, type type) { return py_isinstance(obj.ptr(), inline bool python_error::match(type type) const { return isinstance(m_exception.ptr(), type); } +inline bool error_already_set::match(type type) const { return py_matchexc(type.index()); } + template constexpr inline bool is_pyobject_v = std::is_base_of_v> || std::is_same_v; diff --git a/include/pybind11/internal/error.h b/include/pybind11/internal/error.h index fbacb453..a5fc6b9d 100644 --- a/include/pybind11/internal/error.h +++ b/include/pybind11/internal/error.h @@ -25,7 +25,12 @@ private: object m_exception; }; -using error_already_set = python_error; +class error_already_set : public std::exception { +public: + bool match(py_Type type) const { return py_matchexc(type); } + + bool match(type type) const; +}; template inline auto raise_call(Args&&... args) { diff --git a/include/pybind11/internal/function.h b/include/pybind11/internal/function.h index 3138fec0..b9e16684 100644 --- a/include/pybind11/internal/function.h +++ b/include/pybind11/internal/function.h @@ -568,6 +568,8 @@ private: py_exception(tp_ValueError, e.what()); } catch(type_error& e) { py_exception(tp_TypeError, e.what()); } catch(import_error& e) { py_exception(tp_ImportError, e.what()); + } catch(error_already_set&) { + // exception already set, do nothing } catch(attribute_error& e) { py_exception(tp_AttributeError, e.what()); } catch(std::exception& e) { py_exception(tp_RuntimeError, e.what()); } diff --git a/include/pybind11/tests/error.cpp b/include/pybind11/tests/error.cpp index 12ea3ee9..b11cad28 100644 --- a/include/pybind11/tests/error.cpp +++ b/include/pybind11/tests/error.cpp @@ -40,6 +40,31 @@ TEST_F(PYBIND11_TEST, exception_cpp_to_python) { throw py::stop_iteration(); }); py::exec("try:\n test_stop_iteration()\nexcept StopIteration as e:\n pass"); + + m.def("test_error_already_set", []() { + KeyError(none().ptr()); + throw py::error_already_set(); + }); + py::exec("try:\n test_error_already_set()\nexcept KeyError as e:\n pass"); + + m.def("test_error_already_set_matches", []() { + try { + KeyError(none().ptr()); + throw py::error_already_set(); + } catch(py::error_already_set& e) { + if(e.match(tp_KeyError)) { return; } + std::rethrow_exception(std::current_exception()); + } + + try { + StopIteration(); + throw py::error_already_set(); + } catch(py::error_already_set& e) { + if(e.match(type(tp_StopIteration))) { return; } + std::rethrow_exception(std::current_exception()); + } + }); + py::exec("test_error_already_set_matches()"); TEST_EXCEPTION(index_error, IndexError); // FIXME: TEST_EXCEPTION(key_error, KeyError); TEST_EXCEPTION(value_error, ValueError);