err: add `PyErr::take`
This commit is contained in:
parent
833f365aad
commit
f801c19efe
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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)?;
|
||||||
|
|
|
@ -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))
|
||||||
|
|
|
@ -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];
|
||||||
|
|
|
@ -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>,
|
||||||
},
|
},
|
||||||
|
|
159
src/err/mod.rs
159
src/err/mod.rs
|
@ -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(),
|
||||||
|
|
|
@ -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"
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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 _)
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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())),
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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(
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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())),
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -77,7 +77,7 @@ impl PySlice {
|
||||||
slicelength,
|
slicelength,
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
Err(PyErr::api_call_failed(self.py()))
|
Err(PyErr::fetch(self.py()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue