diff --git a/include/pybind11/internal/error.h b/include/pybind11/internal/error.h index a5fc6b9d..1db80454 100644 --- a/include/pybind11/internal/error.h +++ b/include/pybind11/internal/error.h @@ -53,7 +53,17 @@ inline auto raise_call(Args&&... args) { throw python_error(what, std::move(e)); } -class stop_iteration {}; +class stop_iteration { +public: + stop_iteration() = default; + + stop_iteration(object value) : m_value(std::move(value)) {} + + object value() const { return m_value; } + +private: + object m_value; +}; class cast_error : public std::runtime_error { using std::runtime_error::runtime_error; diff --git a/include/pybind11/internal/function.h b/include/pybind11/internal/function.h index b9e16684..653b2dad 100644 --- a/include/pybind11/internal/function.h +++ b/include/pybind11/internal/function.h @@ -562,7 +562,14 @@ private: py_exception(tp_IndexError, e.what()); } catch(std::range_error& e) { py_exception(tp_ValueError, e.what()); - } catch(stop_iteration&) { StopIteration(); } catch(index_error& e) { + } catch(stop_iteration& e) { + if(auto value_ptr = e.value().ptr()) { + bool ok = py_tpcall(tp_StopIteration, 1, value_ptr); + if(ok) { py_raise(py_retval()); } + } else { + StopIteration(); + } + } catch(index_error& e) { py_exception(tp_IndexError, e.what()); } catch(key_error& e) { py_exception(tp_KeyError, e.what()); } catch(value_error& e) { py_exception(tp_ValueError, e.what()); diff --git a/include/pybind11/tests/error.cpp b/include/pybind11/tests/error.cpp index b11cad28..8f945b23 100644 --- a/include/pybind11/tests/error.cpp +++ b/include/pybind11/tests/error.cpp @@ -41,6 +41,12 @@ TEST_F(PYBIND11_TEST, exception_cpp_to_python) { }); py::exec("try:\n test_stop_iteration()\nexcept StopIteration as e:\n pass"); + m.def("test_stop_iteration_value", []() { + throw py::stop_iteration(py::int_(42)); + }); + py::exec( + "try:\n test_stop_iteration_value()\nexcept StopIteration as e:\n assert e.value == 42"); + m.def("test_error_already_set", []() { KeyError(none().ptr()); throw py::error_already_set();