Преглед на файлове

fix pybind11 implementation for error_already_set

Kevin Eady преди 1 година
родител
ревизия
bd47fd6d39

+ 1 - 1
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;

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

+ 6 - 1
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 <auto Fn, typename... Args>
 inline auto raise_call(Args&&... args) {

+ 2 - 0
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()); }

+ 25 - 0
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);