diff --git a/CHANGELOG.md b/CHANGELOG.md index a78ee55b99d..7248fb77989 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,10 +28,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Add `abi3-py310` feature. [#1889](https://github.com/PyO3/pyo3/pull/1889) - Add `PyCFunction::new_closure` to create a Python function from a Rust closure. [#1901](https://github.com/PyO3/pyo3/pull/1901) - Add support for positional-only arguments in `#[pyfunction]` [#1925](https://github.com/PyO3/pyo3/pull/1925) +- Add `PyErr::take` to attempt to fetch a Python exception if present. [#1957](https://github.com/PyO3/pyo3/pull/1957) ### Changed -- Change `PyErr::fetch` to return `Option`. [#1717](https://github.com/PyO3/pyo3/pull/1717) - `PyList`, `PyTuple` and `PySequence`'s APIs now accepts only `usize` indices instead of `isize`. [#1733](https://github.com/PyO3/pyo3/pull/1733), [#1802](https://github.com/PyO3/pyo3/pull/1802), [#1803](https://github.com/PyO3/pyo3/pull/1803) @@ -48,6 +48,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Remove function PyTuple_ClearFreeList from python 3.9 above. [#1887](https://github.com/PyO3/pyo3/pull/1887) - Deprecate `#[call]` attribute in favor of using `fn __call__`. [#1929](https://github.com/PyO3/pyo3/pull/1929) - Fix missing FFI definition `_PyImport_FindExtensionObject` on Python 3.10. [#1942](https://github.com/PyO3/pyo3/pull/1942) +- Change `PyErr::fetch` to panic in debug mode if no exception is present. [#1957](https://github.com/PyO3/pyo3/pull/1957) ### Fixed diff --git a/src/conversion.rs b/src/conversion.rs index c7dead3d43f..e1238edc80e 100644 --- a/src/conversion.rs +++ b/src/conversion.rs @@ -494,7 +494,7 @@ pub unsafe trait FromPyPointer<'p>: Sized { /// /// Relies on [`from_owned_ptr_or_opt`](#method.from_owned_ptr_or_opt). unsafe fn from_owned_ptr_or_err(py: Python<'p>, ptr: *mut ffi::PyObject) -> PyResult<&'p Self> { - Self::from_owned_ptr_or_opt(py, ptr).ok_or_else(|| err::PyErr::api_call_failed(py)) + Self::from_owned_ptr_or_opt(py, ptr).ok_or_else(|| err::PyErr::fetch(py)) } /// Convert from an arbitrary borrowed `PyObject`. /// @@ -528,7 +528,7 @@ pub unsafe trait FromPyPointer<'p>: Sized { py: Python<'p>, ptr: *mut ffi::PyObject, ) -> PyResult<&'p Self> { - Self::from_borrowed_ptr_or_opt(py, ptr).ok_or_else(|| err::PyErr::api_call_failed(py)) + Self::from_borrowed_ptr_or_opt(py, ptr).ok_or_else(|| err::PyErr::fetch(py)) } } diff --git a/src/conversions/num_bigint.rs b/src/conversions/num_bigint.rs index d5932b6b2bb..197f7ec375b 100644 --- a/src/conversions/num_bigint.rs +++ b/src/conversions/num_bigint.rs @@ -108,19 +108,16 @@ macro_rules! bigint_conversion { fn extract(ob: &'source PyAny) -> PyResult<$rust_ty> { let py = ob.py(); unsafe { - let num = ffi::PyNumber_Index(ob.as_ptr()); - if num.is_null() { - return Err(PyErr::api_call_failed(py)); - } - let n_bits = ffi::_PyLong_NumBits(num); - let n_bytes = if n_bits < 0 { - return Err(PyErr::api_call_failed(py)); + let num: Py = + Py::from_owned_ptr_or_err(py, ffi::PyNumber_Index(ob.as_ptr()))?; + let n_bits = ffi::_PyLong_NumBits(num.as_ptr()); + let n_bytes = if n_bits == -1 { + return Err(PyErr::fetch(py)); } else if n_bits == 0 { 0 } else { (n_bits as usize - 1 + $is_signed) / 8 + 1 }; - let num: Py = Py::from_owned_ptr(py, num); if n_bytes <= 128 { let mut buffer = [0; 128]; extract(num.as_ref(py), &mut buffer[..n_bytes], $is_signed)?; diff --git a/src/conversions/num_complex.rs b/src/conversions/num_complex.rs index d5fd5e15618..41c96aef276 100644 --- a/src/conversions/num_complex.rs +++ b/src/conversions/num_complex.rs @@ -143,19 +143,22 @@ macro_rules! complex_conversion { #[cfg(not(any(Py_LIMITED_API, PyPy)))] unsafe { let val = ffi::PyComplex_AsCComplex(obj.as_ptr()); - if val.real == -1.0 && PyErr::occurred(obj.py()) { - Err(PyErr::api_call_failed(obj.py())) - } else { - Ok(Complex::new(val.real as $float, val.imag as $float)) + if val.real == -1.0 { + if let Some(err) = PyErr::take(obj.py()) { + return Err(err); + } } + Ok(Complex::new(val.real as $float, val.imag as $float)) } #[cfg(any(Py_LIMITED_API, PyPy))] unsafe { let ptr = obj.as_ptr(); let real = ffi::PyComplex_RealAsDouble(ptr); - if real == -1.0 && PyErr::occurred(obj.py()) { - return Err(PyErr::api_call_failed(obj.py())); + if real == -1.0 { + if let Some(err) = PyErr::take(obj.py()) { + return Err(err); + } } let imag = ffi::PyComplex_ImagAsDouble(ptr); Ok(Complex::new(real as $float, imag as $float)) diff --git a/src/conversions/osstr.rs b/src/conversions/osstr.rs index 72cf423f5dc..b6282f373f8 100644 --- a/src/conversions/osstr.rs +++ b/src/conversions/osstr.rs @@ -94,7 +94,7 @@ impl FromPyObject<'_> for OsString { let size = unsafe { ffi::PyUnicode_AsWideChar(pystring.as_ptr(), std::ptr::null_mut(), 0) }; if size == -1 { - return Err(PyErr::api_call_failed(ob.py())); + return Err(PyErr::fetch(ob.py())); } let mut buffer = vec![0; size as usize]; diff --git a/src/err/err_state.rs b/src/err/err_state.rs index 6947446dcf5..b1390dc171a 100644 --- a/src/err/err_state.rs +++ b/src/err/err_state.rs @@ -23,7 +23,7 @@ pub(crate) enum PyErrState { pvalue: Box PyObject + Send + Sync>, }, FfiTuple { - ptype: Option, + ptype: PyObject, pvalue: Option, ptraceback: Option, }, diff --git a/src/err/mod.rs b/src/err/mod.rs index 911bf106421..db8e2571fde 100644 --- a/src/err/mod.rs +++ b/src/err/mod.rs @@ -7,9 +7,7 @@ use crate::{ exceptions::{self, PyBaseException}, ffi, }; -use crate::{ - AsPyPointer, FromPyPointer, IntoPy, Py, PyAny, PyObject, Python, ToBorrowedObject, ToPyObject, -}; +use crate::{AsPyPointer, IntoPy, Py, PyAny, PyObject, Python, ToBorrowedObject, ToPyObject}; use std::borrow::Cow; use std::cell::UnsafeCell; use std::ffi::CString; @@ -137,15 +135,13 @@ impl PyErr { let state = if unsafe { ffi::PyExceptionInstance_Check(ptr) } != 0 { PyErrState::Normalized(PyErrStateNormalized { - ptype: unsafe { - Py::from_borrowed_ptr(obj.py(), ffi::PyExceptionInstance_Class(ptr)) - }, + ptype: obj.get_type().into(), pvalue: unsafe { Py::from_borrowed_ptr(obj.py(), obj.as_ptr()) }, ptraceback: None, }) } else if unsafe { ffi::PyExceptionClass_Check(obj.as_ptr()) } != 0 { PyErrState::FfiTuple { - ptype: unsafe { Some(Py::from_borrowed_ptr(obj.py(), ptr)) }, + ptype: obj.into(), pvalue: None, ptraceback: None, } @@ -218,61 +214,95 @@ impl PyErr { unsafe { !ffi::PyErr_Occurred().is_null() } } - /// Retrieves the current error from the Python interpreter's global state. + /// Takes the current error from the Python interpreter's global state and clears the global + /// state. If no error is set, returns `None`. /// - /// The error is cleared from the Python interpreter. - /// If no error is set, returns a `None`. + /// If the error is a `PanicException` (which would have originated from a panic in a pyo3 + /// callback) then this function will resume the panic. /// - /// If the error fetched is a `PanicException` (which would have originated from a panic in a - /// pyo3 callback) then this function will resume the panic. - pub fn fetch(py: Python) -> Option { - unsafe { + /// Use this function when it is not known if an error should be present. If the error is + /// expected to have been set, for example from [PyErr::occurred] or by an error return value + /// from a C FFI function, use [PyErr::fetch]. + pub fn take(py: Python) -> Option { + let (ptype, pvalue, ptraceback) = unsafe { let mut ptype: *mut ffi::PyObject = std::ptr::null_mut(); let mut pvalue: *mut ffi::PyObject = std::ptr::null_mut(); let mut ptraceback: *mut ffi::PyObject = std::ptr::null_mut(); ffi::PyErr_Fetch(&mut ptype, &mut pvalue, &mut ptraceback); - // If the error indicator is not set, all three variables are set to NULL - if ptype.is_null() && pvalue.is_null() && ptraceback.is_null() { - return None; - } - - let err = PyErr::new_from_ffi_tuple(py, ptype, pvalue, ptraceback); + // Convert to Py immediately so that any references are freed by early return. + let ptype = Py::from_owned_ptr_or_opt(py, ptype); + let pvalue = Py::from_owned_ptr_or_opt(py, pvalue); + let ptraceback = Py::from_owned_ptr_or_opt(py, ptraceback); + + // A valid exception state should always have a non-null ptype, but the other two may be + // null. + let ptype = match ptype { + Some(ptype) => ptype, + None => { + debug_assert!( + pvalue.is_none(), + "Exception type was null but value was not null" + ); + debug_assert!( + ptraceback.is_none(), + "Exception type was null but traceback was not null" + ); + return None; + } + }; + + (ptype, pvalue, ptraceback) + }; - if ptype == PanicException::type_object(py).as_ptr() { - let msg: String = PyAny::from_borrowed_ptr_or_opt(py, pvalue) - .and_then(|obj| obj.extract().ok()) - .unwrap_or_else(|| String::from("Unwrapped panic from Python code")); + if ptype.as_ptr() == PanicException::type_object(py).as_ptr() { + let msg: String = pvalue + .as_ref() + .and_then(|obj| obj.extract(py).ok()) + .unwrap_or_else(|| String::from("Unwrapped panic from Python code")); - eprintln!( - "--- PyO3 is resuming a panic after fetching a PanicException from Python. ---" - ); - eprintln!("Python stack trace below:"); - err.print(py); + eprintln!( + "--- PyO3 is resuming a panic after fetching a PanicException from Python. ---" + ); + eprintln!("Python stack trace below:"); - std::panic::resume_unwind(Box::new(msg)) + unsafe { + use crate::conversion::IntoPyPointer; + ffi::PyErr_Restore(ptype.into_ptr(), pvalue.into_ptr(), ptraceback.into_ptr()); + ffi::PyErr_PrintEx(0); } - Some(err) + std::panic::resume_unwind(Box::new(msg)) } + + Some(PyErr::from_state(PyErrState::FfiTuple { + ptype, + pvalue, + ptraceback, + })) } - /// Retrieves the current error from the Python interpreter's global state. + /// Equivalent to [PyErr::take], but when no error is set: + /// - Panics in debug mode. + /// - Returns a `SystemError` in release mode. /// - /// The error is cleared from the Python interpreter. - /// If no error is set, returns a `SystemError` in release mode, - /// panics in debug mode. - pub(crate) fn api_call_failed(py: Python) -> PyErr { - #[cfg(debug_assertions)] - { - PyErr::fetch(py).expect("error return without exception set") - } - #[cfg(not(debug_assertions))] - { - use crate::exceptions::PySystemError; - - PyErr::fetch(py) - .unwrap_or_else(|| PySystemError::new_err("error return without exception set")) + /// This behavior is consistent with Python's internal handling of what happens when a C return + /// value indicates an error occurred but the global error state is empty. (A lack of exception + /// should be treated as a bug in the code which returned an error code but did not set an + /// exception.) + /// + /// Use this function when the error is expected to have been set, for example from + /// [PyErr::occurred] or by an error return value from a C FFI function. + #[cfg_attr(all(debug_assertions, track_caller), track_caller)] + #[inline] + pub fn fetch(py: Python) -> PyErr { + const FAILED_TO_FETCH: &str = "attempted to fetch exception but none was set"; + match PyErr::take(py) { + Some(err) => err, + #[cfg(debug_assertions)] + None => panic!("{}", FAILED_TO_FETCH), + #[cfg(not(debug_assertions))] + None => exceptions::PySystemError::new_err(FAILED_TO_FETCH), } } @@ -309,27 +339,6 @@ impl PyErr { } } - /// Create a PyErr from an ffi tuple - /// - /// # Safety - /// - `ptype` must be a pointer to valid Python exception type object. - /// - `pvalue` must be a pointer to a valid Python object, or NULL. - /// - `ptraceback` must be a pointer to a valid Python traceback object, or NULL. - unsafe fn new_from_ffi_tuple( - py: Python, - ptype: *mut ffi::PyObject, - pvalue: *mut ffi::PyObject, - ptraceback: *mut ffi::PyObject, - ) -> PyErr { - // Note: must not panic to ensure all owned pointers get acquired correctly, - // and because we mustn't panic in normalize(). - PyErr::from_state(PyErrState::FfiTuple { - ptype: Py::from_owned_ptr_or_opt(py, ptype), - pvalue: Py::from_owned_ptr_or_opt(py, pvalue), - ptraceback: Py::from_owned_ptr_or_opt(py, ptraceback), - }) - } - /// Prints a standard traceback to `sys.stderr`. pub fn print(&self, py: Python) { self.clone_ref(py).restore(py); @@ -579,7 +588,7 @@ pub fn error_on_minusone(py: Python, result: c_int) -> PyResult<()> { if result != -1 { Ok(()) } else { - Err(PyErr::api_call_failed(py)) + Err(PyErr::fetch(py)) } } @@ -596,9 +605,7 @@ mod tests { #[test] fn no_error() { - Python::with_gil(|py| { - assert!(PyErr::fetch(py).is_none()); - }); + assert!(Python::with_gil(PyErr::take).is_none()); } #[test] @@ -608,7 +615,7 @@ mod tests { assert!(err.is_instance::(py)); err.restore(py); assert!(PyErr::occurred(py)); - let err = PyErr::fetch(py).unwrap(); + let err = PyErr::fetch(py); assert!(err.is_instance::(py)); assert_eq!(err.to_string(), "ValueError: some exception message"); }) @@ -620,7 +627,7 @@ mod tests { let err: PyErr = PyErr::new::(()); assert!(err.is_instance::(py)); err.restore(py); - let err = PyErr::fetch(py).unwrap(); + let err = PyErr::fetch(py); assert!(err.is_instance::(py)); assert_eq!( err.to_string(), diff --git a/src/exceptions.rs b/src/exceptions.rs index 15e0e780251..004e19f4f9f 100644 --- a/src/exceptions.rs +++ b/src/exceptions.rs @@ -829,7 +829,7 @@ mod tests { e.restore(py); assert_eq!( - PyErr::api_call_failed(py).to_string(), + PyErr::fetch(py).to_string(), "UnicodeDecodeError: \'utf-8\' codec can\'t decode byte 0xd8 in position 2: invalid utf-8" ); }); diff --git a/src/instance.rs b/src/instance.rs index 354927e3449..269d22f3107 100644 --- a/src/instance.rs +++ b/src/instance.rs @@ -589,7 +589,7 @@ impl Py { let kwargs = kwargs.into_ptr(); let ptr = ffi::PyObject_GetAttr(self.as_ptr(), name); if ptr.is_null() { - return Err(PyErr::api_call_failed(py)); + return Err(PyErr::fetch(py)); } let result = PyObject::from_owned_ptr_or_err(py, ffi::PyObject_Call(ptr, args, kwargs)); ffi::Py_DECREF(ptr); @@ -656,7 +656,7 @@ impl Py { pub unsafe fn from_owned_ptr_or_err(py: Python, ptr: *mut ffi::PyObject) -> PyResult> { match NonNull::new(ptr) { Some(nonnull_ptr) => Ok(Py(nonnull_ptr, PhantomData)), - None => Err(PyErr::api_call_failed(py)), + None => Err(PyErr::fetch(py)), } } @@ -694,7 +694,7 @@ impl Py { /// `ptr` must be a pointer to a Python object of type T. #[inline] pub unsafe fn from_borrowed_ptr_or_err(py: Python, ptr: *mut ffi::PyObject) -> PyResult { - Self::from_borrowed_ptr_or_opt(py, ptr).ok_or_else(|| PyErr::api_call_failed(py)) + Self::from_borrowed_ptr_or_opt(py, ptr).ok_or_else(|| PyErr::fetch(py)) } /// Create a `Py` instance by creating a new reference from the given FFI pointer. diff --git a/src/pyclass.rs b/src/pyclass.rs index 61412a6197f..fc8a4efae93 100644 --- a/src/pyclass.rs +++ b/src/pyclass.rs @@ -122,7 +122,7 @@ where let type_object = unsafe { ffi::PyType_FromSpec(&mut spec) }; if type_object.is_null() { - Err(PyErr::api_call_failed(py)) + Err(PyErr::fetch(py)) } else { tp_init_additional::(type_object as _); Ok(type_object as _) diff --git a/src/pyclass_init.rs b/src/pyclass_init.rs index f2b6922bfb2..51dacd09528 100644 --- a/src/pyclass_init.rs +++ b/src/pyclass_init.rs @@ -45,7 +45,7 @@ impl PyObjectInit for PyNativeTypeInitializer { let alloc = get_tp_alloc(subtype).unwrap_or(ffi::PyType_GenericAlloc); let obj = alloc(subtype, 0); return if obj.is_null() { - Err(PyErr::api_call_failed(py)) + Err(PyErr::fetch(py)) } else { Ok(obj) }; @@ -61,7 +61,7 @@ impl PyObjectInit for PyNativeTypeInitializer { Some(newfunc) => { let obj = newfunc(subtype, std::ptr::null_mut(), std::ptr::null_mut()); if obj.is_null() { - Err(PyErr::api_call_failed(py)) + Err(PyErr::fetch(py)) } else { Ok(obj) } diff --git a/src/python.rs b/src/python.rs index e5b2c2d93bd..2fb14857a11 100644 --- a/src/python.rs +++ b/src/python.rs @@ -428,7 +428,7 @@ impl<'p> Python<'p> { unsafe { let mptr = ffi::PyImport_AddModule("__main__\0".as_ptr() as *const _); if mptr.is_null() { - return Err(PyErr::api_call_failed(self)); + return Err(PyErr::fetch(self)); } let globals = globals @@ -438,7 +438,7 @@ impl<'p> Python<'p> { let code_obj = ffi::Py_CompileString(code.as_ptr(), "\0".as_ptr() as _, start); if code_obj.is_null() { - return Err(PyErr::api_call_failed(self)); + return Err(PyErr::fetch(self)); } let res_ptr = ffi::PyEval_EvalCode(code_obj, globals, locals); ffi::Py_DECREF(code_obj); diff --git a/src/types/any.rs b/src/types/any.rs index 38fde0cfb52..8fc8640d4e3 100644 --- a/src/types/any.rs +++ b/src/types/any.rs @@ -418,7 +418,7 @@ impl PyAny { let py = self.py(); let ptr = ffi::PyObject_GetAttr(self.as_ptr(), name); if ptr.is_null() { - return Err(PyErr::api_call_failed(py)); + return Err(PyErr::fetch(py)); } let args = args.into_py(py).into_ptr(); let kwargs = kwargs.into_ptr(); @@ -639,7 +639,7 @@ impl PyAny { pub fn hash(&self) -> PyResult { let v = unsafe { ffi::PyObject_Hash(self.as_ptr()) }; if v == -1 { - Err(PyErr::api_call_failed(self.py())) + Err(PyErr::fetch(self.py())) } else { Ok(v) } @@ -652,7 +652,7 @@ impl PyAny { pub fn len(&self) -> PyResult { let v = unsafe { ffi::PyObject_Size(self.as_ptr()) }; if v == -1 { - Err(PyErr::api_call_failed(self.py())) + Err(PyErr::fetch(self.py())) } else { Ok(v as usize) } diff --git a/src/types/bytearray.rs b/src/types/bytearray.rs index 33b8f06d044..29750a5c8bd 100644 --- a/src/types/bytearray.rs +++ b/src/types/bytearray.rs @@ -161,7 +161,7 @@ impl PyByteArray { if result == 0 { Ok(()) } else { - Err(PyErr::api_call_failed(self.py())) + Err(PyErr::fetch(self.py())) } } } diff --git a/src/types/dict.rs b/src/types/dict.rs index cf7dbbaf0bf..955204ebccf 100644 --- a/src/types/dict.rs +++ b/src/types/dict.rs @@ -88,7 +88,7 @@ impl PyDict { match ffi::PyDict_Contains(self.as_ptr(), key) { 1 => Ok(true), 0 => Ok(false), - _ => Err(PyErr::api_call_failed(self.py())), + _ => Err(PyErr::fetch(self.py())), } }) } diff --git a/src/types/floatob.rs b/src/types/floatob.rs index e725605472d..1cd66510183 100644 --- a/src/types/floatob.rs +++ b/src/types/floatob.rs @@ -53,7 +53,7 @@ impl<'source> FromPyObject<'source> for f64 { let v = unsafe { ffi::PyFloat_AsDouble(obj.as_ptr()) }; if v == -1.0 && PyErr::occurred(obj.py()) { - Err(PyErr::api_call_failed(obj.py())) + Err(PyErr::fetch(obj.py())) } else { Ok(v) } diff --git a/src/types/iterator.rs b/src/types/iterator.rs index 6ba447745e9..c30394986d4 100644 --- a/src/types/iterator.rs +++ b/src/types/iterator.rs @@ -60,7 +60,7 @@ impl<'p> Iterator for &'p PyIterator { Some(obj) => Some(Ok(obj)), None => { if PyErr::occurred(py) { - Some(Err(PyErr::api_call_failed(py))) + Some(Err(PyErr::fetch(py))) } else { None } diff --git a/src/types/mapping.rs b/src/types/mapping.rs index ca907f67a4c..90d8b5cc53f 100644 --- a/src/types/mapping.rs +++ b/src/types/mapping.rs @@ -20,7 +20,7 @@ impl PyMapping { pub fn len(&self) -> PyResult { let v = unsafe { ffi::PyMapping_Size(self.as_ptr()) }; if v == -1 { - Err(PyErr::api_call_failed(self.py())) + Err(PyErr::fetch(self.py())) } else { Ok(v as usize) } diff --git a/src/types/module.rs b/src/types/module.rs index 0121ae16ac1..e3cbcf165a1 100644 --- a/src/types/module.rs +++ b/src/types/module.rs @@ -116,13 +116,13 @@ impl PyModule { unsafe { let cptr = ffi::Py_CompileString(data.as_ptr(), filename.as_ptr(), ffi::Py_file_input); if cptr.is_null() { - return Err(PyErr::api_call_failed(py)); + return Err(PyErr::fetch(py)); } let mptr = ffi::PyImport_ExecCodeModuleEx(module.as_ptr(), cptr, filename.as_ptr()); ffi::Py_DECREF(cptr); if mptr.is_null() { - return Err(PyErr::api_call_failed(py)); + return Err(PyErr::fetch(py)); } <&PyModule as crate::FromPyObject>::extract(py.from_owned_ptr_or_err(mptr)?) @@ -163,7 +163,7 @@ impl PyModule { pub fn name(&self) -> PyResult<&str> { let ptr = unsafe { ffi::PyModule_GetName(self.as_ptr()) }; if ptr.is_null() { - Err(PyErr::api_call_failed(self.py())) + Err(PyErr::fetch(self.py())) } else { let name = unsafe { CStr::from_ptr(ptr) } .to_str() diff --git a/src/types/num.rs b/src/types/num.rs index 6691f113763..11cfba7d625 100644 --- a/src/types/num.rs +++ b/src/types/num.rs @@ -16,7 +16,7 @@ fn err_if_invalid_value( actual_value: T, ) -> PyResult { if actual_value == invalid_value && PyErr::occurred(py) { - Err(PyErr::api_call_failed(py)) + Err(PyErr::fetch(py)) } else { Ok(actual_value) } @@ -76,7 +76,7 @@ macro_rules! int_fits_c_long { let val = unsafe { let num = ffi::PyNumber_Index(ptr); if num.is_null() { - Err(PyErr::api_call_failed(obj.py())) + Err(PyErr::fetch(obj.py())) } else { let val = err_if_invalid_value(obj.py(), -1, ffi::PyLong_AsLong(num)); ffi::Py_DECREF(num); @@ -110,7 +110,7 @@ macro_rules! int_convert_u64_or_i64 { unsafe { let num = ffi::PyNumber_Index(ptr); if num.is_null() { - Err(PyErr::api_call_failed(ob.py())) + Err(PyErr::fetch(ob.py())) } else { let result = err_if_invalid_value(ob.py(), !0, $pylong_as_ll_or_ull(num)); ffi::Py_DECREF(num); @@ -189,7 +189,7 @@ mod fast_128bit_int_conversion { unsafe { let num = ffi::PyNumber_Index(ob.as_ptr()); if num.is_null() { - return Err(PyErr::api_call_failed(ob.py())); + return Err(PyErr::fetch(ob.py())); } let mut buffer = [0; std::mem::size_of::<$rust_type>()]; let ok = ffi::_PyLong_AsByteArray( diff --git a/src/types/sequence.rs b/src/types/sequence.rs index 1a1e1500b15..e14270d5fff 100644 --- a/src/types/sequence.rs +++ b/src/types/sequence.rs @@ -21,7 +21,7 @@ impl PySequence { pub fn len(&self) -> PyResult { let v = unsafe { ffi::PySequence_Size(self.as_ptr()) }; if v == -1 { - Err(PyErr::api_call_failed(self.py())) + Err(PyErr::fetch(self.py())) } else { Ok(v as usize) } @@ -191,7 +191,7 @@ impl PySequence { ffi::PySequence_Count(self.as_ptr(), ptr) }); if r == -1 { - Err(PyErr::api_call_failed(self.py())) + Err(PyErr::fetch(self.py())) } else { Ok(r as usize) } @@ -211,7 +211,7 @@ impl PySequence { match r { 0 => Ok(false), 1 => Ok(true), - _ => Err(PyErr::api_call_failed(self.py())), + _ => Err(PyErr::fetch(self.py())), } } @@ -227,7 +227,7 @@ impl PySequence { ffi::PySequence_Index(self.as_ptr(), ptr) }); if r == -1 { - Err(PyErr::api_call_failed(self.py())) + Err(PyErr::fetch(self.py())) } else { Ok(r as usize) } diff --git a/src/types/set.rs b/src/types/set.rs index 8650e99c797..9c52fe2ec2b 100644 --- a/src/types/set.rs +++ b/src/types/set.rs @@ -73,7 +73,7 @@ impl PySet { match ffi::PySet_Contains(self.as_ptr(), key) { 1 => Ok(true), 0 => Ok(false), - _ => Err(PyErr::api_call_failed(self.py())), + _ => Err(PyErr::fetch(self.py())), } }) } @@ -309,7 +309,7 @@ impl PyFrozenSet { match ffi::PySet_Contains(self.as_ptr(), key) { 1 => Ok(true), 0 => Ok(false), - _ => Err(PyErr::api_call_failed(self.py())), + _ => Err(PyErr::fetch(self.py())), } }) } diff --git a/src/types/slice.rs b/src/types/slice.rs index 2b88beb3fe4..6187e26adbe 100644 --- a/src/types/slice.rs +++ b/src/types/slice.rs @@ -77,7 +77,7 @@ impl PySlice { slicelength, }) } else { - Err(PyErr::api_call_failed(self.py())) + Err(PyErr::fetch(self.py())) } } } diff --git a/src/types/string.rs b/src/types/string.rs index 0648eedc041..4c5ff52d91d 100644 --- a/src/types/string.rs +++ b/src/types/string.rs @@ -171,7 +171,7 @@ impl PyString { let mut size: ffi::Py_ssize_t = 0; let data = unsafe { ffi::PyUnicode_AsUTF8AndSize(self.as_ptr(), &mut size) }; if data.is_null() { - return Err(crate::PyErr::api_call_failed(self.py())); + return Err(crate::PyErr::fetch(self.py())); } else { unsafe { std::slice::from_raw_parts(data as *const u8, size as usize) } } @@ -232,7 +232,7 @@ impl PyString { let ready = ffi::PyUnicode_READY(ptr); if ready != 0 { // Exception was created on failure. - return Err(crate::PyErr::api_call_failed(self.py())); + return Err(crate::PyErr::fetch(self.py())); } }