err: add `PyErr::take`

This commit is contained in:
David Hewitt 2021-10-30 10:51:02 +01:00
parent 833f365aad
commit f801c19efe
24 changed files with 136 additions and 128 deletions

View File

@ -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 `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 `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 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 ### Changed
- Change `PyErr::fetch` to return `Option<PyErr>`. [#1717](https://github.com/PyO3/pyo3/pull/1717)
- `PyList`, `PyTuple` and `PySequence`'s APIs now accepts only `usize` indices instead of `isize`. - `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), [#1733](https://github.com/PyO3/pyo3/pull/1733), [#1802](https://github.com/PyO3/pyo3/pull/1802),
[#1803](https://github.com/PyO3/pyo3/pull/1803) [#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) - 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) - 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) - 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 ### Fixed

View File

@ -494,7 +494,7 @@ pub unsafe trait FromPyPointer<'p>: Sized {
/// ///
/// Relies on [`from_owned_ptr_or_opt`](#method.from_owned_ptr_or_opt). /// 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> { 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`. /// Convert from an arbitrary borrowed `PyObject`.
/// ///
@ -528,7 +528,7 @@ pub unsafe trait FromPyPointer<'p>: Sized {
py: Python<'p>, py: Python<'p>,
ptr: *mut ffi::PyObject, ptr: *mut ffi::PyObject,
) -> PyResult<&'p Self> { ) -> 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))
} }
} }

View File

@ -108,19 +108,16 @@ macro_rules! bigint_conversion {
fn extract(ob: &'source PyAny) -> PyResult<$rust_ty> { fn extract(ob: &'source PyAny) -> PyResult<$rust_ty> {
let py = ob.py(); let py = ob.py();
unsafe { unsafe {
let num = ffi::PyNumber_Index(ob.as_ptr()); let num: Py<PyLong> =
if num.is_null() { Py::from_owned_ptr_or_err(py, ffi::PyNumber_Index(ob.as_ptr()))?;
return Err(PyErr::api_call_failed(py)); let n_bits = ffi::_PyLong_NumBits(num.as_ptr());
} let n_bytes = if n_bits == -1 {
let n_bits = ffi::_PyLong_NumBits(num); return Err(PyErr::fetch(py));
let n_bytes = if n_bits < 0 {
return Err(PyErr::api_call_failed(py));
} else if n_bits == 0 { } else if n_bits == 0 {
0 0
} else { } else {
(n_bits as usize - 1 + $is_signed) / 8 + 1 (n_bits as usize - 1 + $is_signed) / 8 + 1
}; };
let num: Py<PyLong> = Py::from_owned_ptr(py, num);
if n_bytes <= 128 { if n_bytes <= 128 {
let mut buffer = [0; 128]; let mut buffer = [0; 128];
extract(num.as_ref(py), &mut buffer[..n_bytes], $is_signed)?; extract(num.as_ref(py), &mut buffer[..n_bytes], $is_signed)?;

View File

@ -143,19 +143,22 @@ macro_rules! complex_conversion {
#[cfg(not(any(Py_LIMITED_API, PyPy)))] #[cfg(not(any(Py_LIMITED_API, PyPy)))]
unsafe { unsafe {
let val = ffi::PyComplex_AsCComplex(obj.as_ptr()); let val = ffi::PyComplex_AsCComplex(obj.as_ptr());
if val.real == -1.0 && PyErr::occurred(obj.py()) { if val.real == -1.0 {
Err(PyErr::api_call_failed(obj.py())) if let Some(err) = PyErr::take(obj.py()) {
} else { return Err(err);
Ok(Complex::new(val.real as $float, val.imag as $float)) }
} }
Ok(Complex::new(val.real as $float, val.imag as $float))
} }
#[cfg(any(Py_LIMITED_API, PyPy))] #[cfg(any(Py_LIMITED_API, PyPy))]
unsafe { unsafe {
let ptr = obj.as_ptr(); let ptr = obj.as_ptr();
let real = ffi::PyComplex_RealAsDouble(ptr); let real = ffi::PyComplex_RealAsDouble(ptr);
if real == -1.0 && PyErr::occurred(obj.py()) { if real == -1.0 {
return Err(PyErr::api_call_failed(obj.py())); if let Some(err) = PyErr::take(obj.py()) {
return Err(err);
}
} }
let imag = ffi::PyComplex_ImagAsDouble(ptr); let imag = ffi::PyComplex_ImagAsDouble(ptr);
Ok(Complex::new(real as $float, imag as $float)) Ok(Complex::new(real as $float, imag as $float))

View File

@ -94,7 +94,7 @@ impl FromPyObject<'_> for OsString {
let size = let size =
unsafe { ffi::PyUnicode_AsWideChar(pystring.as_ptr(), std::ptr::null_mut(), 0) }; unsafe { ffi::PyUnicode_AsWideChar(pystring.as_ptr(), std::ptr::null_mut(), 0) };
if size == -1 { 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]; let mut buffer = vec![0; size as usize];

View File

@ -23,7 +23,7 @@ pub(crate) enum PyErrState {
pvalue: Box<dyn FnOnce(Python) -> PyObject + Send + Sync>, pvalue: Box<dyn FnOnce(Python) -> PyObject + Send + Sync>,
}, },
FfiTuple { FfiTuple {
ptype: Option<PyObject>, ptype: PyObject,
pvalue: Option<PyObject>, pvalue: Option<PyObject>,
ptraceback: Option<PyObject>, ptraceback: Option<PyObject>,
}, },

View File

@ -7,9 +7,7 @@ use crate::{
exceptions::{self, PyBaseException}, exceptions::{self, PyBaseException},
ffi, ffi,
}; };
use crate::{ use crate::{AsPyPointer, IntoPy, Py, PyAny, PyObject, Python, ToBorrowedObject, ToPyObject};
AsPyPointer, FromPyPointer, IntoPy, Py, PyAny, PyObject, Python, ToBorrowedObject, ToPyObject,
};
use std::borrow::Cow; use std::borrow::Cow;
use std::cell::UnsafeCell; use std::cell::UnsafeCell;
use std::ffi::CString; use std::ffi::CString;
@ -137,15 +135,13 @@ impl PyErr {
let state = if unsafe { ffi::PyExceptionInstance_Check(ptr) } != 0 { let state = if unsafe { ffi::PyExceptionInstance_Check(ptr) } != 0 {
PyErrState::Normalized(PyErrStateNormalized { PyErrState::Normalized(PyErrStateNormalized {
ptype: unsafe { ptype: obj.get_type().into(),
Py::from_borrowed_ptr(obj.py(), ffi::PyExceptionInstance_Class(ptr))
},
pvalue: unsafe { Py::from_borrowed_ptr(obj.py(), obj.as_ptr()) }, pvalue: unsafe { Py::from_borrowed_ptr(obj.py(), obj.as_ptr()) },
ptraceback: None, ptraceback: None,
}) })
} else if unsafe { ffi::PyExceptionClass_Check(obj.as_ptr()) } != 0 { } else if unsafe { ffi::PyExceptionClass_Check(obj.as_ptr()) } != 0 {
PyErrState::FfiTuple { PyErrState::FfiTuple {
ptype: unsafe { Some(Py::from_borrowed_ptr(obj.py(), ptr)) }, ptype: obj.into(),
pvalue: None, pvalue: None,
ptraceback: None, ptraceback: None,
} }
@ -218,61 +214,95 @@ impl PyErr {
unsafe { !ffi::PyErr_Occurred().is_null() } 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 the error is a `PanicException` (which would have originated from a panic in a pyo3
/// If no error is set, returns a `None`. /// callback) then this function will resume the panic.
/// ///
/// If the error fetched is a `PanicException` (which would have originated from a panic in a /// Use this function when it is not known if an error should be present. If the error is
/// pyo3 callback) then this function will resume the panic. /// expected to have been set, for example from [PyErr::occurred] or by an error return value
pub fn fetch(py: Python) -> Option<PyErr> { /// from a C FFI function, use [PyErr::fetch].
unsafe { pub fn take(py: Python) -> Option<PyErr> {
let (ptype, pvalue, ptraceback) = unsafe {
let mut ptype: *mut ffi::PyObject = std::ptr::null_mut(); let mut ptype: *mut ffi::PyObject = std::ptr::null_mut();
let mut pvalue: *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(); let mut ptraceback: *mut ffi::PyObject = std::ptr::null_mut();
ffi::PyErr_Fetch(&mut ptype, &mut pvalue, &mut ptraceback); ffi::PyErr_Fetch(&mut ptype, &mut pvalue, &mut ptraceback);
// If the error indicator is not set, all three variables are set to NULL // Convert to Py immediately so that any references are freed by early return.
if ptype.is_null() && pvalue.is_null() && ptraceback.is_null() { let ptype = Py::from_owned_ptr_or_opt(py, ptype);
return None; 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.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:");
unsafe {
use crate::conversion::IntoPyPointer;
ffi::PyErr_Restore(ptype.into_ptr(), pvalue.into_ptr(), ptraceback.into_ptr());
ffi::PyErr_PrintEx(0);
} }
let err = PyErr::new_from_ffi_tuple(py, ptype, pvalue, ptraceback); std::panic::resume_unwind(Box::new(msg))
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"));
eprintln!(
"--- PyO3 is resuming a panic after fetching a PanicException from Python. ---"
);
eprintln!("Python stack trace below:");
err.print(py);
std::panic::resume_unwind(Box::new(msg))
}
Some(err)
} }
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. /// This behavior is consistent with Python's internal handling of what happens when a C return
/// If no error is set, returns a `SystemError` in release mode, /// value indicates an error occurred but the global error state is empty. (A lack of exception
/// panics in debug mode. /// should be treated as a bug in the code which returned an error code but did not set an
pub(crate) fn api_call_failed(py: Python) -> PyErr { /// exception.)
#[cfg(debug_assertions)] ///
{ /// Use this function when the error is expected to have been set, for example from
PyErr::fetch(py).expect("error return without exception set") /// [PyErr::occurred] or by an error return value from a C FFI function.
} #[cfg_attr(all(debug_assertions, track_caller), track_caller)]
#[cfg(not(debug_assertions))] #[inline]
{ pub fn fetch(py: Python) -> PyErr {
use crate::exceptions::PySystemError; const FAILED_TO_FETCH: &str = "attempted to fetch exception but none was set";
match PyErr::take(py) {
PyErr::fetch(py) Some(err) => err,
.unwrap_or_else(|| PySystemError::new_err("error return without exception set")) #[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`. /// Prints a standard traceback to `sys.stderr`.
pub fn print(&self, py: Python) { pub fn print(&self, py: Python) {
self.clone_ref(py).restore(py); self.clone_ref(py).restore(py);
@ -579,7 +588,7 @@ pub fn error_on_minusone(py: Python, result: c_int) -> PyResult<()> {
if result != -1 { if result != -1 {
Ok(()) Ok(())
} else { } else {
Err(PyErr::api_call_failed(py)) Err(PyErr::fetch(py))
} }
} }
@ -596,9 +605,7 @@ mod tests {
#[test] #[test]
fn no_error() { fn no_error() {
Python::with_gil(|py| { assert!(Python::with_gil(PyErr::take).is_none());
assert!(PyErr::fetch(py).is_none());
});
} }
#[test] #[test]
@ -608,7 +615,7 @@ mod tests {
assert!(err.is_instance::<exceptions::PyValueError>(py)); assert!(err.is_instance::<exceptions::PyValueError>(py));
err.restore(py); err.restore(py);
assert!(PyErr::occurred(py)); assert!(PyErr::occurred(py));
let err = PyErr::fetch(py).unwrap(); let err = PyErr::fetch(py);
assert!(err.is_instance::<exceptions::PyValueError>(py)); assert!(err.is_instance::<exceptions::PyValueError>(py));
assert_eq!(err.to_string(), "ValueError: some exception message"); assert_eq!(err.to_string(), "ValueError: some exception message");
}) })
@ -620,7 +627,7 @@ mod tests {
let err: PyErr = PyErr::new::<crate::types::PyString, _>(()); let err: PyErr = PyErr::new::<crate::types::PyString, _>(());
assert!(err.is_instance::<exceptions::PyTypeError>(py)); assert!(err.is_instance::<exceptions::PyTypeError>(py));
err.restore(py); err.restore(py);
let err = PyErr::fetch(py).unwrap(); let err = PyErr::fetch(py);
assert!(err.is_instance::<exceptions::PyTypeError>(py)); assert!(err.is_instance::<exceptions::PyTypeError>(py));
assert_eq!( assert_eq!(
err.to_string(), err.to_string(),

View File

@ -829,7 +829,7 @@ mod tests {
e.restore(py); e.restore(py);
assert_eq!( 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" "UnicodeDecodeError: \'utf-8\' codec can\'t decode byte 0xd8 in position 2: invalid utf-8"
); );
}); });

View File

@ -589,7 +589,7 @@ impl<T> Py<T> {
let kwargs = kwargs.into_ptr(); let kwargs = kwargs.into_ptr();
let ptr = ffi::PyObject_GetAttr(self.as_ptr(), name); let ptr = ffi::PyObject_GetAttr(self.as_ptr(), name);
if ptr.is_null() { 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)); let result = PyObject::from_owned_ptr_or_err(py, ffi::PyObject_Call(ptr, args, kwargs));
ffi::Py_DECREF(ptr); ffi::Py_DECREF(ptr);
@ -656,7 +656,7 @@ impl<T> Py<T> {
pub unsafe fn from_owned_ptr_or_err(py: Python, ptr: *mut ffi::PyObject) -> PyResult<Py<T>> { pub unsafe fn from_owned_ptr_or_err(py: Python, ptr: *mut ffi::PyObject) -> PyResult<Py<T>> {
match NonNull::new(ptr) { match NonNull::new(ptr) {
Some(nonnull_ptr) => Ok(Py(nonnull_ptr, PhantomData)), 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<T> Py<T> {
/// `ptr` must be a pointer to a Python object of type T. /// `ptr` must be a pointer to a Python object of type T.
#[inline] #[inline]
pub unsafe fn from_borrowed_ptr_or_err(py: Python, ptr: *mut ffi::PyObject) -> PyResult<Self> { pub unsafe fn from_borrowed_ptr_or_err(py: Python, ptr: *mut ffi::PyObject) -> PyResult<Self> {
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<T>` instance by creating a new reference from the given FFI pointer. /// Create a `Py<T>` instance by creating a new reference from the given FFI pointer.

View File

@ -122,7 +122,7 @@ where
let type_object = unsafe { ffi::PyType_FromSpec(&mut spec) }; let type_object = unsafe { ffi::PyType_FromSpec(&mut spec) };
if type_object.is_null() { if type_object.is_null() {
Err(PyErr::api_call_failed(py)) Err(PyErr::fetch(py))
} else { } else {
tp_init_additional::<T>(type_object as _); tp_init_additional::<T>(type_object as _);
Ok(type_object as _) Ok(type_object as _)

View File

@ -45,7 +45,7 @@ impl<T: PyTypeInfo> PyObjectInit<T> for PyNativeTypeInitializer<T> {
let alloc = get_tp_alloc(subtype).unwrap_or(ffi::PyType_GenericAlloc); let alloc = get_tp_alloc(subtype).unwrap_or(ffi::PyType_GenericAlloc);
let obj = alloc(subtype, 0); let obj = alloc(subtype, 0);
return if obj.is_null() { return if obj.is_null() {
Err(PyErr::api_call_failed(py)) Err(PyErr::fetch(py))
} else { } else {
Ok(obj) Ok(obj)
}; };
@ -61,7 +61,7 @@ impl<T: PyTypeInfo> PyObjectInit<T> for PyNativeTypeInitializer<T> {
Some(newfunc) => { Some(newfunc) => {
let obj = newfunc(subtype, std::ptr::null_mut(), std::ptr::null_mut()); let obj = newfunc(subtype, std::ptr::null_mut(), std::ptr::null_mut());
if obj.is_null() { if obj.is_null() {
Err(PyErr::api_call_failed(py)) Err(PyErr::fetch(py))
} else { } else {
Ok(obj) Ok(obj)
} }

View File

@ -428,7 +428,7 @@ impl<'p> Python<'p> {
unsafe { unsafe {
let mptr = ffi::PyImport_AddModule("__main__\0".as_ptr() as *const _); let mptr = ffi::PyImport_AddModule("__main__\0".as_ptr() as *const _);
if mptr.is_null() { if mptr.is_null() {
return Err(PyErr::api_call_failed(self)); return Err(PyErr::fetch(self));
} }
let globals = globals let globals = globals
@ -438,7 +438,7 @@ impl<'p> Python<'p> {
let code_obj = ffi::Py_CompileString(code.as_ptr(), "<string>\0".as_ptr() as _, start); let code_obj = ffi::Py_CompileString(code.as_ptr(), "<string>\0".as_ptr() as _, start);
if code_obj.is_null() { 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); let res_ptr = ffi::PyEval_EvalCode(code_obj, globals, locals);
ffi::Py_DECREF(code_obj); ffi::Py_DECREF(code_obj);

View File

@ -418,7 +418,7 @@ impl PyAny {
let py = self.py(); let py = self.py();
let ptr = ffi::PyObject_GetAttr(self.as_ptr(), name); let ptr = ffi::PyObject_GetAttr(self.as_ptr(), name);
if ptr.is_null() { 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 args = args.into_py(py).into_ptr();
let kwargs = kwargs.into_ptr(); let kwargs = kwargs.into_ptr();
@ -639,7 +639,7 @@ impl PyAny {
pub fn hash(&self) -> PyResult<isize> { pub fn hash(&self) -> PyResult<isize> {
let v = unsafe { ffi::PyObject_Hash(self.as_ptr()) }; let v = unsafe { ffi::PyObject_Hash(self.as_ptr()) };
if v == -1 { if v == -1 {
Err(PyErr::api_call_failed(self.py())) Err(PyErr::fetch(self.py()))
} else { } else {
Ok(v) Ok(v)
} }
@ -652,7 +652,7 @@ impl PyAny {
pub fn len(&self) -> PyResult<usize> { pub fn len(&self) -> PyResult<usize> {
let v = unsafe { ffi::PyObject_Size(self.as_ptr()) }; let v = unsafe { ffi::PyObject_Size(self.as_ptr()) };
if v == -1 { if v == -1 {
Err(PyErr::api_call_failed(self.py())) Err(PyErr::fetch(self.py()))
} else { } else {
Ok(v as usize) Ok(v as usize)
} }

View File

@ -161,7 +161,7 @@ impl PyByteArray {
if result == 0 { if result == 0 {
Ok(()) Ok(())
} else { } else {
Err(PyErr::api_call_failed(self.py())) Err(PyErr::fetch(self.py()))
} }
} }
} }

View File

@ -88,7 +88,7 @@ impl PyDict {
match ffi::PyDict_Contains(self.as_ptr(), key) { match ffi::PyDict_Contains(self.as_ptr(), key) {
1 => Ok(true), 1 => Ok(true),
0 => Ok(false), 0 => Ok(false),
_ => Err(PyErr::api_call_failed(self.py())), _ => Err(PyErr::fetch(self.py())),
} }
}) })
} }

View File

@ -53,7 +53,7 @@ impl<'source> FromPyObject<'source> for f64 {
let v = unsafe { ffi::PyFloat_AsDouble(obj.as_ptr()) }; let v = unsafe { ffi::PyFloat_AsDouble(obj.as_ptr()) };
if v == -1.0 && PyErr::occurred(obj.py()) { if v == -1.0 && PyErr::occurred(obj.py()) {
Err(PyErr::api_call_failed(obj.py())) Err(PyErr::fetch(obj.py()))
} else { } else {
Ok(v) Ok(v)
} }

View File

@ -60,7 +60,7 @@ impl<'p> Iterator for &'p PyIterator {
Some(obj) => Some(Ok(obj)), Some(obj) => Some(Ok(obj)),
None => { None => {
if PyErr::occurred(py) { if PyErr::occurred(py) {
Some(Err(PyErr::api_call_failed(py))) Some(Err(PyErr::fetch(py)))
} else { } else {
None None
} }

View File

@ -20,7 +20,7 @@ impl PyMapping {
pub fn len(&self) -> PyResult<usize> { pub fn len(&self) -> PyResult<usize> {
let v = unsafe { ffi::PyMapping_Size(self.as_ptr()) }; let v = unsafe { ffi::PyMapping_Size(self.as_ptr()) };
if v == -1 { if v == -1 {
Err(PyErr::api_call_failed(self.py())) Err(PyErr::fetch(self.py()))
} else { } else {
Ok(v as usize) Ok(v as usize)
} }

View File

@ -116,13 +116,13 @@ impl PyModule {
unsafe { unsafe {
let cptr = ffi::Py_CompileString(data.as_ptr(), filename.as_ptr(), ffi::Py_file_input); let cptr = ffi::Py_CompileString(data.as_ptr(), filename.as_ptr(), ffi::Py_file_input);
if cptr.is_null() { 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()); let mptr = ffi::PyImport_ExecCodeModuleEx(module.as_ptr(), cptr, filename.as_ptr());
ffi::Py_DECREF(cptr); ffi::Py_DECREF(cptr);
if mptr.is_null() { 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)?) <&PyModule as crate::FromPyObject>::extract(py.from_owned_ptr_or_err(mptr)?)
@ -163,7 +163,7 @@ impl PyModule {
pub fn name(&self) -> PyResult<&str> { pub fn name(&self) -> PyResult<&str> {
let ptr = unsafe { ffi::PyModule_GetName(self.as_ptr()) }; let ptr = unsafe { ffi::PyModule_GetName(self.as_ptr()) };
if ptr.is_null() { if ptr.is_null() {
Err(PyErr::api_call_failed(self.py())) Err(PyErr::fetch(self.py()))
} else { } else {
let name = unsafe { CStr::from_ptr(ptr) } let name = unsafe { CStr::from_ptr(ptr) }
.to_str() .to_str()

View File

@ -16,7 +16,7 @@ fn err_if_invalid_value<T: PartialEq>(
actual_value: T, actual_value: T,
) -> PyResult<T> { ) -> PyResult<T> {
if actual_value == invalid_value && PyErr::occurred(py) { if actual_value == invalid_value && PyErr::occurred(py) {
Err(PyErr::api_call_failed(py)) Err(PyErr::fetch(py))
} else { } else {
Ok(actual_value) Ok(actual_value)
} }
@ -76,7 +76,7 @@ macro_rules! int_fits_c_long {
let val = unsafe { let val = unsafe {
let num = ffi::PyNumber_Index(ptr); let num = ffi::PyNumber_Index(ptr);
if num.is_null() { if num.is_null() {
Err(PyErr::api_call_failed(obj.py())) Err(PyErr::fetch(obj.py()))
} else { } else {
let val = err_if_invalid_value(obj.py(), -1, ffi::PyLong_AsLong(num)); let val = err_if_invalid_value(obj.py(), -1, ffi::PyLong_AsLong(num));
ffi::Py_DECREF(num); ffi::Py_DECREF(num);
@ -110,7 +110,7 @@ macro_rules! int_convert_u64_or_i64 {
unsafe { unsafe {
let num = ffi::PyNumber_Index(ptr); let num = ffi::PyNumber_Index(ptr);
if num.is_null() { if num.is_null() {
Err(PyErr::api_call_failed(ob.py())) Err(PyErr::fetch(ob.py()))
} else { } else {
let result = err_if_invalid_value(ob.py(), !0, $pylong_as_ll_or_ull(num)); let result = err_if_invalid_value(ob.py(), !0, $pylong_as_ll_or_ull(num));
ffi::Py_DECREF(num); ffi::Py_DECREF(num);
@ -189,7 +189,7 @@ mod fast_128bit_int_conversion {
unsafe { unsafe {
let num = ffi::PyNumber_Index(ob.as_ptr()); let num = ffi::PyNumber_Index(ob.as_ptr());
if num.is_null() { 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 mut buffer = [0; std::mem::size_of::<$rust_type>()];
let ok = ffi::_PyLong_AsByteArray( let ok = ffi::_PyLong_AsByteArray(

View File

@ -21,7 +21,7 @@ impl PySequence {
pub fn len(&self) -> PyResult<usize> { pub fn len(&self) -> PyResult<usize> {
let v = unsafe { ffi::PySequence_Size(self.as_ptr()) }; let v = unsafe { ffi::PySequence_Size(self.as_ptr()) };
if v == -1 { if v == -1 {
Err(PyErr::api_call_failed(self.py())) Err(PyErr::fetch(self.py()))
} else { } else {
Ok(v as usize) Ok(v as usize)
} }
@ -191,7 +191,7 @@ impl PySequence {
ffi::PySequence_Count(self.as_ptr(), ptr) ffi::PySequence_Count(self.as_ptr(), ptr)
}); });
if r == -1 { if r == -1 {
Err(PyErr::api_call_failed(self.py())) Err(PyErr::fetch(self.py()))
} else { } else {
Ok(r as usize) Ok(r as usize)
} }
@ -211,7 +211,7 @@ impl PySequence {
match r { match r {
0 => Ok(false), 0 => Ok(false),
1 => Ok(true), 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) ffi::PySequence_Index(self.as_ptr(), ptr)
}); });
if r == -1 { if r == -1 {
Err(PyErr::api_call_failed(self.py())) Err(PyErr::fetch(self.py()))
} else { } else {
Ok(r as usize) Ok(r as usize)
} }

View File

@ -73,7 +73,7 @@ impl PySet {
match ffi::PySet_Contains(self.as_ptr(), key) { match ffi::PySet_Contains(self.as_ptr(), key) {
1 => Ok(true), 1 => Ok(true),
0 => Ok(false), 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) { match ffi::PySet_Contains(self.as_ptr(), key) {
1 => Ok(true), 1 => Ok(true),
0 => Ok(false), 0 => Ok(false),
_ => Err(PyErr::api_call_failed(self.py())), _ => Err(PyErr::fetch(self.py())),
} }
}) })
} }

View File

@ -77,7 +77,7 @@ impl PySlice {
slicelength, slicelength,
}) })
} else { } else {
Err(PyErr::api_call_failed(self.py())) Err(PyErr::fetch(self.py()))
} }
} }
} }

View File

@ -171,7 +171,7 @@ impl PyString {
let mut size: ffi::Py_ssize_t = 0; let mut size: ffi::Py_ssize_t = 0;
let data = unsafe { ffi::PyUnicode_AsUTF8AndSize(self.as_ptr(), &mut size) }; let data = unsafe { ffi::PyUnicode_AsUTF8AndSize(self.as_ptr(), &mut size) };
if data.is_null() { if data.is_null() {
return Err(crate::PyErr::api_call_failed(self.py())); return Err(crate::PyErr::fetch(self.py()));
} else { } else {
unsafe { std::slice::from_raw_parts(data as *const u8, size as usize) } 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); let ready = ffi::PyUnicode_READY(ptr);
if ready != 0 { if ready != 0 {
// Exception was created on failure. // Exception was created on failure.
return Err(crate::PyErr::api_call_failed(self.py())); return Err(crate::PyErr::fetch(self.py()));
} }
} }