fix pybind11 implementation for error_already_set

This commit is contained in:
Kevin Eady 2025-01-06 20:13:19 +01:00
parent a2c0bddf79
commit bd47fd6d39
No known key found for this signature in database
5 changed files with 36 additions and 2 deletions

View File

@ -28,7 +28,7 @@ int main() {
py::exec(script); py::exec(script);
std::cout << "Numpy script executed successfully." << std::endl; 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 // Catch and print Python exceptions
std::cerr << "Python error: " << e.what() << std::endl; std::cerr << "Python error: " << e.what() << std::endl;
return 1; return 1;

View File

@ -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 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 <typename T> template <typename T>
constexpr inline bool is_pyobject_v = constexpr inline bool is_pyobject_v =
std::is_base_of_v<object, std::decay_t<T>> || std::is_same_v<type, T>; std::is_base_of_v<object, std::decay_t<T>> || std::is_same_v<type, T>;

View File

@ -25,7 +25,12 @@ private:
object m_exception; 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 <auto Fn, typename... Args> template <auto Fn, typename... Args>
inline auto raise_call(Args&&... args) { inline auto raise_call(Args&&... args) {

View File

@ -568,6 +568,8 @@ private:
py_exception(tp_ValueError, e.what()); py_exception(tp_ValueError, e.what());
} catch(type_error& e) { py_exception(tp_TypeError, e.what()); } catch(import_error& e) { } catch(type_error& e) { py_exception(tp_TypeError, e.what()); } catch(import_error& e) {
py_exception(tp_ImportError, e.what()); py_exception(tp_ImportError, e.what());
} catch(error_already_set&) {
// exception already set, do nothing
} catch(attribute_error& e) { } catch(attribute_error& e) {
py_exception(tp_AttributeError, e.what()); py_exception(tp_AttributeError, e.what());
} catch(std::exception& e) { py_exception(tp_RuntimeError, e.what()); } } catch(std::exception& e) { py_exception(tp_RuntimeError, e.what()); }

View File

@ -40,6 +40,31 @@ TEST_F(PYBIND11_TEST, exception_cpp_to_python) {
throw py::stop_iteration(); throw py::stop_iteration();
}); });
py::exec("try:\n test_stop_iteration()\nexcept StopIteration as e:\n pass"); 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); TEST_EXCEPTION(index_error, IndexError);
// FIXME: TEST_EXCEPTION(key_error, KeyError); // FIXME: TEST_EXCEPTION(key_error, KeyError);
TEST_EXCEPTION(value_error, ValueError); TEST_EXCEPTION(value_error, ValueError);