Merge pull request #3273 from davidhewitt/conventions

add some style guide to Contributing.md
This commit is contained in:
David Hewitt 2023-07-05 17:14:24 +00:00 committed by GitHub
commit edb62e05e3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
25 changed files with 420 additions and 416 deletions

View file

@ -111,6 +111,36 @@ To include your changes in the release notes, you should create one (or more) ne
- `removed` - for features which have been removed - `removed` - for features which have been removed
- `fixed` - for "changed" features which were classed as a bugfix - `fixed` - for "changed" features which were classed as a bugfix
### Style guide
#### Generic code
PyO3 has a lot of generic APIs to increase usability. These can come at the cost of generic code bloat. Where reasonable, try to implement a concrete sub-portion of generic functions. There are two forms of this:
- If the concrete sub-portion doesn't benefit from re-use by other functions, name it `inner` and keep it as a local to the function.
- If the concrete sub-portion is re-used by other functions, preferably name it `_foo` and place it directly below `foo` in the source code (where `foo` is the original generic function).
#### FFI calls
PyO3 makes a lot of FFI calls to Python's C API using raw pointers. Where possible try to avoid using pointers-to-temporaries in expressions:
```rust
// dangerous
pyo3::ffi::Something(name.to_object(py).as_ptr());
// because the following refactoring is a use-after-free error:
let name = name.to_object(py).as_ptr();
pyo3::ffi::Something(name)
```
Instead, prefer to bind the safe owned `PyObject` wrapper before passing to ffi functions:
```rust
let name: PyObject = name.to_object(py);
pyo3::ffi::Something(name.as_ptr())
// name will automatically be freed when it falls out of scope
```
## Python and Rust version support policy ## Python and Rust version support policy
PyO3 aims to keep sufficient compatibility to make packaging Python extensions built with PyO3 feasible on most common package managers. PyO3 aims to keep sufficient compatibility to make packaging Python extensions built with PyO3 feasible on most common package managers.

View file

@ -119,7 +119,7 @@ pub fn process_functions_in_module(
let name = &func.sig.ident; let name = &func.sig.ident;
let statements: Vec<syn::Stmt> = syn::parse_quote! { let statements: Vec<syn::Stmt> = syn::parse_quote! {
#wrapped_function #wrapped_function
#module_name.add_function(#krate::impl_::pyfunction::wrap_pyfunction_impl(&#name::DEF, #module_name)?)?; #module_name.add_function(#krate::impl_::pyfunction::_wrap_pyfunction(&#name::DEF, #module_name)?)?;
}; };
stmts.extend(statements); stmts.extend(statements);
} }

View file

@ -420,7 +420,7 @@ fn impl_traverse_slot(cls: &syn::Type, spec: &FnSpec<'_>) -> syn::Result<MethodA
visit: _pyo3::ffi::visitproc, visit: _pyo3::ffi::visitproc,
arg: *mut ::std::os::raw::c_void, arg: *mut ::std::os::raw::c_void,
) -> ::std::os::raw::c_int { ) -> ::std::os::raw::c_int {
_pyo3::impl_::pymethods::call_traverse_impl::<#cls>(slf, #cls::#rust_fn_ident, visit, arg) _pyo3::impl_::pymethods::_call_traverse::<#cls>(slf, #cls::#rust_fn_ident, visit, arg)
} }
}; };
let slot_def = quote! { let slot_def = quote! {

View file

@ -193,14 +193,13 @@ impl<T: Element> PyBuffer<T> {
pub fn get(obj: &PyAny) -> PyResult<PyBuffer<T>> { pub fn get(obj: &PyAny) -> PyResult<PyBuffer<T>> {
// TODO: use nightly API Box::new_uninit() once stable // TODO: use nightly API Box::new_uninit() once stable
let mut buf = Box::new(mem::MaybeUninit::uninit()); let mut buf = Box::new(mem::MaybeUninit::uninit());
let buf: Box<ffi::Py_buffer> = unsafe { let buf: Box<ffi::Py_buffer> = {
err::error_on_minusone( err::error_on_minusone(obj.py(), unsafe {
obj.py(), ffi::PyObject_GetBuffer(obj.as_ptr(), buf.as_mut_ptr(), ffi::PyBUF_FULL_RO)
ffi::PyObject_GetBuffer(obj.as_ptr(), buf.as_mut_ptr(), ffi::PyBUF_FULL_RO), })?;
)?;
// Safety: buf is initialized by PyObject_GetBuffer. // Safety: buf is initialized by PyObject_GetBuffer.
// TODO: use nightly API Box::assume_init() once stable // TODO: use nightly API Box::assume_init() once stable
mem::transmute(buf) unsafe { mem::transmute(buf) }
}; };
// Create PyBuffer immediately so that if validation checks fail, the PyBuffer::drop code // Create PyBuffer immediately so that if validation checks fail, the PyBuffer::drop code
// will call PyBuffer_Release (thus avoiding any leaks). // will call PyBuffer_Release (thus avoiding any leaks).
@ -469,7 +468,7 @@ impl<T: Element> PyBuffer<T> {
/// you can use `<T as buffer::Element>::is_compatible_format(buf.format())`. /// you can use `<T as buffer::Element>::is_compatible_format(buf.format())`.
/// Alternatively, `match buffer::ElementType::from_format(buf.format())`. /// Alternatively, `match buffer::ElementType::from_format(buf.format())`.
pub fn copy_to_slice(&self, py: Python<'_>, target: &mut [T]) -> PyResult<()> { pub fn copy_to_slice(&self, py: Python<'_>, target: &mut [T]) -> PyResult<()> {
self.copy_to_slice_impl(py, target, b'C') self._copy_to_slice(py, target, b'C')
} }
/// Copies the buffer elements to the specified slice. /// Copies the buffer elements to the specified slice.
@ -482,10 +481,10 @@ impl<T: Element> PyBuffer<T> {
/// you can use `<T as buffer::Element>::is_compatible_format(buf.format())`. /// you can use `<T as buffer::Element>::is_compatible_format(buf.format())`.
/// Alternatively, `match buffer::ElementType::from_format(buf.format())`. /// Alternatively, `match buffer::ElementType::from_format(buf.format())`.
pub fn copy_to_fortran_slice(&self, py: Python<'_>, target: &mut [T]) -> PyResult<()> { pub fn copy_to_fortran_slice(&self, py: Python<'_>, target: &mut [T]) -> PyResult<()> {
self.copy_to_slice_impl(py, target, b'F') self._copy_to_slice(py, target, b'F')
} }
fn copy_to_slice_impl(&self, py: Python<'_>, target: &mut [T], fort: u8) -> PyResult<()> { fn _copy_to_slice(&self, py: Python<'_>, target: &mut [T], fort: u8) -> PyResult<()> {
if mem::size_of_val(target) != self.len_bytes() { if mem::size_of_val(target) != self.len_bytes() {
return Err(PyBufferError::new_err(format!( return Err(PyBufferError::new_err(format!(
"slice to copy to (of length {}) does not match buffer length of {}", "slice to copy to (of length {}) does not match buffer length of {}",
@ -493,9 +492,8 @@ impl<T: Element> PyBuffer<T> {
self.item_count() self.item_count()
))); )));
} }
unsafe {
err::error_on_minusone( err::error_on_minusone(py, unsafe {
py,
ffi::PyBuffer_ToContiguous( ffi::PyBuffer_ToContiguous(
target.as_ptr() as *mut raw::c_void, target.as_ptr() as *mut raw::c_void,
#[cfg(Py_3_11)] #[cfg(Py_3_11)]
@ -506,9 +504,8 @@ impl<T: Element> PyBuffer<T> {
}, },
self.0.len, self.0.len,
fort as std::os::raw::c_char, fort as std::os::raw::c_char,
),
) )
} })
} }
/// Copies the buffer elements to a newly allocated vector. /// Copies the buffer elements to a newly allocated vector.
@ -516,7 +513,7 @@ impl<T: Element> PyBuffer<T> {
/// ///
/// Fails if the buffer format is not compatible with type `T`. /// Fails if the buffer format is not compatible with type `T`.
pub fn to_vec(&self, py: Python<'_>) -> PyResult<Vec<T>> { pub fn to_vec(&self, py: Python<'_>) -> PyResult<Vec<T>> {
self.to_vec_impl(py, b'C') self._to_vec(py, b'C')
} }
/// Copies the buffer elements to a newly allocated vector. /// Copies the buffer elements to a newly allocated vector.
@ -524,17 +521,16 @@ impl<T: Element> PyBuffer<T> {
/// ///
/// Fails if the buffer format is not compatible with type `T`. /// Fails if the buffer format is not compatible with type `T`.
pub fn to_fortran_vec(&self, py: Python<'_>) -> PyResult<Vec<T>> { pub fn to_fortran_vec(&self, py: Python<'_>) -> PyResult<Vec<T>> {
self.to_vec_impl(py, b'F') self._to_vec(py, b'F')
} }
fn to_vec_impl(&self, py: Python<'_>, fort: u8) -> PyResult<Vec<T>> { fn _to_vec(&self, py: Python<'_>, fort: u8) -> PyResult<Vec<T>> {
let item_count = self.item_count(); let item_count = self.item_count();
let mut vec: Vec<T> = Vec::with_capacity(item_count); let mut vec: Vec<T> = Vec::with_capacity(item_count);
unsafe {
// Copy the buffer into the uninitialized space in the vector. // Copy the buffer into the uninitialized space in the vector.
// Due to T:Copy, we don't need to be concerned with Drop impls. // Due to T:Copy, we don't need to be concerned with Drop impls.
err::error_on_minusone( err::error_on_minusone(py, unsafe {
py,
ffi::PyBuffer_ToContiguous( ffi::PyBuffer_ToContiguous(
vec.as_ptr() as *mut raw::c_void, vec.as_ptr() as *mut raw::c_void,
#[cfg(Py_3_11)] #[cfg(Py_3_11)]
@ -545,11 +541,10 @@ impl<T: Element> PyBuffer<T> {
}, },
self.0.len, self.0.len,
fort as std::os::raw::c_char, fort as std::os::raw::c_char,
), )
)?; })?;
// set vector length to mark the now-initialized space as usable // set vector length to mark the now-initialized space as usable
vec.set_len(item_count); unsafe { vec.set_len(item_count) };
}
Ok(vec) Ok(vec)
} }
@ -564,7 +559,7 @@ impl<T: Element> PyBuffer<T> {
/// use `<T as buffer::Element>::is_compatible_format(buf.format())`. /// use `<T as buffer::Element>::is_compatible_format(buf.format())`.
/// Alternatively, `match buffer::ElementType::from_format(buf.format())`. /// Alternatively, `match buffer::ElementType::from_format(buf.format())`.
pub fn copy_from_slice(&self, py: Python<'_>, source: &[T]) -> PyResult<()> { pub fn copy_from_slice(&self, py: Python<'_>, source: &[T]) -> PyResult<()> {
self.copy_from_slice_impl(py, source, b'C') self._copy_from_slice(py, source, b'C')
} }
/// Copies the specified slice into the buffer. /// Copies the specified slice into the buffer.
@ -578,10 +573,10 @@ impl<T: Element> PyBuffer<T> {
/// use `<T as buffer::Element>::is_compatible_format(buf.format())`. /// use `<T as buffer::Element>::is_compatible_format(buf.format())`.
/// Alternatively, `match buffer::ElementType::from_format(buf.format())`. /// Alternatively, `match buffer::ElementType::from_format(buf.format())`.
pub fn copy_from_fortran_slice(&self, py: Python<'_>, source: &[T]) -> PyResult<()> { pub fn copy_from_fortran_slice(&self, py: Python<'_>, source: &[T]) -> PyResult<()> {
self.copy_from_slice_impl(py, source, b'F') self._copy_from_slice(py, source, b'F')
} }
fn copy_from_slice_impl(&self, py: Python<'_>, source: &[T], fort: u8) -> PyResult<()> { fn _copy_from_slice(&self, py: Python<'_>, source: &[T], fort: u8) -> PyResult<()> {
if self.readonly() { if self.readonly() {
return Err(PyBufferError::new_err("cannot write to read-only buffer")); return Err(PyBufferError::new_err("cannot write to read-only buffer"));
} else if mem::size_of_val(source) != self.len_bytes() { } else if mem::size_of_val(source) != self.len_bytes() {
@ -591,9 +586,8 @@ impl<T: Element> PyBuffer<T> {
self.item_count() self.item_count()
))); )));
} }
unsafe {
err::error_on_minusone( err::error_on_minusone(py, unsafe {
py,
ffi::PyBuffer_FromContiguous( ffi::PyBuffer_FromContiguous(
#[cfg(Py_3_11)] #[cfg(Py_3_11)]
&*self.0, &*self.0,
@ -611,9 +605,8 @@ impl<T: Element> PyBuffer<T> {
}, },
self.0.len, self.0.len,
fort as std::os::raw::c_char, fort as std::os::raw::c_char,
),
) )
} })
} }
/// Releases the buffer object, freeing the reference to the Python object /// Releases the buffer object, freeing the reference to the Python object

View file

@ -178,16 +178,18 @@ mod fast_128bit_int_conversion {
} }
impl IntoPy<PyObject> for $rust_type { impl IntoPy<PyObject> for $rust_type {
fn into_py(self, py: Python<'_>) -> PyObject { fn into_py(self, py: Python<'_>) -> PyObject {
unsafe {
// Always use little endian // Always use little endian
let bytes = self.to_le_bytes(); let bytes = self.to_le_bytes();
let obj = ffi::_PyLong_FromByteArray( unsafe {
PyObject::from_owned_ptr(
py,
ffi::_PyLong_FromByteArray(
bytes.as_ptr() as *const std::os::raw::c_uchar, bytes.as_ptr() as *const std::os::raw::c_uchar,
bytes.len(), bytes.len(),
1, 1,
$is_signed, $is_signed,
); ),
PyObject::from_owned_ptr(py, obj) )
} }
} }
@ -199,24 +201,21 @@ mod fast_128bit_int_conversion {
impl<'source> FromPyObject<'source> for $rust_type { impl<'source> FromPyObject<'source> for $rust_type {
fn extract(ob: &'source PyAny) -> PyResult<$rust_type> { fn extract(ob: &'source PyAny) -> PyResult<$rust_type> {
unsafe { let num = unsafe {
let num = ffi::PyNumber_Index(ob.as_ptr()); PyObject::from_owned_ptr_or_err(ob.py(), ffi::PyNumber_Index(ob.as_ptr()))?
if num.is_null() { };
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( crate::err::error_on_minusone(ob.py(), unsafe {
num as *mut ffi::PyLongObject, ffi::_PyLong_AsByteArray(
num.as_ptr() as *mut ffi::PyLongObject,
buffer.as_mut_ptr(), buffer.as_mut_ptr(),
buffer.len(), buffer.len(),
1, 1,
$is_signed, $is_signed,
); )
ffi::Py_DECREF(num); })?;
crate::err::error_on_minusone(ob.py(), ok)?;
Ok(<$rust_type>::from_le_bytes(buffer)) Ok(<$rust_type>::from_le_bytes(buffer))
} }
}
#[cfg(feature = "experimental-inspect")] #[cfg(feature = "experimental-inspect")]
fn type_input() -> TypeInfo { fn type_input() -> TypeInfo {
@ -248,19 +247,17 @@ mod slow_128bit_int_conversion {
impl IntoPy<PyObject> for $rust_type { impl IntoPy<PyObject> for $rust_type {
fn into_py(self, py: Python<'_>) -> PyObject { fn into_py(self, py: Python<'_>) -> PyObject {
let lower = self as u64; let lower = (self as u64).into_py(py);
let upper = (self >> SHIFT) as $half_type; let upper = ((self >> SHIFT) as $half_type).into_py(py);
let shift = SHIFT.into_py(py);
unsafe { unsafe {
let shifted = PyObject::from_owned_ptr( let shifted = PyObject::from_owned_ptr(
py, py,
ffi::PyNumber_Lshift( ffi::PyNumber_Lshift(upper.as_ptr(), shift.as_ptr()),
upper.into_py(py).as_ptr(),
SHIFT.into_py(py).as_ptr(),
),
); );
PyObject::from_owned_ptr( PyObject::from_owned_ptr(
py, py,
ffi::PyNumber_Or(shifted.as_ptr(), lower.into_py(py).as_ptr()), ffi::PyNumber_Or(shifted.as_ptr(), lower.as_ptr()),
) )
} }
} }
@ -280,9 +277,10 @@ mod slow_128bit_int_conversion {
-1 as _, -1 as _,
ffi::PyLong_AsUnsignedLongLongMask(ob.as_ptr()), ffi::PyLong_AsUnsignedLongLongMask(ob.as_ptr()),
)? as $rust_type; )? as $rust_type;
let shift = SHIFT.into_py(py);
let shifted = PyObject::from_owned_ptr_or_err( let shifted = PyObject::from_owned_ptr_or_err(
py, py,
ffi::PyNumber_Rshift(ob.as_ptr(), SHIFT.into_py(py).as_ptr()), ffi::PyNumber_Rshift(ob.as_ptr(), shift.as_ptr()),
)?; )?;
let upper: $half_type = shifted.extract(py)?; let upper: $half_type = shifted.extract(py)?;
Ok((<$rust_type>::from(upper) << SHIFT) | lower) Ok((<$rust_type>::from(upper) << SHIFT) | lower)

View file

@ -1,6 +1,4 @@
use crate::types::PyString; use crate::types::PyString;
#[cfg(windows)]
use crate::PyErr;
use crate::{ use crate::{
ffi, AsPyPointer, FromPyObject, IntoPy, PyAny, PyObject, PyResult, Python, ToPyObject, ffi, AsPyPointer, FromPyObject, IntoPy, PyAny, PyObject, PyResult, Python, ToPyObject,
}; };
@ -92,9 +90,7 @@ impl FromPyObject<'_> for OsString {
// ourselves // ourselves
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 { crate::err::error_on_minusone(ob.py(), size)?;
return Err(PyErr::fetch(ob.py()));
}
let mut buffer = vec![0; size as usize]; let mut buffer = vec![0; size as usize];
let bytes_read = let bytes_read =

View file

@ -9,7 +9,6 @@ use crate::{AsPyPointer, IntoPy, IntoPyPointer, Py, PyAny, PyObject, Python, ToP
use std::borrow::Cow; use std::borrow::Cow;
use std::cell::UnsafeCell; use std::cell::UnsafeCell;
use std::ffi::CString; use std::ffi::CString;
use std::os::raw::c_int;
mod err_state; mod err_state;
mod impls; mod impls;
@ -314,7 +313,7 @@ impl PyErr {
(ptype, pvalue, ptraceback) (ptype, pvalue, ptraceback)
}; };
if ptype.as_ptr() == PanicException::type_object(py).as_ptr() { if ptype.as_ptr() == PanicException::type_object_raw(py).cast() {
let msg: String = pvalue let msg: String = pvalue
.as_ref() .as_ref()
.and_then(|obj| obj.extract(py).ok()) .and_then(|obj| obj.extract(py).ok())
@ -439,15 +438,16 @@ impl PyErr {
where where
T: ToPyObject, T: ToPyObject,
{ {
unsafe { fn inner(err: &PyErr, py: Python<'_>, exc: PyObject) -> bool {
ffi::PyErr_GivenExceptionMatches(self.type_ptr(py), exc.to_object(py).as_ptr()) != 0 (unsafe { ffi::PyErr_GivenExceptionMatches(err.type_ptr(py), exc.as_ptr()) }) != 0
} }
inner(self, py, exc.to_object(py))
} }
/// Returns true if the current exception is instance of `T`. /// Returns true if the current exception is instance of `T`.
#[inline] #[inline]
pub fn is_instance(&self, py: Python<'_>, ty: &PyAny) -> bool { pub fn is_instance(&self, py: Python<'_>, ty: &PyAny) -> bool {
unsafe { ffi::PyErr_GivenExceptionMatches(self.type_ptr(py), ty.as_ptr()) != 0 } (unsafe { ffi::PyErr_GivenExceptionMatches(self.type_ptr(py), ty.as_ptr()) }) != 0
} }
/// Returns true if the current exception is instance of `T`. /// Returns true if the current exception is instance of `T`.
@ -531,16 +531,13 @@ impl PyErr {
/// ``` /// ```
pub fn warn(py: Python<'_>, category: &PyAny, message: &str, stacklevel: i32) -> PyResult<()> { pub fn warn(py: Python<'_>, category: &PyAny, message: &str, stacklevel: i32) -> PyResult<()> {
let message = CString::new(message)?; let message = CString::new(message)?;
unsafe { error_on_minusone(py, unsafe {
error_on_minusone(
py,
ffi::PyErr_WarnEx( ffi::PyErr_WarnEx(
category.as_ptr(), category.as_ptr(),
message.as_ptr(), message.as_ptr(),
stacklevel as ffi::Py_ssize_t, stacklevel as ffi::Py_ssize_t,
),
) )
} })
} }
/// Issues a warning message, with more control over the warning attributes. /// Issues a warning message, with more control over the warning attributes.
@ -571,9 +568,7 @@ impl PyErr {
None => std::ptr::null_mut(), None => std::ptr::null_mut(),
Some(obj) => obj.as_ptr(), Some(obj) => obj.as_ptr(),
}; };
unsafe { error_on_minusone(py, unsafe {
error_on_minusone(
py,
ffi::PyErr_WarnExplicit( ffi::PyErr_WarnExplicit(
category.as_ptr(), category.as_ptr(),
message.as_ptr(), message.as_ptr(),
@ -581,9 +576,8 @@ impl PyErr {
lineno, lineno,
module_ptr, module_ptr,
registry, registry,
),
) )
} })
} }
/// Clone the PyErr. This requires the GIL, which is why PyErr does not implement Clone. /// Clone the PyErr. This requires the GIL, which is why PyErr does not implement Clone.
@ -610,18 +604,21 @@ impl PyErr {
/// Return the cause (either an exception instance, or None, set by `raise ... from ...`) /// Return the cause (either an exception instance, or None, set by `raise ... from ...`)
/// associated with the exception, as accessible from Python through `__cause__`. /// associated with the exception, as accessible from Python through `__cause__`.
pub fn cause(&self, py: Python<'_>) -> Option<PyErr> { pub fn cause(&self, py: Python<'_>) -> Option<PyErr> {
let ptr = unsafe { ffi::PyException_GetCause(self.value(py).as_ptr()) }; let value = self.value(py);
let obj = unsafe { py.from_owned_ptr_or_opt::<PyAny>(ptr) }; let obj =
unsafe { py.from_owned_ptr_or_opt::<PyAny>(ffi::PyException_GetCause(value.as_ptr())) };
obj.map(Self::from_value) obj.map(Self::from_value)
} }
/// Set the cause associated with the exception, pass `None` to clear it. /// Set the cause associated with the exception, pass `None` to clear it.
pub fn set_cause(&self, py: Python<'_>, cause: Option<Self>) { pub fn set_cause(&self, py: Python<'_>, cause: Option<Self>) {
let value = self.value(py);
let cause = cause.map(|err| err.into_value(py));
unsafe { unsafe {
// PyException_SetCause _steals_ a reference to cause, so must use .into_ptr() // PyException_SetCause _steals_ a reference to cause, so must use .into_ptr()
ffi::PyException_SetCause( ffi::PyException_SetCause(
self.value(py).as_ptr(), value.as_ptr(),
cause.map_or(std::ptr::null_mut(), |err| err.into_value(py).into_ptr()), cause.map_or(std::ptr::null_mut(), IntoPyPointer::into_ptr),
); );
} }
} }
@ -790,14 +787,33 @@ pub fn panic_after_error(_py: Python<'_>) -> ! {
/// Returns Ok if the error code is not -1. /// Returns Ok if the error code is not -1.
#[inline] #[inline]
pub fn error_on_minusone(py: Python<'_>, result: c_int) -> PyResult<()> { pub(crate) fn error_on_minusone<T: SignedInteger>(py: Python<'_>, result: T) -> PyResult<()> {
if result != -1 { if result != T::MINUS_ONE {
Ok(()) Ok(())
} else { } else {
Err(PyErr::fetch(py)) Err(PyErr::fetch(py))
} }
} }
pub(crate) trait SignedInteger: Eq {
const MINUS_ONE: Self;
}
macro_rules! impl_signed_integer {
($t:ty) => {
impl SignedInteger for $t {
const MINUS_ONE: Self = -1;
}
};
}
impl_signed_integer!(i8);
impl_signed_integer!(i16);
impl_signed_integer!(i32);
impl_signed_integer!(i64);
impl_signed_integer!(i128);
impl_signed_integer!(isize);
#[inline] #[inline]
fn exceptions_must_derive_from_base_exception(py: Python<'_>) -> PyErr { fn exceptions_must_derive_from_base_exception(py: Python<'_>) -> PyErr {
PyErr::from_state(PyErrState::exceptions_must_derive_from_base_exception(py)) PyErr::from_state(PyErrState::exceptions_must_derive_from_base_exception(py))

View file

@ -71,12 +71,8 @@ fn test_timezone_from_offset() {
use crate::types::PyDelta; use crate::types::PyDelta;
Python::with_gil(|py| { Python::with_gil(|py| {
let tz: &PyAny = unsafe { let delta = PyDelta::new(py, 0, 100, 0, false).unwrap();
PyDateTime_IMPORT(); let tz: &PyAny = unsafe { py.from_borrowed_ptr(PyTimeZone_FromOffset(delta.as_ptr())) };
py.from_borrowed_ptr(PyTimeZone_FromOffset(
PyDelta::new(py, 0, 100, 0, false).unwrap().as_ptr(),
))
};
crate::py_run!( crate::py_run!(
py, py,
tz, tz,
@ -92,11 +88,12 @@ fn test_timezone_from_offset_and_name() {
use crate::types::PyDelta; use crate::types::PyDelta;
Python::with_gil(|py| { Python::with_gil(|py| {
let delta = PyDelta::new(py, 0, 100, 0, false).unwrap();
let tzname = PyString::new(py, "testtz");
let tz: &PyAny = unsafe { let tz: &PyAny = unsafe {
PyDateTime_IMPORT();
py.from_borrowed_ptr(PyTimeZone_FromOffsetAndName( py.from_borrowed_ptr(PyTimeZone_FromOffsetAndName(
PyDelta::new(py, 0, 100, 0, false).unwrap().as_ptr(), delta.as_ptr(),
PyString::new(py, "testtz").as_ptr(), tzname.as_ptr(),
)) ))
}; };
crate::py_run!( crate::py_run!(

View file

@ -714,14 +714,14 @@ mod tests {
}; };
Python::with_gil(|py| { Python::with_gil(|py| {
let args = PyTuple::new(py, Vec::<&PyAny>::new());
let kwargs = [("foo".to_object(py).into_ref(py), 0u8)].into_py_dict(py);
let err = unsafe { let err = unsafe {
function_description function_description
.extract_arguments_tuple_dict::<NoVarargs, NoVarkeywords>( .extract_arguments_tuple_dict::<NoVarargs, NoVarkeywords>(
py, py,
PyTuple::new(py, Vec::<&PyAny>::new()).as_ptr(), args.as_ptr(),
[("foo".to_object(py).into_ref(py), 0u8)] kwargs.as_ptr(),
.into_py_dict(py)
.as_ptr(),
&mut [], &mut [],
) )
.unwrap_err() .unwrap_err()
@ -745,14 +745,14 @@ mod tests {
}; };
Python::with_gil(|py| { Python::with_gil(|py| {
let args = PyTuple::new(py, Vec::<&PyAny>::new());
let kwargs = [(1u8.to_object(py).into_ref(py), 1u8)].into_py_dict(py);
let err = unsafe { let err = unsafe {
function_description function_description
.extract_arguments_tuple_dict::<NoVarargs, NoVarkeywords>( .extract_arguments_tuple_dict::<NoVarargs, NoVarkeywords>(
py, py,
PyTuple::new(py, Vec::<&PyAny>::new()).as_ptr(), args.as_ptr(),
[(1u8.to_object(py).into_ref(py), 1u8)] kwargs.as_ptr(),
.into_py_dict(py)
.as_ptr(),
&mut [], &mut [],
) )
.unwrap_err() .unwrap_err()
@ -776,11 +776,12 @@ mod tests {
}; };
Python::with_gil(|py| { Python::with_gil(|py| {
let args = PyTuple::new(py, Vec::<&PyAny>::new());
let mut output = [None, None]; let mut output = [None, None];
let err = unsafe { let err = unsafe {
function_description.extract_arguments_tuple_dict::<NoVarargs, NoVarkeywords>( function_description.extract_arguments_tuple_dict::<NoVarargs, NoVarkeywords>(
py, py,
PyTuple::new(py, Vec::<&PyAny>::new()).as_ptr(), args.as_ptr(),
std::ptr::null_mut(), std::ptr::null_mut(),
&mut output, &mut output,
) )

View file

@ -202,8 +202,9 @@ fn initialize_tp_dict(
// We hold the GIL: the dictionary update can be considered atomic from // We hold the GIL: the dictionary update can be considered atomic from
// the POV of other threads. // the POV of other threads.
for (key, val) in items { for (key, val) in items {
let ret = unsafe { ffi::PyObject_SetAttrString(type_object, key.as_ptr(), val.into_ptr()) }; crate::err::error_on_minusone(py, unsafe {
crate::err::error_on_minusone(py, ret)?; ffi::PyObject_SetAttrString(type_object, key.as_ptr(), val.into_ptr())
})?;
} }
Ok(()) Ok(())
} }

View file

@ -2,7 +2,7 @@ use crate::{derive_utils::PyFunctionArguments, types::PyCFunction, PyResult};
pub use crate::impl_::pymethods::PyMethodDef; pub use crate::impl_::pymethods::PyMethodDef;
pub fn wrap_pyfunction_impl<'a>( pub fn _wrap_pyfunction<'a>(
method_def: &PyMethodDef, method_def: &PyMethodDef,
py_or_module: impl Into<PyFunctionArguments<'a>>, py_or_module: impl Into<PyFunctionArguments<'a>>,
) -> PyResult<&'a PyCFunction> { ) -> PyResult<&'a PyCFunction> {

View file

@ -247,7 +247,7 @@ impl PySetterDef {
/// Calls an implementation of __traverse__ for tp_traverse /// Calls an implementation of __traverse__ for tp_traverse
#[doc(hidden)] #[doc(hidden)]
pub unsafe fn call_traverse_impl<T>( pub unsafe fn _call_traverse<T>(
slf: *mut ffi::PyObject, slf: *mut ffi::PyObject,
impl_: fn(&T, PyVisit<'_>) -> Result<(), PyTraverseError>, impl_: fn(&T, PyVisit<'_>) -> Result<(), PyTraverseError>,
visit: ffi::visitproc, visit: ffi::visitproc,

View file

@ -18,7 +18,7 @@ use crate::{
pub unsafe fn module_init( pub unsafe fn module_init(
f: for<'py> unsafe fn(Python<'py>) -> PyResult<Py<PyModule>>, f: for<'py> unsafe fn(Python<'py>) -> PyResult<Py<PyModule>>,
) -> *mut ffi::PyObject { ) -> *mut ffi::PyObject {
trampoline_inner(|py| f(py).map(|module| module.into_ptr())) trampoline(|py| f(py).map(|module| module.into_ptr()))
} }
#[inline] #[inline]
@ -28,7 +28,7 @@ pub unsafe fn noargs(
f: for<'py> unsafe fn(Python<'py>, *mut ffi::PyObject) -> PyResult<*mut ffi::PyObject>, f: for<'py> unsafe fn(Python<'py>, *mut ffi::PyObject) -> PyResult<*mut ffi::PyObject>,
) -> *mut ffi::PyObject { ) -> *mut ffi::PyObject {
debug_assert!(args.is_null()); debug_assert!(args.is_null());
trampoline_inner(|py| f(py, slf)) trampoline(|py| f(py, slf))
} }
macro_rules! trampoline { macro_rules! trampoline {
@ -38,7 +38,7 @@ macro_rules! trampoline {
$($arg_names: $arg_types,)* $($arg_names: $arg_types,)*
f: for<'py> unsafe fn (Python<'py>, $($arg_types),*) -> PyResult<$ret>, f: for<'py> unsafe fn (Python<'py>, $($arg_types),*) -> PyResult<$ret>,
) -> $ret { ) -> $ret {
trampoline_inner(|py| f(py, $($arg_names,)*)) trampoline(|py| f(py, $($arg_names,)*))
} }
} }
} }
@ -131,7 +131,7 @@ pub unsafe fn releasebufferproc(
buf: *mut ffi::Py_buffer, buf: *mut ffi::Py_buffer,
f: for<'py> unsafe fn(Python<'py>, *mut ffi::PyObject, *mut ffi::Py_buffer) -> PyResult<()>, f: for<'py> unsafe fn(Python<'py>, *mut ffi::PyObject, *mut ffi::Py_buffer) -> PyResult<()>,
) { ) {
trampoline_inner_unraisable(|py| f(py, slf, buf), slf) trampoline_unraisable(|py| f(py, slf, buf), slf)
} }
#[inline] #[inline]
@ -143,7 +143,7 @@ pub(crate) unsafe fn dealloc(
// so pass null_mut() to the context. // so pass null_mut() to the context.
// //
// (Note that we don't allow the implementation `f` to fail.) // (Note that we don't allow the implementation `f` to fail.)
trampoline_inner_unraisable( trampoline_unraisable(
|py| { |py| {
f(py, slf); f(py, slf);
Ok(()) Ok(())
@ -168,7 +168,7 @@ trampoline!(
/// Panics during execution are trapped so that they don't propagate through any /// Panics during execution are trapped so that they don't propagate through any
/// outer FFI boundary. /// outer FFI boundary.
#[inline] #[inline]
pub(crate) fn trampoline_inner<F, R>(body: F) -> R pub(crate) fn trampoline<F, R>(body: F) -> R
where where
F: for<'py> FnOnce(Python<'py>) -> PyResult<R> + UnwindSafe, F: for<'py> FnOnce(Python<'py>) -> PyResult<R> + UnwindSafe,
R: PyCallbackOutput, R: PyCallbackOutput,
@ -214,7 +214,7 @@ where
/// ///
/// ctx must be either a valid ffi::PyObject or NULL /// ctx must be either a valid ffi::PyObject or NULL
#[inline] #[inline]
unsafe fn trampoline_inner_unraisable<F>(body: F, ctx: *mut ffi::PyObject) unsafe fn trampoline_unraisable<F>(body: F, ctx: *mut ffi::PyObject)
where where
F: for<'py> FnOnce(Python<'py>) -> PyResult<()> + UnwindSafe, F: for<'py> FnOnce(Python<'py>) -> PyResult<()> + UnwindSafe,
{ {

View file

@ -650,12 +650,9 @@ impl<T> Py<T> {
let attr_name = attr_name.into_py(py); let attr_name = attr_name.into_py(py);
let value = value.into_py(py); let value = value.into_py(py);
unsafe { err::error_on_minusone(py, unsafe {
err::error_on_minusone( ffi::PyObject_SetAttr(self.as_ptr(), attr_name.as_ptr(), value.as_ptr())
py, })
ffi::PyObject_SetAttr(self.as_ptr(), attr_name.as_ptr(), value.as_ptr()),
)
}
} }
/// Calls the object. /// Calls the object.

View file

@ -125,12 +125,12 @@ macro_rules! wrap_pyfunction {
($function:path) => { ($function:path) => {
&|py_or_module| { &|py_or_module| {
use $function as wrapped_pyfunction; use $function as wrapped_pyfunction;
$crate::impl_::pyfunction::wrap_pyfunction_impl(&wrapped_pyfunction::DEF, py_or_module) $crate::impl_::pyfunction::_wrap_pyfunction(&wrapped_pyfunction::DEF, py_or_module)
} }
}; };
($function:path, $py_or_module:expr) => {{ ($function:path, $py_or_module:expr) => {{
use $function as wrapped_pyfunction; use $function as wrapped_pyfunction;
$crate::impl_::pyfunction::wrap_pyfunction_impl(&wrapped_pyfunction::DEF, $py_or_module) $crate::impl_::pyfunction::_wrap_pyfunction(&wrapped_pyfunction::DEF, $py_or_module)
}}; }};
} }

View file

@ -876,8 +876,7 @@ impl<'py> Python<'py> {
/// [1]: https://docs.python.org/3/c-api/exceptions.html?highlight=pyerr_checksignals#c.PyErr_CheckSignals /// [1]: https://docs.python.org/3/c-api/exceptions.html?highlight=pyerr_checksignals#c.PyErr_CheckSignals
/// [2]: https://docs.python.org/3/library/signal.html /// [2]: https://docs.python.org/3/library/signal.html
pub fn check_signals(self) -> PyResult<()> { pub fn check_signals(self) -> PyResult<()> {
let v = unsafe { ffi::PyErr_CheckSignals() }; err::error_on_minusone(self, unsafe { ffi::PyErr_CheckSignals() })
err::error_on_minusone(self, v)
} }
/// Create a new pool for managing PyO3's owned references. /// Create a new pool for managing PyO3's owned references.

View file

@ -7,7 +7,7 @@ use crate::{
}, },
impl_::{ impl_::{
pymethods::{get_doc, get_name, Getter, Setter}, pymethods::{get_doc, get_name, Getter, Setter},
trampoline::trampoline_inner, trampoline::trampoline,
}, },
types::PyType, types::PyType,
Py, PyClass, PyGetterDef, PyMethodDefType, PyResult, PySetterDef, PyTypeInfo, Python, Py, PyClass, PyGetterDef, PyMethodDefType, PyResult, PySetterDef, PyTypeInfo, Python,
@ -413,7 +413,7 @@ unsafe extern "C" fn no_constructor_defined(
_args: *mut ffi::PyObject, _args: *mut ffi::PyObject,
_kwds: *mut ffi::PyObject, _kwds: *mut ffi::PyObject,
) -> *mut ffi::PyObject { ) -> *mut ffi::PyObject {
trampoline_inner(|_| { trampoline(|_| {
Err(crate::exceptions::PyTypeError::new_err( Err(crate::exceptions::PyTypeError::new_err(
"No constructor defined", "No constructor defined",
)) ))
@ -513,7 +513,7 @@ impl GetSetDefType {
) -> *mut ffi::PyObject { ) -> *mut ffi::PyObject {
// Safety: PyO3 sets the closure when constructing the ffi getter so this cast should always be valid // Safety: PyO3 sets the closure when constructing the ffi getter so this cast should always be valid
let getter: Getter = std::mem::transmute(closure); let getter: Getter = std::mem::transmute(closure);
trampoline_inner(|py| getter(py, slf)) trampoline(|py| getter(py, slf))
} }
(Some(getter), None, closure as Getter as _) (Some(getter), None, closure as Getter as _)
} }
@ -525,7 +525,7 @@ impl GetSetDefType {
) -> c_int { ) -> c_int {
// Safety: PyO3 sets the closure when constructing the ffi setter so this cast should always be valid // Safety: PyO3 sets the closure when constructing the ffi setter so this cast should always be valid
let setter: Setter = std::mem::transmute(closure); let setter: Setter = std::mem::transmute(closure);
trampoline_inner(|py| setter(py, slf, value)) trampoline(|py| setter(py, slf, value))
} }
(None, Some(setter), closure as Setter as _) (None, Some(setter), closure as Setter as _)
} }
@ -535,7 +535,7 @@ impl GetSetDefType {
closure: *mut c_void, closure: *mut c_void,
) -> *mut ffi::PyObject { ) -> *mut ffi::PyObject {
let getset: &GetterAndSetter = &*(closure as *const GetterAndSetter); let getset: &GetterAndSetter = &*(closure as *const GetterAndSetter);
trampoline_inner(|py| (getset.getter)(py, slf)) trampoline(|py| (getset.getter)(py, slf))
} }
unsafe extern "C" fn getset_setter( unsafe extern "C" fn getset_setter(
@ -544,7 +544,7 @@ impl GetSetDefType {
closure: *mut c_void, closure: *mut c_void,
) -> c_int { ) -> c_int {
let getset: &GetterAndSetter = &*(closure as *const GetterAndSetter); let getset: &GetterAndSetter = &*(closure as *const GetterAndSetter);
trampoline_inner(|py| (getset.setter)(py, slf, value)) trampoline(|py| (getset.setter)(py, slf, value))
} }
( (
Some(getset_getter), Some(getset_getter),

View file

@ -227,14 +227,14 @@ impl PyAny {
N: IntoPy<Py<PyString>>, N: IntoPy<Py<PyString>>,
V: ToPyObject, V: ToPyObject,
{ {
let py = self.py(); fn inner(any: &PyAny, attr_name: Py<PyString>, value: PyObject) -> PyResult<()> {
let attr_name = attr_name.into_py(py); err::error_on_minusone(any.py(), unsafe {
let value = value.to_object(py); ffi::PyObject_SetAttr(any.as_ptr(), attr_name.as_ptr(), value.as_ptr())
})
unsafe {
let ret = ffi::PyObject_SetAttr(self.as_ptr(), attr_name.as_ptr(), value.as_ptr());
err::error_on_minusone(py, ret)
} }
let py = self.py();
inner(self, attr_name.into_py(py), value.to_object(py))
} }
/// Deletes an attribute. /// Deletes an attribute.
@ -247,13 +247,13 @@ impl PyAny {
where where
N: IntoPy<Py<PyString>>, N: IntoPy<Py<PyString>>,
{ {
let py = self.py(); fn inner(any: &PyAny, attr_name: Py<PyString>) -> PyResult<()> {
let attr_name = attr_name.into_py(py); err::error_on_minusone(any.py(), unsafe {
ffi::PyObject_DelAttr(any.as_ptr(), attr_name.as_ptr())
unsafe { })
let ret = ffi::PyObject_DelAttr(self.as_ptr(), attr_name.as_ptr());
err::error_on_minusone(py, ret)
} }
inner(self, attr_name.into_py(self.py()))
} }
/// Returns an [`Ordering`] between `self` and `other`. /// Returns an [`Ordering`] between `self` and `other`.
@ -369,15 +369,19 @@ impl PyAny {
where where
O: ToPyObject, O: ToPyObject,
{ {
fn inner(slf: &PyAny, other: PyObject, compare_op: CompareOp) -> PyResult<&PyAny> {
unsafe { unsafe {
self.py().from_owned_ptr_or_err(ffi::PyObject_RichCompare( slf.py().from_owned_ptr_or_err(ffi::PyObject_RichCompare(
self.as_ptr(), slf.as_ptr(),
other.to_object(self.py()).as_ptr(), other.as_ptr(),
compare_op as c_int, compare_op as c_int,
)) ))
} }
} }
inner(self, other.to_object(self.py()), compare_op)
}
/// Tests whether this object is less than another. /// Tests whether this object is less than another.
/// ///
/// This is equivalent to the Python expression `self < other`. /// This is equivalent to the Python expression `self < other`.
@ -767,14 +771,16 @@ impl PyAny {
where where
K: ToPyObject, K: ToPyObject,
{ {
fn inner(slf: &PyAny, key: PyObject) -> PyResult<&PyAny> {
unsafe { unsafe {
self.py().from_owned_ptr_or_err(ffi::PyObject_GetItem( slf.py()
self.as_ptr(), .from_owned_ptr_or_err(ffi::PyObject_GetItem(slf.as_ptr(), key.as_ptr()))
key.to_object(self.py()).as_ptr(),
))
} }
} }
inner(self, key.to_object(self.py()))
}
/// Sets a collection item value. /// Sets a collection item value.
/// ///
/// This is equivalent to the Python expression `self[key] = value`. /// This is equivalent to the Python expression `self[key] = value`.
@ -783,17 +789,14 @@ impl PyAny {
K: ToPyObject, K: ToPyObject,
V: ToPyObject, V: ToPyObject,
{ {
let py = self.py(); fn inner(slf: &PyAny, key: PyObject, value: PyObject) -> PyResult<()> {
unsafe { err::error_on_minusone(slf.py(), unsafe {
err::error_on_minusone( ffi::PyObject_SetItem(slf.as_ptr(), key.as_ptr(), value.as_ptr())
py, })
ffi::PyObject_SetItem(
self.as_ptr(),
key.to_object(py).as_ptr(),
value.to_object(py).as_ptr(),
),
)
} }
let py = self.py();
inner(self, key.to_object(py), value.to_object(py))
} }
/// Deletes an item from the collection. /// Deletes an item from the collection.
@ -803,12 +806,13 @@ impl PyAny {
where where
K: ToPyObject, K: ToPyObject,
{ {
unsafe { fn inner(slf: &PyAny, key: PyObject) -> PyResult<()> {
err::error_on_minusone( err::error_on_minusone(slf.py(), unsafe {
self.py(), ffi::PyObject_DelItem(slf.as_ptr(), key.as_ptr())
ffi::PyObject_DelItem(self.as_ptr(), key.to_object(self.py()).as_ptr()), })
)
} }
inner(self, key.to_object(self.py()))
} }
/// Takes an object and returns an iterator for it. /// Takes an object and returns an iterator for it.
@ -943,24 +947,18 @@ impl PyAny {
/// This is equivalent to the Python expression `hash(self)`. /// This is equivalent to the Python expression `hash(self)`.
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 { crate::err::error_on_minusone(self.py(), v)?;
Err(PyErr::fetch(self.py()))
} else {
Ok(v) Ok(v)
} }
}
/// Returns the length of the sequence or mapping. /// Returns the length of the sequence or mapping.
/// ///
/// This is equivalent to the Python expression `len(self)`. /// This is equivalent to the Python expression `len(self)`.
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 { crate::err::error_on_minusone(self.py(), v)?;
Err(PyErr::fetch(self.py()))
} else {
Ok(v as usize) Ok(v as usize)
} }
}
/// Returns the list of attributes of this object. /// Returns the list of attributes of this object.
/// ///

View file

@ -68,15 +68,12 @@ impl PyDict {
/// this keeps the last entry seen. /// this keeps the last entry seen.
#[cfg(not(PyPy))] #[cfg(not(PyPy))]
pub fn from_sequence(py: Python<'_>, seq: PyObject) -> PyResult<&PyDict> { pub fn from_sequence(py: Python<'_>, seq: PyObject) -> PyResult<&PyDict> {
unsafe { let dict = Self::new(py);
let dict = py.from_owned_ptr::<PyDict>(ffi::PyDict_New()); err::error_on_minusone(py, unsafe {
err::error_on_minusone( ffi::PyDict_MergeFromSeq2(dict.into_ptr(), seq.into_ptr(), 1)
py, })?;
ffi::PyDict_MergeFromSeq2(dict.into_ptr(), seq.into_ptr(), 1),
)?;
Ok(dict) Ok(dict)
} }
}
/// Returns a new dictionary that contains the same key-value pairs as self. /// Returns a new dictionary that contains the same key-value pairs as self.
/// ///
@ -124,13 +121,15 @@ impl PyDict {
where where
K: ToPyObject, K: ToPyObject,
{ {
unsafe { fn inner(dict: &PyDict, key: PyObject) -> PyResult<bool> {
match ffi::PyDict_Contains(self.as_ptr(), key.to_object(self.py()).as_ptr()) { match unsafe { ffi::PyDict_Contains(dict.as_ptr(), key.as_ptr()) } {
1 => Ok(true), 1 => Ok(true),
0 => Ok(false), 0 => Ok(false),
_ => Err(PyErr::fetch(self.py())), _ => Err(PyErr::fetch(dict.py())),
} }
} }
inner(self, key.to_object(self.py()))
} }
/// Gets an item from the dictionary. /// Gets an item from the dictionary.
@ -142,17 +141,20 @@ impl PyDict {
where where
K: ToPyObject, K: ToPyObject,
{ {
self.get_item_impl(key.to_object(self.py())) fn inner(dict: &PyDict, key: PyObject) -> Option<&PyAny> {
} let py = dict.py();
fn get_item_impl(&self, key: PyObject) -> Option<&PyAny> {
let py = self.py();
unsafe {
let ptr = ffi::PyDict_GetItem(self.as_ptr(), key.as_ptr());
// PyDict_GetItem returns a borrowed ptr, must make it owned for safety (see #890). // PyDict_GetItem returns a borrowed ptr, must make it owned for safety (see #890).
// PyObject::from_borrowed_ptr_or_opt will take ownership in this way. // PyObject::from_borrowed_ptr_or_opt will take ownership in this way.
PyObject::from_borrowed_ptr_or_opt(py, ptr).map(|pyobject| pyobject.into_ref(py)) unsafe {
PyObject::from_borrowed_ptr_or_opt(
py,
ffi::PyDict_GetItem(dict.as_ptr(), key.as_ptr()),
)
} }
.map(|pyobject| pyobject.into_ref(py))
}
inner(self, key.to_object(self.py()))
} }
/// Gets an item from the dictionary, /// Gets an item from the dictionary,
@ -164,20 +166,22 @@ impl PyDict {
where where
K: ToPyObject, K: ToPyObject,
{ {
self.get_item_with_error_impl(key.to_object(self.py())) fn inner(dict: &PyDict, key: PyObject) -> PyResult<Option<&PyAny>> {
} let py = dict.py();
fn get_item_with_error_impl(&self, key: PyObject) -> PyResult<Option<&PyAny>> {
let py = self.py();
unsafe {
let ptr = ffi::PyDict_GetItemWithError(self.as_ptr(), key.as_ptr());
// PyDict_GetItemWithError returns a borrowed ptr, must make it owned for safety (see #890). // PyDict_GetItemWithError returns a borrowed ptr, must make it owned for safety (see #890).
// PyObject::from_borrowed_ptr_or_opt will take ownership in this way. // PyObject::from_borrowed_ptr_or_opt will take ownership in this way.
PyObject::from_borrowed_ptr_or_opt(py, ptr) unsafe {
PyObject::from_borrowed_ptr_or_opt(
py,
ffi::PyDict_GetItemWithError(dict.as_ptr(), key.as_ptr()),
)
}
.map(|pyobject| Ok(pyobject.into_ref(py))) .map(|pyobject| Ok(pyobject.into_ref(py)))
.or_else(|| PyErr::take(py).map(Err)) .or_else(|| PyErr::take(py).map(Err))
.transpose() .transpose()
} }
inner(self, key.to_object(self.py()))
} }
/// Sets an item value. /// Sets an item value.
@ -188,17 +192,14 @@ impl PyDict {
K: ToPyObject, K: ToPyObject,
V: ToPyObject, V: ToPyObject,
{ {
let py = self.py(); fn inner(dict: &PyDict, key: PyObject, value: PyObject) -> PyResult<()> {
unsafe { err::error_on_minusone(dict.py(), unsafe {
err::error_on_minusone( ffi::PyDict_SetItem(dict.as_ptr(), key.as_ptr(), value.as_ptr())
py, })
ffi::PyDict_SetItem(
self.as_ptr(),
key.to_object(py).as_ptr(),
value.to_object(py).as_ptr(),
),
)
} }
let py = self.py();
inner(self, key.to_object(py), value.to_object(py))
} }
/// Deletes an item. /// Deletes an item.
@ -208,13 +209,13 @@ impl PyDict {
where where
K: ToPyObject, K: ToPyObject,
{ {
let py = self.py(); fn inner(dict: &PyDict, key: PyObject) -> PyResult<()> {
unsafe { err::error_on_minusone(dict.py(), unsafe {
err::error_on_minusone( ffi::PyDict_DelItem(dict.as_ptr(), key.as_ptr())
py, })
ffi::PyDict_DelItem(self.as_ptr(), key.to_object(py).as_ptr()),
)
} }
inner(self, key.to_object(self.py()))
} }
/// Returns a list of dict keys. /// Returns a list of dict keys.
@ -269,7 +270,9 @@ impl PyDict {
/// to use `self.update(other.as_mapping())`, note: `PyDict::as_mapping` is a zero-cost conversion. /// to use `self.update(other.as_mapping())`, note: `PyDict::as_mapping` is a zero-cost conversion.
pub fn update(&self, other: &PyMapping) -> PyResult<()> { pub fn update(&self, other: &PyMapping) -> PyResult<()> {
let py = self.py(); let py = self.py();
unsafe { err::error_on_minusone(py, ffi::PyDict_Update(self.as_ptr(), other.as_ptr())) } err::error_on_minusone(py, unsafe {
ffi::PyDict_Update(self.as_ptr(), other.as_ptr())
})
} }
/// Add key/value pairs from another dictionary to this one only when they do not exist in this. /// Add key/value pairs from another dictionary to this one only when they do not exist in this.
@ -282,7 +285,9 @@ impl PyDict {
/// so should have the same performance as `update`. /// so should have the same performance as `update`.
pub fn update_if_missing(&self, other: &PyMapping) -> PyResult<()> { pub fn update_if_missing(&self, other: &PyMapping) -> PyResult<()> {
let py = self.py(); let py = self.py();
unsafe { err::error_on_minusone(py, ffi::PyDict_Merge(self.as_ptr(), other.as_ptr(), 0)) } err::error_on_minusone(py, unsafe {
ffi::PyDict_Merge(self.as_ptr(), other.as_ptr(), 0)
})
} }
} }

View file

@ -28,12 +28,15 @@ impl<'py> PyFrozenSetBuilder<'py> {
where where
K: ToPyObject, K: ToPyObject,
{ {
let py = self.py_frozen_set.py(); fn inner(frozenset: &PyFrozenSet, key: PyObject) -> PyResult<()> {
err::error_on_minusone(py, unsafe { err::error_on_minusone(frozenset.py(), unsafe {
ffi::PySet_Add(self.py_frozen_set.as_ptr(), key.to_object(py).as_ptr()) ffi::PySet_Add(frozenset.as_ptr(), key.as_ptr())
}) })
} }
inner(self.py_frozen_set, key.to_object(self.py_frozen_set.py()))
}
/// Finish building the set and take ownership of its current value /// Finish building the set and take ownership of its current value
pub fn finalize(self) -> &'py PyFrozenSet { pub fn finalize(self) -> &'py PyFrozenSet {
self.py_frozen_set self.py_frozen_set
@ -94,13 +97,15 @@ impl PyFrozenSet {
where where
K: ToPyObject, K: ToPyObject,
{ {
unsafe { fn inner(frozenset: &PyFrozenSet, key: PyObject) -> PyResult<bool> {
match ffi::PySet_Contains(self.as_ptr(), key.to_object(self.py()).as_ptr()) { match unsafe { ffi::PySet_Contains(frozenset.as_ptr(), key.as_ptr()) } {
1 => Ok(true), 1 => Ok(true),
0 => Ok(false), 0 => Ok(false),
_ => Err(PyErr::fetch(self.py())), _ => Err(PyErr::fetch(frozenset.py())),
} }
} }
inner(self, key.to_object(self.py()))
} }
/// Returns an iterator of values in this frozen set. /// Returns an iterator of values in this frozen set.
@ -197,7 +202,7 @@ pub(crate) fn new_from_iter<T: ToPyObject>(
py: Python<'_>, py: Python<'_>,
elements: impl IntoIterator<Item = T>, elements: impl IntoIterator<Item = T>,
) -> PyResult<Py<PyFrozenSet>> { ) -> PyResult<Py<PyFrozenSet>> {
fn new_from_iter_inner( fn inner(
py: Python<'_>, py: Python<'_>,
elements: &mut dyn Iterator<Item = PyObject>, elements: &mut dyn Iterator<Item = PyObject>,
) -> PyResult<Py<PyFrozenSet>> { ) -> PyResult<Py<PyFrozenSet>> {
@ -208,16 +213,14 @@ pub(crate) fn new_from_iter<T: ToPyObject>(
let ptr = set.as_ptr(); let ptr = set.as_ptr();
for obj in elements { for obj in elements {
unsafe { err::error_on_minusone(py, unsafe { ffi::PySet_Add(ptr, obj.as_ptr()) })?;
err::error_on_minusone(py, ffi::PySet_Add(ptr, obj.as_ptr()))?;
}
} }
Ok(set) Ok(set)
} }
let mut iter = elements.into_iter().map(|e| e.to_object(py)); let mut iter = elements.into_iter().map(|e| e.to_object(py));
new_from_iter_inner(py, &mut iter) inner(py, &mut iter)
} }
#[cfg(test)] #[cfg(test)]

View file

@ -167,16 +167,13 @@ impl PyList {
where where
I: ToPyObject, I: ToPyObject,
{ {
unsafe { fn inner(list: &PyList, index: usize, item: PyObject) -> PyResult<()> {
err::error_on_minusone( err::error_on_minusone(list.py(), unsafe {
self.py(), ffi::PyList_SetItem(list.as_ptr(), get_ssize_index(index), item.into_ptr())
ffi::PyList_SetItem( })
self.as_ptr(),
get_ssize_index(index),
item.to_object(self.py()).into_ptr(),
),
)
} }
inner(self, index, item.to_object(self.py()))
} }
/// Deletes the `index`th element of self. /// Deletes the `index`th element of self.
@ -192,17 +189,14 @@ impl PyList {
/// This is equivalent to the Python statement `self[low:high] = v`. /// This is equivalent to the Python statement `self[low:high] = v`.
#[inline] #[inline]
pub fn set_slice(&self, low: usize, high: usize, seq: &PyAny) -> PyResult<()> { pub fn set_slice(&self, low: usize, high: usize, seq: &PyAny) -> PyResult<()> {
unsafe { err::error_on_minusone(self.py(), unsafe {
err::error_on_minusone(
self.py(),
ffi::PyList_SetSlice( ffi::PyList_SetSlice(
self.as_ptr(), self.as_ptr(),
get_ssize_index(low), get_ssize_index(low),
get_ssize_index(high), get_ssize_index(high),
seq.as_ptr(), seq.as_ptr(),
),
) )
} })
} }
/// Deletes the slice from `low` to `high` from `self`. /// Deletes the slice from `low` to `high` from `self`.
@ -218,13 +212,13 @@ impl PyList {
where where
I: ToPyObject, I: ToPyObject,
{ {
let py = self.py(); fn inner(list: &PyList, item: PyObject) -> PyResult<()> {
unsafe { err::error_on_minusone(list.py(), unsafe {
err::error_on_minusone( ffi::PyList_Append(list.as_ptr(), item.as_ptr())
py, })
ffi::PyList_Append(self.as_ptr(), item.to_object(py).as_ptr()),
)
} }
inner(self, item.to_object(self.py()))
} }
/// Inserts an item at the specified index. /// Inserts an item at the specified index.
@ -234,17 +228,13 @@ impl PyList {
where where
I: ToPyObject, I: ToPyObject,
{ {
let py = self.py(); fn inner(list: &PyList, index: usize, item: PyObject) -> PyResult<()> {
unsafe { err::error_on_minusone(list.py(), unsafe {
err::error_on_minusone( ffi::PyList_Insert(list.as_ptr(), get_ssize_index(index), item.as_ptr())
py, })
ffi::PyList_Insert(
self.as_ptr(),
get_ssize_index(index),
item.to_object(py).as_ptr(),
),
)
} }
inner(self, index, item.to_object(self.py()))
} }
/// Determines if self contains `value`. /// Determines if self contains `value`.
@ -279,12 +269,12 @@ impl PyList {
/// Sorts the list in-place. Equivalent to the Python expression `l.sort()`. /// Sorts the list in-place. Equivalent to the Python expression `l.sort()`.
pub fn sort(&self) -> PyResult<()> { pub fn sort(&self) -> PyResult<()> {
unsafe { err::error_on_minusone(self.py(), ffi::PyList_Sort(self.as_ptr())) } err::error_on_minusone(self.py(), unsafe { ffi::PyList_Sort(self.as_ptr()) })
} }
/// Reverses the list in-place. Equivalent to the Python expression `l.reverse()`. /// Reverses the list in-place. Equivalent to the Python expression `l.reverse()`.
pub fn reverse(&self) -> PyResult<()> { pub fn reverse(&self) -> PyResult<()> {
unsafe { err::error_on_minusone(self.py(), ffi::PyList_Reverse(self.as_ptr())) } err::error_on_minusone(self.py(), unsafe { ffi::PyList_Reverse(self.as_ptr()) })
} }
/// Return a new tuple containing the contents of the list; equivalent to the Python expression `tuple(list)`. /// Return a new tuple containing the contents of the list; equivalent to the Python expression `tuple(list)`.

View file

@ -1,4 +1,4 @@
use crate::err::{PyDowncastError, PyErr, PyResult}; use crate::err::{PyDowncastError, PyResult};
use crate::sync::GILOnceCell; use crate::sync::GILOnceCell;
use crate::type_object::PyTypeInfo; use crate::type_object::PyTypeInfo;
use crate::types::{PyAny, PyDict, PySequence, PyType}; use crate::types::{PyAny, PyDict, PySequence, PyType};
@ -17,12 +17,9 @@ impl PyMapping {
#[inline] #[inline]
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 { crate::err::error_on_minusone(self.py(), v)?;
Err(PyErr::fetch(self.py()))
} else {
Ok(v as usize) Ok(v as usize)
} }
}
/// Returns whether the mapping is empty. /// Returns whether the mapping is empty.
#[inline] #[inline]

View file

@ -6,7 +6,7 @@ use crate::internal_tricks::get_ssize_index;
use crate::sync::GILOnceCell; use crate::sync::GILOnceCell;
use crate::type_object::PyTypeInfo; use crate::type_object::PyTypeInfo;
use crate::types::{PyAny, PyList, PyString, PyTuple, PyType}; use crate::types::{PyAny, PyList, PyString, PyTuple, PyType};
use crate::{ffi, PyNativeType, ToPyObject}; use crate::{ffi, PyNativeType, PyObject, ToPyObject};
use crate::{AsPyPointer, IntoPyPointer, Py, Python}; use crate::{AsPyPointer, IntoPyPointer, Py, Python};
use crate::{FromPyObject, PyTryFrom}; use crate::{FromPyObject, PyTryFrom};
@ -23,12 +23,9 @@ impl PySequence {
#[inline] #[inline]
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 { crate::err::error_on_minusone(self.py(), v)?;
Err(PyErr::fetch(self.py()))
} else {
Ok(v as usize) Ok(v as usize)
} }
}
/// Returns whether the sequence is empty. /// Returns whether the sequence is empty.
#[inline] #[inline]
@ -128,17 +125,13 @@ impl PySequence {
where where
I: ToPyObject, I: ToPyObject,
{ {
let py = self.py(); fn inner(seq: &PySequence, i: usize, item: PyObject) -> PyResult<()> {
unsafe { err::error_on_minusone(seq.py(), unsafe {
err::error_on_minusone( ffi::PySequence_SetItem(seq.as_ptr(), get_ssize_index(i), item.as_ptr())
py, })
ffi::PySequence_SetItem(
self.as_ptr(),
get_ssize_index(i),
item.to_object(py).as_ptr(),
),
)
} }
inner(self, i, item.to_object(self.py()))
} }
/// Deletes the `i`th element of self. /// Deletes the `i`th element of self.
@ -146,12 +139,9 @@ impl PySequence {
/// This is equivalent to the Python statement `del self[i]`. /// This is equivalent to the Python statement `del self[i]`.
#[inline] #[inline]
pub fn del_item(&self, i: usize) -> PyResult<()> { pub fn del_item(&self, i: usize) -> PyResult<()> {
unsafe { err::error_on_minusone(self.py(), unsafe {
err::error_on_minusone( ffi::PySequence_DelItem(self.as_ptr(), get_ssize_index(i))
self.py(), })
ffi::PySequence_DelItem(self.as_ptr(), get_ssize_index(i)),
)
}
} }
/// Assigns the sequence `v` to the slice of `self` from `i1` to `i2`. /// Assigns the sequence `v` to the slice of `self` from `i1` to `i2`.
@ -159,17 +149,14 @@ impl PySequence {
/// This is equivalent to the Python statement `self[i1:i2] = v`. /// This is equivalent to the Python statement `self[i1:i2] = v`.
#[inline] #[inline]
pub fn set_slice(&self, i1: usize, i2: usize, v: &PyAny) -> PyResult<()> { pub fn set_slice(&self, i1: usize, i2: usize, v: &PyAny) -> PyResult<()> {
unsafe { err::error_on_minusone(self.py(), unsafe {
err::error_on_minusone(
self.py(),
ffi::PySequence_SetSlice( ffi::PySequence_SetSlice(
self.as_ptr(), self.as_ptr(),
get_ssize_index(i1), get_ssize_index(i1),
get_ssize_index(i2), get_ssize_index(i2),
v.as_ptr(), v.as_ptr(),
),
) )
} })
} }
/// Deletes the slice from `i1` to `i2` from `self`. /// Deletes the slice from `i1` to `i2` from `self`.
@ -177,12 +164,9 @@ impl PySequence {
/// This is equivalent to the Python statement `del self[i1:i2]`. /// This is equivalent to the Python statement `del self[i1:i2]`.
#[inline] #[inline]
pub fn del_slice(&self, i1: usize, i2: usize) -> PyResult<()> { pub fn del_slice(&self, i1: usize, i2: usize) -> PyResult<()> {
unsafe { err::error_on_minusone(self.py(), unsafe {
err::error_on_minusone( ffi::PySequence_DelSlice(self.as_ptr(), get_ssize_index(i1), get_ssize_index(i2))
self.py(), })
ffi::PySequence_DelSlice(self.as_ptr(), get_ssize_index(i1), get_ssize_index(i2)),
)
}
} }
/// Returns the number of occurrences of `value` in self, that is, return the /// Returns the number of occurrences of `value` in self, that is, return the
@ -193,13 +177,13 @@ impl PySequence {
where where
V: ToPyObject, V: ToPyObject,
{ {
let r = fn inner(seq: &PySequence, value: PyObject) -> PyResult<usize> {
unsafe { ffi::PySequence_Count(self.as_ptr(), value.to_object(self.py()).as_ptr()) }; let r = unsafe { ffi::PySequence_Count(seq.as_ptr(), value.as_ptr()) };
if r == -1 { crate::err::error_on_minusone(seq.py(), r)?;
Err(PyErr::fetch(self.py()))
} else {
Ok(r as usize) Ok(r as usize)
} }
inner(self, value.to_object(self.py()))
} }
/// Determines if self contains `value`. /// Determines if self contains `value`.
@ -210,15 +194,18 @@ impl PySequence {
where where
V: ToPyObject, V: ToPyObject,
{ {
let r = fn inner(seq: &PySequence, value: PyObject) -> PyResult<bool> {
unsafe { ffi::PySequence_Contains(self.as_ptr(), value.to_object(self.py()).as_ptr()) }; let r = unsafe { ffi::PySequence_Contains(seq.as_ptr(), value.as_ptr()) };
match r { match r {
0 => Ok(false), 0 => Ok(false),
1 => Ok(true), 1 => Ok(true),
_ => Err(PyErr::fetch(self.py())), _ => Err(PyErr::fetch(seq.py())),
} }
} }
inner(self, value.to_object(self.py()))
}
/// Returns the first index `i` for which `self[i] == value`. /// Returns the first index `i` for which `self[i] == value`.
/// ///
/// This is equivalent to the Python expression `self.index(value)`. /// This is equivalent to the Python expression `self.index(value)`.
@ -227,13 +214,13 @@ impl PySequence {
where where
V: ToPyObject, V: ToPyObject,
{ {
let r = fn inner(seq: &PySequence, value: PyObject) -> PyResult<usize> {
unsafe { ffi::PySequence_Index(self.as_ptr(), value.to_object(self.py()).as_ptr()) }; let r = unsafe { ffi::PySequence_Index(seq.as_ptr(), value.as_ptr()) };
if r == -1 { crate::err::error_on_minusone(seq.py(), r)?;
Err(PyErr::fetch(self.py()))
} else {
Ok(r as usize) Ok(r as usize)
} }
inner(self, value.to_object(self.py()))
} }
/// Returns a fresh list based on the Sequence. /// Returns a fresh list based on the Sequence.

View file

@ -71,13 +71,15 @@ impl PySet {
where where
K: ToPyObject, K: ToPyObject,
{ {
unsafe { fn inner(set: &PySet, key: PyObject) -> PyResult<bool> {
match ffi::PySet_Contains(self.as_ptr(), key.to_object(self.py()).as_ptr()) { match unsafe { ffi::PySet_Contains(set.as_ptr(), key.as_ptr()) } {
1 => Ok(true), 1 => Ok(true),
0 => Ok(false), 0 => Ok(false),
_ => Err(PyErr::fetch(self.py())), _ => Err(PyErr::fetch(set.py())),
} }
} }
inner(self, key.to_object(self.py()))
} }
/// Removes the element from the set if it is present. /// Removes the element from the set if it is present.
@ -88,14 +90,12 @@ impl PySet {
K: ToPyObject, K: ToPyObject,
{ {
fn inner(set: &PySet, key: PyObject) -> PyResult<bool> { fn inner(set: &PySet, key: PyObject) -> PyResult<bool> {
unsafe { match unsafe { ffi::PySet_Discard(set.as_ptr(), key.as_ptr()) } {
match ffi::PySet_Discard(set.as_ptr(), key.as_ptr()) {
1 => Ok(true), 1 => Ok(true),
0 => Ok(false), 0 => Ok(false),
_ => Err(PyErr::fetch(set.py())), _ => Err(PyErr::fetch(set.py())),
} }
} }
}
inner(self, key.to_object(self.py())) inner(self, key.to_object(self.py()))
} }
@ -105,12 +105,13 @@ impl PySet {
where where
K: ToPyObject, K: ToPyObject,
{ {
unsafe { fn inner(set: &PySet, key: PyObject) -> PyResult<()> {
err::error_on_minusone( err::error_on_minusone(set.py(), unsafe {
self.py(), ffi::PySet_Add(set.as_ptr(), key.as_ptr())
ffi::PySet_Add(self.as_ptr(), key.to_object(self.py()).as_ptr()), })
)
} }
inner(self, key.to_object(self.py()))
} }
/// Removes and returns an arbitrary element from the set. /// Removes and returns an arbitrary element from the set.
@ -248,10 +249,7 @@ pub(crate) fn new_from_iter<T: ToPyObject>(
py: Python<'_>, py: Python<'_>,
elements: impl IntoIterator<Item = T>, elements: impl IntoIterator<Item = T>,
) -> PyResult<Py<PySet>> { ) -> PyResult<Py<PySet>> {
fn new_from_iter_inner( fn inner(py: Python<'_>, elements: &mut dyn Iterator<Item = PyObject>) -> PyResult<Py<PySet>> {
py: Python<'_>,
elements: &mut dyn Iterator<Item = PyObject>,
) -> PyResult<Py<PySet>> {
let set: Py<PySet> = unsafe { let set: Py<PySet> = unsafe {
// We create the `Py` pointer because its Drop cleans up the set if user code panics. // We create the `Py` pointer because its Drop cleans up the set if user code panics.
Py::from_owned_ptr_or_err(py, ffi::PySet_New(std::ptr::null_mut()))? Py::from_owned_ptr_or_err(py, ffi::PySet_New(std::ptr::null_mut()))?
@ -259,16 +257,14 @@ pub(crate) fn new_from_iter<T: ToPyObject>(
let ptr = set.as_ptr(); let ptr = set.as_ptr();
for obj in elements { for obj in elements {
unsafe { err::error_on_minusone(py, unsafe { ffi::PySet_Add(ptr, obj.as_ptr()) })?;
err::error_on_minusone(py, ffi::PySet_Add(ptr, obj.as_ptr()))?;
}
} }
Ok(set) Ok(set)
} }
let mut iter = elements.into_iter().map(|e| e.to_object(py)); let mut iter = elements.into_iter().map(|e| e.to_object(py));
new_from_iter_inner(py, &mut iter) inner(py, &mut iter)
} }
#[cfg(test)] #[cfg(test)]

View file

@ -19,5 +19,5 @@ error[E0308]: mismatched types
note: function defined here note: function defined here
--> src/impl_/pymethods.rs --> src/impl_/pymethods.rs
| |
| pub unsafe fn call_traverse_impl<T>( | pub unsafe fn _call_traverse<T>(
| ^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^