add pybind11 implementation for stop_iteration with value

This commit is contained in:
Kevin Eady 2025-01-12 13:53:05 +01:00
parent bd47fd6d39
commit 30f04b4753
No known key found for this signature in database
3 changed files with 25 additions and 2 deletions

View File

@ -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;

View File

@ -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());

View File

@ -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();