From 1f675dcaa75d3457b86f0a83a1981ec12c3b3e42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Niederb=C3=BChl?= Date: Fri, 10 Jan 2020 23:27:10 +0100 Subject: [PATCH] Clear error indicator when the exception is handled on the Rust side Leaving Python's global exception state is misleading, e.g. subsequent calls of `py.eval` will fail. --- CHANGELOG.md | 4 ++++ src/types/iterator.rs | 1 + src/types/set.rs | 10 +++++++++- tests/test_various.rs | 3 +++ 4 files changed, 17 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e0b3814e..4ef6eff3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. * Implemented `IntoIterator` for `PySet` and `PyFrozenSet`. [#716](https://github.com/PyO3/pyo3/pull/716) +### Fixed + +* Clear error indicator when the exception is handled on the Rust side. [#719](https://github.com/PyO3/pyo3/pull/719) + ## [0.8.5] * Support for `#[name = "foo"]` attribute for `#[pyfunction]` and in `#[pymethods]`. [#692](https://github.com/PyO3/pyo3/pull/692) diff --git a/src/types/iterator.rs b/src/types/iterator.rs index 0d7ab4ab..52378caa 100644 --- a/src/types/iterator.rs +++ b/src/types/iterator.rs @@ -42,6 +42,7 @@ impl<'p> PyIterator<'p> { let ptr = ffi::PyObject_GetIter(obj.as_ptr()); // Returns NULL if an object cannot be iterated. if ptr.is_null() { + PyErr::fetch(py); return Err(PyDowncastError); } diff --git a/src/types/set.rs b/src/types/set.rs index 23c43f0b..f565af6f 100644 --- a/src/types/set.rs +++ b/src/types/set.rs @@ -93,7 +93,12 @@ impl PySet { /// Remove and return an arbitrary element from the set pub fn pop(&self) -> Option { - unsafe { PyObject::from_owned_ptr_or_opt(self.py(), ffi::PySet_Pop(self.as_ptr())) } + let element = + unsafe { PyObject::from_owned_ptr_or_err(self.py(), ffi::PySet_Pop(self.as_ptr())) }; + match element { + Ok(e) => Some(e), + Err(_) => None, + } } /// Returns an iterator of values in this set. @@ -324,6 +329,9 @@ mod test { assert!(val.is_some()); let val2 = set.pop(); assert!(val2.is_none()); + assert!(py + .eval("print('Exception state should not be set.')", None, None) + .is_ok()); } #[test] diff --git a/tests/test_various.rs b/tests/test_various.rs index 655101db..563166bd 100644 --- a/tests/test_various.rs +++ b/tests/test_various.rs @@ -179,4 +179,7 @@ fn incorrect_iter() { let int_ref = int.as_ref(py); // Should not segfault. assert!(int_ref.iter().is_err()); + assert!(py + .eval("print('Exception state should not be set.')", None, None) + .is_ok()); }