Merge pull request #3273 from davidhewitt/conventions
add some style guide to Contributing.md
This commit is contained in:
commit
edb62e05e3
|
@ -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
|
||||
- `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
|
||||
|
||||
PyO3 aims to keep sufficient compatibility to make packaging Python extensions built with PyO3 feasible on most common package managers.
|
||||
|
|
|
@ -119,7 +119,7 @@ pub fn process_functions_in_module(
|
|||
let name = &func.sig.ident;
|
||||
let statements: Vec<syn::Stmt> = syn::parse_quote! {
|
||||
#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);
|
||||
}
|
||||
|
|
|
@ -420,7 +420,7 @@ fn impl_traverse_slot(cls: &syn::Type, spec: &FnSpec<'_>) -> syn::Result<MethodA
|
|||
visit: _pyo3::ffi::visitproc,
|
||||
arg: *mut ::std::os::raw::c_void,
|
||||
) -> ::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! {
|
||||
|
|
|
@ -193,14 +193,13 @@ impl<T: Element> PyBuffer<T> {
|
|||
pub fn get(obj: &PyAny) -> PyResult<PyBuffer<T>> {
|
||||
// TODO: use nightly API Box::new_uninit() once stable
|
||||
let mut buf = Box::new(mem::MaybeUninit::uninit());
|
||||
let buf: Box<ffi::Py_buffer> = unsafe {
|
||||
err::error_on_minusone(
|
||||
obj.py(),
|
||||
ffi::PyObject_GetBuffer(obj.as_ptr(), buf.as_mut_ptr(), ffi::PyBUF_FULL_RO),
|
||||
)?;
|
||||
let buf: Box<ffi::Py_buffer> = {
|
||||
err::error_on_minusone(obj.py(), unsafe {
|
||||
ffi::PyObject_GetBuffer(obj.as_ptr(), buf.as_mut_ptr(), ffi::PyBUF_FULL_RO)
|
||||
})?;
|
||||
// Safety: buf is initialized by PyObject_GetBuffer.
|
||||
// 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
|
||||
// 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())`.
|
||||
/// Alternatively, `match buffer::ElementType::from_format(buf.format())`.
|
||||
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.
|
||||
|
@ -482,10 +481,10 @@ impl<T: Element> PyBuffer<T> {
|
|||
/// you can use `<T as buffer::Element>::is_compatible_format(buf.format())`.
|
||||
/// Alternatively, `match buffer::ElementType::from_format(buf.format())`.
|
||||
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() {
|
||||
return Err(PyBufferError::new_err(format!(
|
||||
"slice to copy to (of length {}) does not match buffer length of {}",
|
||||
|
@ -493,9 +492,8 @@ impl<T: Element> PyBuffer<T> {
|
|||
self.item_count()
|
||||
)));
|
||||
}
|
||||
unsafe {
|
||||
err::error_on_minusone(
|
||||
py,
|
||||
|
||||
err::error_on_minusone(py, unsafe {
|
||||
ffi::PyBuffer_ToContiguous(
|
||||
target.as_ptr() as *mut raw::c_void,
|
||||
#[cfg(Py_3_11)]
|
||||
|
@ -506,9 +504,8 @@ impl<T: Element> PyBuffer<T> {
|
|||
},
|
||||
self.0.len,
|
||||
fort as std::os::raw::c_char,
|
||||
),
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// 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`.
|
||||
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.
|
||||
|
@ -524,17 +521,16 @@ impl<T: Element> PyBuffer<T> {
|
|||
///
|
||||
/// Fails if the buffer format is not compatible with type `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 mut vec: Vec<T> = Vec::with_capacity(item_count);
|
||||
unsafe {
|
||||
|
||||
// Copy the buffer into the uninitialized space in the vector.
|
||||
// Due to T:Copy, we don't need to be concerned with Drop impls.
|
||||
err::error_on_minusone(
|
||||
py,
|
||||
err::error_on_minusone(py, unsafe {
|
||||
ffi::PyBuffer_ToContiguous(
|
||||
vec.as_ptr() as *mut raw::c_void,
|
||||
#[cfg(Py_3_11)]
|
||||
|
@ -545,11 +541,10 @@ impl<T: Element> PyBuffer<T> {
|
|||
},
|
||||
self.0.len,
|
||||
fort as std::os::raw::c_char,
|
||||
),
|
||||
)?;
|
||||
)
|
||||
})?;
|
||||
// set vector length to mark the now-initialized space as usable
|
||||
vec.set_len(item_count);
|
||||
}
|
||||
unsafe { vec.set_len(item_count) };
|
||||
Ok(vec)
|
||||
}
|
||||
|
||||
|
@ -564,7 +559,7 @@ impl<T: Element> PyBuffer<T> {
|
|||
/// use `<T as buffer::Element>::is_compatible_format(buf.format())`.
|
||||
/// Alternatively, `match buffer::ElementType::from_format(buf.format())`.
|
||||
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.
|
||||
|
@ -578,10 +573,10 @@ impl<T: Element> PyBuffer<T> {
|
|||
/// use `<T as buffer::Element>::is_compatible_format(buf.format())`.
|
||||
/// Alternatively, `match buffer::ElementType::from_format(buf.format())`.
|
||||
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() {
|
||||
return Err(PyBufferError::new_err("cannot write to read-only buffer"));
|
||||
} else if mem::size_of_val(source) != self.len_bytes() {
|
||||
|
@ -591,9 +586,8 @@ impl<T: Element> PyBuffer<T> {
|
|||
self.item_count()
|
||||
)));
|
||||
}
|
||||
unsafe {
|
||||
err::error_on_minusone(
|
||||
py,
|
||||
|
||||
err::error_on_minusone(py, unsafe {
|
||||
ffi::PyBuffer_FromContiguous(
|
||||
#[cfg(Py_3_11)]
|
||||
&*self.0,
|
||||
|
@ -611,9 +605,8 @@ impl<T: Element> PyBuffer<T> {
|
|||
},
|
||||
self.0.len,
|
||||
fort as std::os::raw::c_char,
|
||||
),
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Releases the buffer object, freeing the reference to the Python object
|
||||
|
|
|
@ -178,16 +178,18 @@ mod fast_128bit_int_conversion {
|
|||
}
|
||||
impl IntoPy<PyObject> for $rust_type {
|
||||
fn into_py(self, py: Python<'_>) -> PyObject {
|
||||
unsafe {
|
||||
// Always use little endian
|
||||
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.len(),
|
||||
1,
|
||||
$is_signed,
|
||||
);
|
||||
PyObject::from_owned_ptr(py, obj)
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -199,24 +201,21 @@ mod fast_128bit_int_conversion {
|
|||
|
||||
impl<'source> FromPyObject<'source> for $rust_type {
|
||||
fn extract(ob: &'source PyAny) -> PyResult<$rust_type> {
|
||||
unsafe {
|
||||
let num = ffi::PyNumber_Index(ob.as_ptr());
|
||||
if num.is_null() {
|
||||
return Err(PyErr::fetch(ob.py()));
|
||||
}
|
||||
let num = unsafe {
|
||||
PyObject::from_owned_ptr_or_err(ob.py(), ffi::PyNumber_Index(ob.as_ptr()))?
|
||||
};
|
||||
let mut buffer = [0; std::mem::size_of::<$rust_type>()];
|
||||
let ok = ffi::_PyLong_AsByteArray(
|
||||
num as *mut ffi::PyLongObject,
|
||||
crate::err::error_on_minusone(ob.py(), unsafe {
|
||||
ffi::_PyLong_AsByteArray(
|
||||
num.as_ptr() as *mut ffi::PyLongObject,
|
||||
buffer.as_mut_ptr(),
|
||||
buffer.len(),
|
||||
1,
|
||||
$is_signed,
|
||||
);
|
||||
ffi::Py_DECREF(num);
|
||||
crate::err::error_on_minusone(ob.py(), ok)?;
|
||||
)
|
||||
})?;
|
||||
Ok(<$rust_type>::from_le_bytes(buffer))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "experimental-inspect")]
|
||||
fn type_input() -> TypeInfo {
|
||||
|
@ -248,19 +247,17 @@ mod slow_128bit_int_conversion {
|
|||
|
||||
impl IntoPy<PyObject> for $rust_type {
|
||||
fn into_py(self, py: Python<'_>) -> PyObject {
|
||||
let lower = self as u64;
|
||||
let upper = (self >> SHIFT) as $half_type;
|
||||
let lower = (self as u64).into_py(py);
|
||||
let upper = ((self >> SHIFT) as $half_type).into_py(py);
|
||||
let shift = SHIFT.into_py(py);
|
||||
unsafe {
|
||||
let shifted = PyObject::from_owned_ptr(
|
||||
py,
|
||||
ffi::PyNumber_Lshift(
|
||||
upper.into_py(py).as_ptr(),
|
||||
SHIFT.into_py(py).as_ptr(),
|
||||
),
|
||||
ffi::PyNumber_Lshift(upper.as_ptr(), shift.as_ptr()),
|
||||
);
|
||||
PyObject::from_owned_ptr(
|
||||
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 _,
|
||||
ffi::PyLong_AsUnsignedLongLongMask(ob.as_ptr()),
|
||||
)? as $rust_type;
|
||||
let shift = SHIFT.into_py(py);
|
||||
let shifted = PyObject::from_owned_ptr_or_err(
|
||||
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)?;
|
||||
Ok((<$rust_type>::from(upper) << SHIFT) | lower)
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
use crate::types::PyString;
|
||||
#[cfg(windows)]
|
||||
use crate::PyErr;
|
||||
use crate::{
|
||||
ffi, AsPyPointer, FromPyObject, IntoPy, PyAny, PyObject, PyResult, Python, ToPyObject,
|
||||
};
|
||||
|
@ -92,9 +90,7 @@ impl FromPyObject<'_> for OsString {
|
|||
// ourselves
|
||||
let size =
|
||||
unsafe { ffi::PyUnicode_AsWideChar(pystring.as_ptr(), std::ptr::null_mut(), 0) };
|
||||
if size == -1 {
|
||||
return Err(PyErr::fetch(ob.py()));
|
||||
}
|
||||
crate::err::error_on_minusone(ob.py(), size)?;
|
||||
|
||||
let mut buffer = vec![0; size as usize];
|
||||
let bytes_read =
|
||||
|
|
|
@ -9,7 +9,6 @@ use crate::{AsPyPointer, IntoPy, IntoPyPointer, Py, PyAny, PyObject, Python, ToP
|
|||
use std::borrow::Cow;
|
||||
use std::cell::UnsafeCell;
|
||||
use std::ffi::CString;
|
||||
use std::os::raw::c_int;
|
||||
|
||||
mod err_state;
|
||||
mod impls;
|
||||
|
@ -314,7 +313,7 @@ impl PyErr {
|
|||
(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
|
||||
.as_ref()
|
||||
.and_then(|obj| obj.extract(py).ok())
|
||||
|
@ -439,15 +438,16 @@ impl PyErr {
|
|||
where
|
||||
T: ToPyObject,
|
||||
{
|
||||
unsafe {
|
||||
ffi::PyErr_GivenExceptionMatches(self.type_ptr(py), exc.to_object(py).as_ptr()) != 0
|
||||
fn inner(err: &PyErr, py: Python<'_>, exc: PyObject) -> bool {
|
||||
(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`.
|
||||
#[inline]
|
||||
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`.
|
||||
|
@ -531,16 +531,13 @@ impl PyErr {
|
|||
/// ```
|
||||
pub fn warn(py: Python<'_>, category: &PyAny, message: &str, stacklevel: i32) -> PyResult<()> {
|
||||
let message = CString::new(message)?;
|
||||
unsafe {
|
||||
error_on_minusone(
|
||||
py,
|
||||
error_on_minusone(py, unsafe {
|
||||
ffi::PyErr_WarnEx(
|
||||
category.as_ptr(),
|
||||
message.as_ptr(),
|
||||
stacklevel as ffi::Py_ssize_t,
|
||||
),
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Issues a warning message, with more control over the warning attributes.
|
||||
|
@ -571,9 +568,7 @@ impl PyErr {
|
|||
None => std::ptr::null_mut(),
|
||||
Some(obj) => obj.as_ptr(),
|
||||
};
|
||||
unsafe {
|
||||
error_on_minusone(
|
||||
py,
|
||||
error_on_minusone(py, unsafe {
|
||||
ffi::PyErr_WarnExplicit(
|
||||
category.as_ptr(),
|
||||
message.as_ptr(),
|
||||
|
@ -581,9 +576,8 @@ impl PyErr {
|
|||
lineno,
|
||||
module_ptr,
|
||||
registry,
|
||||
),
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// 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 ...`)
|
||||
/// associated with the exception, as accessible from Python through `__cause__`.
|
||||
pub fn cause(&self, py: Python<'_>) -> Option<PyErr> {
|
||||
let ptr = unsafe { ffi::PyException_GetCause(self.value(py).as_ptr()) };
|
||||
let obj = unsafe { py.from_owned_ptr_or_opt::<PyAny>(ptr) };
|
||||
let value = self.value(py);
|
||||
let obj =
|
||||
unsafe { py.from_owned_ptr_or_opt::<PyAny>(ffi::PyException_GetCause(value.as_ptr())) };
|
||||
obj.map(Self::from_value)
|
||||
}
|
||||
|
||||
/// Set the cause associated with the exception, pass `None` to clear it.
|
||||
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 {
|
||||
// PyException_SetCause _steals_ a reference to cause, so must use .into_ptr()
|
||||
ffi::PyException_SetCause(
|
||||
self.value(py).as_ptr(),
|
||||
cause.map_or(std::ptr::null_mut(), |err| err.into_value(py).into_ptr()),
|
||||
value.as_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.
|
||||
#[inline]
|
||||
pub fn error_on_minusone(py: Python<'_>, result: c_int) -> PyResult<()> {
|
||||
if result != -1 {
|
||||
pub(crate) fn error_on_minusone<T: SignedInteger>(py: Python<'_>, result: T) -> PyResult<()> {
|
||||
if result != T::MINUS_ONE {
|
||||
Ok(())
|
||||
} else {
|
||||
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]
|
||||
fn exceptions_must_derive_from_base_exception(py: Python<'_>) -> PyErr {
|
||||
PyErr::from_state(PyErrState::exceptions_must_derive_from_base_exception(py))
|
||||
|
|
|
@ -71,12 +71,8 @@ fn test_timezone_from_offset() {
|
|||
use crate::types::PyDelta;
|
||||
|
||||
Python::with_gil(|py| {
|
||||
let tz: &PyAny = unsafe {
|
||||
PyDateTime_IMPORT();
|
||||
py.from_borrowed_ptr(PyTimeZone_FromOffset(
|
||||
PyDelta::new(py, 0, 100, 0, false).unwrap().as_ptr(),
|
||||
))
|
||||
};
|
||||
let delta = PyDelta::new(py, 0, 100, 0, false).unwrap();
|
||||
let tz: &PyAny = unsafe { py.from_borrowed_ptr(PyTimeZone_FromOffset(delta.as_ptr())) };
|
||||
crate::py_run!(
|
||||
py,
|
||||
tz,
|
||||
|
@ -92,11 +88,12 @@ fn test_timezone_from_offset_and_name() {
|
|||
use crate::types::PyDelta;
|
||||
|
||||
Python::with_gil(|py| {
|
||||
let delta = PyDelta::new(py, 0, 100, 0, false).unwrap();
|
||||
let tzname = PyString::new(py, "testtz");
|
||||
let tz: &PyAny = unsafe {
|
||||
PyDateTime_IMPORT();
|
||||
py.from_borrowed_ptr(PyTimeZone_FromOffsetAndName(
|
||||
PyDelta::new(py, 0, 100, 0, false).unwrap().as_ptr(),
|
||||
PyString::new(py, "testtz").as_ptr(),
|
||||
delta.as_ptr(),
|
||||
tzname.as_ptr(),
|
||||
))
|
||||
};
|
||||
crate::py_run!(
|
||||
|
|
|
@ -714,14 +714,14 @@ mod tests {
|
|||
};
|
||||
|
||||
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 {
|
||||
function_description
|
||||
.extract_arguments_tuple_dict::<NoVarargs, NoVarkeywords>(
|
||||
py,
|
||||
PyTuple::new(py, Vec::<&PyAny>::new()).as_ptr(),
|
||||
[("foo".to_object(py).into_ref(py), 0u8)]
|
||||
.into_py_dict(py)
|
||||
.as_ptr(),
|
||||
args.as_ptr(),
|
||||
kwargs.as_ptr(),
|
||||
&mut [],
|
||||
)
|
||||
.unwrap_err()
|
||||
|
@ -745,14 +745,14 @@ mod tests {
|
|||
};
|
||||
|
||||
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 {
|
||||
function_description
|
||||
.extract_arguments_tuple_dict::<NoVarargs, NoVarkeywords>(
|
||||
py,
|
||||
PyTuple::new(py, Vec::<&PyAny>::new()).as_ptr(),
|
||||
[(1u8.to_object(py).into_ref(py), 1u8)]
|
||||
.into_py_dict(py)
|
||||
.as_ptr(),
|
||||
args.as_ptr(),
|
||||
kwargs.as_ptr(),
|
||||
&mut [],
|
||||
)
|
||||
.unwrap_err()
|
||||
|
@ -776,11 +776,12 @@ mod tests {
|
|||
};
|
||||
|
||||
Python::with_gil(|py| {
|
||||
let args = PyTuple::new(py, Vec::<&PyAny>::new());
|
||||
let mut output = [None, None];
|
||||
let err = unsafe {
|
||||
function_description.extract_arguments_tuple_dict::<NoVarargs, NoVarkeywords>(
|
||||
py,
|
||||
PyTuple::new(py, Vec::<&PyAny>::new()).as_ptr(),
|
||||
args.as_ptr(),
|
||||
std::ptr::null_mut(),
|
||||
&mut output,
|
||||
)
|
||||
|
|
|
@ -202,8 +202,9 @@ fn initialize_tp_dict(
|
|||
// We hold the GIL: the dictionary update can be considered atomic from
|
||||
// the POV of other threads.
|
||||
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, ret)?;
|
||||
crate::err::error_on_minusone(py, unsafe {
|
||||
ffi::PyObject_SetAttrString(type_object, key.as_ptr(), val.into_ptr())
|
||||
})?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ use crate::{derive_utils::PyFunctionArguments, types::PyCFunction, PyResult};
|
|||
|
||||
pub use crate::impl_::pymethods::PyMethodDef;
|
||||
|
||||
pub fn wrap_pyfunction_impl<'a>(
|
||||
pub fn _wrap_pyfunction<'a>(
|
||||
method_def: &PyMethodDef,
|
||||
py_or_module: impl Into<PyFunctionArguments<'a>>,
|
||||
) -> PyResult<&'a PyCFunction> {
|
||||
|
|
|
@ -247,7 +247,7 @@ impl PySetterDef {
|
|||
|
||||
/// Calls an implementation of __traverse__ for tp_traverse
|
||||
#[doc(hidden)]
|
||||
pub unsafe fn call_traverse_impl<T>(
|
||||
pub unsafe fn _call_traverse<T>(
|
||||
slf: *mut ffi::PyObject,
|
||||
impl_: fn(&T, PyVisit<'_>) -> Result<(), PyTraverseError>,
|
||||
visit: ffi::visitproc,
|
||||
|
|
|
@ -18,7 +18,7 @@ use crate::{
|
|||
pub unsafe fn module_init(
|
||||
f: for<'py> unsafe fn(Python<'py>) -> PyResult<Py<PyModule>>,
|
||||
) -> *mut ffi::PyObject {
|
||||
trampoline_inner(|py| f(py).map(|module| module.into_ptr()))
|
||||
trampoline(|py| f(py).map(|module| module.into_ptr()))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
@ -28,7 +28,7 @@ pub unsafe fn noargs(
|
|||
f: for<'py> unsafe fn(Python<'py>, *mut ffi::PyObject) -> PyResult<*mut ffi::PyObject>,
|
||||
) -> *mut ffi::PyObject {
|
||||
debug_assert!(args.is_null());
|
||||
trampoline_inner(|py| f(py, slf))
|
||||
trampoline(|py| f(py, slf))
|
||||
}
|
||||
|
||||
macro_rules! trampoline {
|
||||
|
@ -38,7 +38,7 @@ macro_rules! trampoline {
|
|||
$($arg_names: $arg_types,)*
|
||||
f: for<'py> unsafe fn (Python<'py>, $($arg_types),*) -> PyResult<$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,
|
||||
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]
|
||||
|
@ -143,7 +143,7 @@ pub(crate) unsafe fn dealloc(
|
|||
// so pass null_mut() to the context.
|
||||
//
|
||||
// (Note that we don't allow the implementation `f` to fail.)
|
||||
trampoline_inner_unraisable(
|
||||
trampoline_unraisable(
|
||||
|py| {
|
||||
f(py, slf);
|
||||
Ok(())
|
||||
|
@ -168,7 +168,7 @@ trampoline!(
|
|||
/// Panics during execution are trapped so that they don't propagate through any
|
||||
/// outer FFI boundary.
|
||||
#[inline]
|
||||
pub(crate) fn trampoline_inner<F, R>(body: F) -> R
|
||||
pub(crate) fn trampoline<F, R>(body: F) -> R
|
||||
where
|
||||
F: for<'py> FnOnce(Python<'py>) -> PyResult<R> + UnwindSafe,
|
||||
R: PyCallbackOutput,
|
||||
|
@ -214,7 +214,7 @@ where
|
|||
///
|
||||
/// ctx must be either a valid ffi::PyObject or NULL
|
||||
#[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
|
||||
F: for<'py> FnOnce(Python<'py>) -> PyResult<()> + UnwindSafe,
|
||||
{
|
||||
|
|
|
@ -650,12 +650,9 @@ impl<T> Py<T> {
|
|||
let attr_name = attr_name.into_py(py);
|
||||
let value = value.into_py(py);
|
||||
|
||||
unsafe {
|
||||
err::error_on_minusone(
|
||||
py,
|
||||
ffi::PyObject_SetAttr(self.as_ptr(), attr_name.as_ptr(), value.as_ptr()),
|
||||
)
|
||||
}
|
||||
err::error_on_minusone(py, unsafe {
|
||||
ffi::PyObject_SetAttr(self.as_ptr(), attr_name.as_ptr(), value.as_ptr())
|
||||
})
|
||||
}
|
||||
|
||||
/// Calls the object.
|
||||
|
|
|
@ -125,12 +125,12 @@ macro_rules! wrap_pyfunction {
|
|||
($function:path) => {
|
||||
&|py_or_module| {
|
||||
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) => {{
|
||||
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)
|
||||
}};
|
||||
}
|
||||
|
||||
|
|
|
@ -876,8 +876,7 @@ impl<'py> Python<'py> {
|
|||
/// [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
|
||||
pub fn check_signals(self) -> PyResult<()> {
|
||||
let v = unsafe { ffi::PyErr_CheckSignals() };
|
||||
err::error_on_minusone(self, v)
|
||||
err::error_on_minusone(self, unsafe { ffi::PyErr_CheckSignals() })
|
||||
}
|
||||
|
||||
/// Create a new pool for managing PyO3's owned references.
|
||||
|
|
|
@ -7,7 +7,7 @@ use crate::{
|
|||
},
|
||||
impl_::{
|
||||
pymethods::{get_doc, get_name, Getter, Setter},
|
||||
trampoline::trampoline_inner,
|
||||
trampoline::trampoline,
|
||||
},
|
||||
types::PyType,
|
||||
Py, PyClass, PyGetterDef, PyMethodDefType, PyResult, PySetterDef, PyTypeInfo, Python,
|
||||
|
@ -413,7 +413,7 @@ unsafe extern "C" fn no_constructor_defined(
|
|||
_args: *mut ffi::PyObject,
|
||||
_kwds: *mut ffi::PyObject,
|
||||
) -> *mut ffi::PyObject {
|
||||
trampoline_inner(|_| {
|
||||
trampoline(|_| {
|
||||
Err(crate::exceptions::PyTypeError::new_err(
|
||||
"No constructor defined",
|
||||
))
|
||||
|
@ -513,7 +513,7 @@ impl GetSetDefType {
|
|||
) -> *mut ffi::PyObject {
|
||||
// Safety: PyO3 sets the closure when constructing the ffi getter so this cast should always be valid
|
||||
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 _)
|
||||
}
|
||||
|
@ -525,7 +525,7 @@ impl GetSetDefType {
|
|||
) -> c_int {
|
||||
// Safety: PyO3 sets the closure when constructing the ffi setter so this cast should always be valid
|
||||
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 _)
|
||||
}
|
||||
|
@ -535,7 +535,7 @@ impl GetSetDefType {
|
|||
closure: *mut c_void,
|
||||
) -> *mut ffi::PyObject {
|
||||
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(
|
||||
|
@ -544,7 +544,7 @@ impl GetSetDefType {
|
|||
closure: *mut c_void,
|
||||
) -> c_int {
|
||||
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),
|
||||
|
|
|
@ -227,14 +227,14 @@ impl PyAny {
|
|||
N: IntoPy<Py<PyString>>,
|
||||
V: ToPyObject,
|
||||
{
|
||||
let py = self.py();
|
||||
let attr_name = attr_name.into_py(py);
|
||||
let value = value.to_object(py);
|
||||
|
||||
unsafe {
|
||||
let ret = ffi::PyObject_SetAttr(self.as_ptr(), attr_name.as_ptr(), value.as_ptr());
|
||||
err::error_on_minusone(py, ret)
|
||||
fn inner(any: &PyAny, attr_name: Py<PyString>, value: PyObject) -> PyResult<()> {
|
||||
err::error_on_minusone(any.py(), unsafe {
|
||||
ffi::PyObject_SetAttr(any.as_ptr(), attr_name.as_ptr(), value.as_ptr())
|
||||
})
|
||||
}
|
||||
|
||||
let py = self.py();
|
||||
inner(self, attr_name.into_py(py), value.to_object(py))
|
||||
}
|
||||
|
||||
/// Deletes an attribute.
|
||||
|
@ -247,13 +247,13 @@ impl PyAny {
|
|||
where
|
||||
N: IntoPy<Py<PyString>>,
|
||||
{
|
||||
let py = self.py();
|
||||
let attr_name = attr_name.into_py(py);
|
||||
|
||||
unsafe {
|
||||
let ret = ffi::PyObject_DelAttr(self.as_ptr(), attr_name.as_ptr());
|
||||
err::error_on_minusone(py, ret)
|
||||
fn inner(any: &PyAny, attr_name: Py<PyString>) -> PyResult<()> {
|
||||
err::error_on_minusone(any.py(), unsafe {
|
||||
ffi::PyObject_DelAttr(any.as_ptr(), attr_name.as_ptr())
|
||||
})
|
||||
}
|
||||
|
||||
inner(self, attr_name.into_py(self.py()))
|
||||
}
|
||||
|
||||
/// Returns an [`Ordering`] between `self` and `other`.
|
||||
|
@ -369,15 +369,19 @@ impl PyAny {
|
|||
where
|
||||
O: ToPyObject,
|
||||
{
|
||||
fn inner(slf: &PyAny, other: PyObject, compare_op: CompareOp) -> PyResult<&PyAny> {
|
||||
unsafe {
|
||||
self.py().from_owned_ptr_or_err(ffi::PyObject_RichCompare(
|
||||
self.as_ptr(),
|
||||
other.to_object(self.py()).as_ptr(),
|
||||
slf.py().from_owned_ptr_or_err(ffi::PyObject_RichCompare(
|
||||
slf.as_ptr(),
|
||||
other.as_ptr(),
|
||||
compare_op as c_int,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
inner(self, other.to_object(self.py()), compare_op)
|
||||
}
|
||||
|
||||
/// Tests whether this object is less than another.
|
||||
///
|
||||
/// This is equivalent to the Python expression `self < other`.
|
||||
|
@ -767,14 +771,16 @@ impl PyAny {
|
|||
where
|
||||
K: ToPyObject,
|
||||
{
|
||||
fn inner(slf: &PyAny, key: PyObject) -> PyResult<&PyAny> {
|
||||
unsafe {
|
||||
self.py().from_owned_ptr_or_err(ffi::PyObject_GetItem(
|
||||
self.as_ptr(),
|
||||
key.to_object(self.py()).as_ptr(),
|
||||
))
|
||||
slf.py()
|
||||
.from_owned_ptr_or_err(ffi::PyObject_GetItem(slf.as_ptr(), key.as_ptr()))
|
||||
}
|
||||
}
|
||||
|
||||
inner(self, key.to_object(self.py()))
|
||||
}
|
||||
|
||||
/// Sets a collection item value.
|
||||
///
|
||||
/// This is equivalent to the Python expression `self[key] = value`.
|
||||
|
@ -783,17 +789,14 @@ impl PyAny {
|
|||
K: ToPyObject,
|
||||
V: ToPyObject,
|
||||
{
|
||||
let py = self.py();
|
||||
unsafe {
|
||||
err::error_on_minusone(
|
||||
py,
|
||||
ffi::PyObject_SetItem(
|
||||
self.as_ptr(),
|
||||
key.to_object(py).as_ptr(),
|
||||
value.to_object(py).as_ptr(),
|
||||
),
|
||||
)
|
||||
fn inner(slf: &PyAny, key: PyObject, value: PyObject) -> PyResult<()> {
|
||||
err::error_on_minusone(slf.py(), unsafe {
|
||||
ffi::PyObject_SetItem(slf.as_ptr(), key.as_ptr(), value.as_ptr())
|
||||
})
|
||||
}
|
||||
|
||||
let py = self.py();
|
||||
inner(self, key.to_object(py), value.to_object(py))
|
||||
}
|
||||
|
||||
/// Deletes an item from the collection.
|
||||
|
@ -803,12 +806,13 @@ impl PyAny {
|
|||
where
|
||||
K: ToPyObject,
|
||||
{
|
||||
unsafe {
|
||||
err::error_on_minusone(
|
||||
self.py(),
|
||||
ffi::PyObject_DelItem(self.as_ptr(), key.to_object(self.py()).as_ptr()),
|
||||
)
|
||||
fn inner(slf: &PyAny, key: PyObject) -> PyResult<()> {
|
||||
err::error_on_minusone(slf.py(), unsafe {
|
||||
ffi::PyObject_DelItem(slf.as_ptr(), key.as_ptr())
|
||||
})
|
||||
}
|
||||
|
||||
inner(self, key.to_object(self.py()))
|
||||
}
|
||||
|
||||
/// Takes an object and returns an iterator for it.
|
||||
|
@ -943,24 +947,18 @@ impl PyAny {
|
|||
/// This is equivalent to the Python expression `hash(self)`.
|
||||
pub fn hash(&self) -> PyResult<isize> {
|
||||
let v = unsafe { ffi::PyObject_Hash(self.as_ptr()) };
|
||||
if v == -1 {
|
||||
Err(PyErr::fetch(self.py()))
|
||||
} else {
|
||||
crate::err::error_on_minusone(self.py(), v)?;
|
||||
Ok(v)
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the length of the sequence or mapping.
|
||||
///
|
||||
/// This is equivalent to the Python expression `len(self)`.
|
||||
pub fn len(&self) -> PyResult<usize> {
|
||||
let v = unsafe { ffi::PyObject_Size(self.as_ptr()) };
|
||||
if v == -1 {
|
||||
Err(PyErr::fetch(self.py()))
|
||||
} else {
|
||||
crate::err::error_on_minusone(self.py(), v)?;
|
||||
Ok(v as usize)
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the list of attributes of this object.
|
||||
///
|
||||
|
|
|
@ -68,15 +68,12 @@ impl PyDict {
|
|||
/// this keeps the last entry seen.
|
||||
#[cfg(not(PyPy))]
|
||||
pub fn from_sequence(py: Python<'_>, seq: PyObject) -> PyResult<&PyDict> {
|
||||
unsafe {
|
||||
let dict = py.from_owned_ptr::<PyDict>(ffi::PyDict_New());
|
||||
err::error_on_minusone(
|
||||
py,
|
||||
ffi::PyDict_MergeFromSeq2(dict.into_ptr(), seq.into_ptr(), 1),
|
||||
)?;
|
||||
let dict = Self::new(py);
|
||||
err::error_on_minusone(py, unsafe {
|
||||
ffi::PyDict_MergeFromSeq2(dict.into_ptr(), seq.into_ptr(), 1)
|
||||
})?;
|
||||
Ok(dict)
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a new dictionary that contains the same key-value pairs as self.
|
||||
///
|
||||
|
@ -124,13 +121,15 @@ impl PyDict {
|
|||
where
|
||||
K: ToPyObject,
|
||||
{
|
||||
unsafe {
|
||||
match ffi::PyDict_Contains(self.as_ptr(), key.to_object(self.py()).as_ptr()) {
|
||||
fn inner(dict: &PyDict, key: PyObject) -> PyResult<bool> {
|
||||
match unsafe { ffi::PyDict_Contains(dict.as_ptr(), key.as_ptr()) } {
|
||||
1 => Ok(true),
|
||||
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.
|
||||
|
@ -142,17 +141,20 @@ impl PyDict {
|
|||
where
|
||||
K: ToPyObject,
|
||||
{
|
||||
self.get_item_impl(key.to_object(self.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());
|
||||
fn inner(dict: &PyDict, key: PyObject) -> Option<&PyAny> {
|
||||
let py = dict.py();
|
||||
// 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(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,
|
||||
|
@ -164,20 +166,22 @@ impl PyDict {
|
|||
where
|
||||
K: ToPyObject,
|
||||
{
|
||||
self.get_item_with_error_impl(key.to_object(self.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());
|
||||
fn inner(dict: &PyDict, key: PyObject) -> PyResult<Option<&PyAny>> {
|
||||
let py = dict.py();
|
||||
// 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(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)))
|
||||
.or_else(|| PyErr::take(py).map(Err))
|
||||
.transpose()
|
||||
}
|
||||
|
||||
inner(self, key.to_object(self.py()))
|
||||
}
|
||||
|
||||
/// Sets an item value.
|
||||
|
@ -188,17 +192,14 @@ impl PyDict {
|
|||
K: ToPyObject,
|
||||
V: ToPyObject,
|
||||
{
|
||||
let py = self.py();
|
||||
unsafe {
|
||||
err::error_on_minusone(
|
||||
py,
|
||||
ffi::PyDict_SetItem(
|
||||
self.as_ptr(),
|
||||
key.to_object(py).as_ptr(),
|
||||
value.to_object(py).as_ptr(),
|
||||
),
|
||||
)
|
||||
fn inner(dict: &PyDict, key: PyObject, value: PyObject) -> PyResult<()> {
|
||||
err::error_on_minusone(dict.py(), unsafe {
|
||||
ffi::PyDict_SetItem(dict.as_ptr(), key.as_ptr(), value.as_ptr())
|
||||
})
|
||||
}
|
||||
|
||||
let py = self.py();
|
||||
inner(self, key.to_object(py), value.to_object(py))
|
||||
}
|
||||
|
||||
/// Deletes an item.
|
||||
|
@ -208,13 +209,13 @@ impl PyDict {
|
|||
where
|
||||
K: ToPyObject,
|
||||
{
|
||||
let py = self.py();
|
||||
unsafe {
|
||||
err::error_on_minusone(
|
||||
py,
|
||||
ffi::PyDict_DelItem(self.as_ptr(), key.to_object(py).as_ptr()),
|
||||
)
|
||||
fn inner(dict: &PyDict, key: PyObject) -> PyResult<()> {
|
||||
err::error_on_minusone(dict.py(), unsafe {
|
||||
ffi::PyDict_DelItem(dict.as_ptr(), key.as_ptr())
|
||||
})
|
||||
}
|
||||
|
||||
inner(self, key.to_object(self.py()))
|
||||
}
|
||||
|
||||
/// 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.
|
||||
pub fn update(&self, other: &PyMapping) -> PyResult<()> {
|
||||
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.
|
||||
|
@ -282,7 +285,9 @@ impl PyDict {
|
|||
/// so should have the same performance as `update`.
|
||||
pub fn update_if_missing(&self, other: &PyMapping) -> PyResult<()> {
|
||||
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)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -28,12 +28,15 @@ impl<'py> PyFrozenSetBuilder<'py> {
|
|||
where
|
||||
K: ToPyObject,
|
||||
{
|
||||
let py = self.py_frozen_set.py();
|
||||
err::error_on_minusone(py, unsafe {
|
||||
ffi::PySet_Add(self.py_frozen_set.as_ptr(), key.to_object(py).as_ptr())
|
||||
fn inner(frozenset: &PyFrozenSet, key: PyObject) -> PyResult<()> {
|
||||
err::error_on_minusone(frozenset.py(), unsafe {
|
||||
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
|
||||
pub fn finalize(self) -> &'py PyFrozenSet {
|
||||
self.py_frozen_set
|
||||
|
@ -94,13 +97,15 @@ impl PyFrozenSet {
|
|||
where
|
||||
K: ToPyObject,
|
||||
{
|
||||
unsafe {
|
||||
match ffi::PySet_Contains(self.as_ptr(), key.to_object(self.py()).as_ptr()) {
|
||||
fn inner(frozenset: &PyFrozenSet, key: PyObject) -> PyResult<bool> {
|
||||
match unsafe { ffi::PySet_Contains(frozenset.as_ptr(), key.as_ptr()) } {
|
||||
1 => Ok(true),
|
||||
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.
|
||||
|
@ -197,7 +202,7 @@ pub(crate) fn new_from_iter<T: ToPyObject>(
|
|||
py: Python<'_>,
|
||||
elements: impl IntoIterator<Item = T>,
|
||||
) -> PyResult<Py<PyFrozenSet>> {
|
||||
fn new_from_iter_inner(
|
||||
fn inner(
|
||||
py: Python<'_>,
|
||||
elements: &mut dyn Iterator<Item = PyObject>,
|
||||
) -> PyResult<Py<PyFrozenSet>> {
|
||||
|
@ -208,16 +213,14 @@ pub(crate) fn new_from_iter<T: ToPyObject>(
|
|||
let ptr = set.as_ptr();
|
||||
|
||||
for obj in elements {
|
||||
unsafe {
|
||||
err::error_on_minusone(py, ffi::PySet_Add(ptr, obj.as_ptr()))?;
|
||||
}
|
||||
err::error_on_minusone(py, unsafe { ffi::PySet_Add(ptr, obj.as_ptr()) })?;
|
||||
}
|
||||
|
||||
Ok(set)
|
||||
}
|
||||
|
||||
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)]
|
||||
|
|
|
@ -167,16 +167,13 @@ impl PyList {
|
|||
where
|
||||
I: ToPyObject,
|
||||
{
|
||||
unsafe {
|
||||
err::error_on_minusone(
|
||||
self.py(),
|
||||
ffi::PyList_SetItem(
|
||||
self.as_ptr(),
|
||||
get_ssize_index(index),
|
||||
item.to_object(self.py()).into_ptr(),
|
||||
),
|
||||
)
|
||||
fn inner(list: &PyList, index: usize, item: PyObject) -> PyResult<()> {
|
||||
err::error_on_minusone(list.py(), unsafe {
|
||||
ffi::PyList_SetItem(list.as_ptr(), get_ssize_index(index), item.into_ptr())
|
||||
})
|
||||
}
|
||||
|
||||
inner(self, index, item.to_object(self.py()))
|
||||
}
|
||||
|
||||
/// Deletes the `index`th element of self.
|
||||
|
@ -192,17 +189,14 @@ impl PyList {
|
|||
/// This is equivalent to the Python statement `self[low:high] = v`.
|
||||
#[inline]
|
||||
pub fn set_slice(&self, low: usize, high: usize, seq: &PyAny) -> PyResult<()> {
|
||||
unsafe {
|
||||
err::error_on_minusone(
|
||||
self.py(),
|
||||
err::error_on_minusone(self.py(), unsafe {
|
||||
ffi::PyList_SetSlice(
|
||||
self.as_ptr(),
|
||||
get_ssize_index(low),
|
||||
get_ssize_index(high),
|
||||
seq.as_ptr(),
|
||||
),
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Deletes the slice from `low` to `high` from `self`.
|
||||
|
@ -218,13 +212,13 @@ impl PyList {
|
|||
where
|
||||
I: ToPyObject,
|
||||
{
|
||||
let py = self.py();
|
||||
unsafe {
|
||||
err::error_on_minusone(
|
||||
py,
|
||||
ffi::PyList_Append(self.as_ptr(), item.to_object(py).as_ptr()),
|
||||
)
|
||||
fn inner(list: &PyList, item: PyObject) -> PyResult<()> {
|
||||
err::error_on_minusone(list.py(), unsafe {
|
||||
ffi::PyList_Append(list.as_ptr(), item.as_ptr())
|
||||
})
|
||||
}
|
||||
|
||||
inner(self, item.to_object(self.py()))
|
||||
}
|
||||
|
||||
/// Inserts an item at the specified index.
|
||||
|
@ -234,17 +228,13 @@ impl PyList {
|
|||
where
|
||||
I: ToPyObject,
|
||||
{
|
||||
let py = self.py();
|
||||
unsafe {
|
||||
err::error_on_minusone(
|
||||
py,
|
||||
ffi::PyList_Insert(
|
||||
self.as_ptr(),
|
||||
get_ssize_index(index),
|
||||
item.to_object(py).as_ptr(),
|
||||
),
|
||||
)
|
||||
fn inner(list: &PyList, index: usize, item: PyObject) -> PyResult<()> {
|
||||
err::error_on_minusone(list.py(), unsafe {
|
||||
ffi::PyList_Insert(list.as_ptr(), get_ssize_index(index), item.as_ptr())
|
||||
})
|
||||
}
|
||||
|
||||
inner(self, index, item.to_object(self.py()))
|
||||
}
|
||||
|
||||
/// Determines if self contains `value`.
|
||||
|
@ -279,12 +269,12 @@ impl PyList {
|
|||
|
||||
/// Sorts the list in-place. Equivalent to the Python expression `l.sort()`.
|
||||
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()`.
|
||||
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)`.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use crate::err::{PyDowncastError, PyErr, PyResult};
|
||||
use crate::err::{PyDowncastError, PyResult};
|
||||
use crate::sync::GILOnceCell;
|
||||
use crate::type_object::PyTypeInfo;
|
||||
use crate::types::{PyAny, PyDict, PySequence, PyType};
|
||||
|
@ -17,12 +17,9 @@ impl PyMapping {
|
|||
#[inline]
|
||||
pub fn len(&self) -> PyResult<usize> {
|
||||
let v = unsafe { ffi::PyMapping_Size(self.as_ptr()) };
|
||||
if v == -1 {
|
||||
Err(PyErr::fetch(self.py()))
|
||||
} else {
|
||||
crate::err::error_on_minusone(self.py(), v)?;
|
||||
Ok(v as usize)
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns whether the mapping is empty.
|
||||
#[inline]
|
||||
|
|
|
@ -6,7 +6,7 @@ use crate::internal_tricks::get_ssize_index;
|
|||
use crate::sync::GILOnceCell;
|
||||
use crate::type_object::PyTypeInfo;
|
||||
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::{FromPyObject, PyTryFrom};
|
||||
|
||||
|
@ -23,12 +23,9 @@ impl PySequence {
|
|||
#[inline]
|
||||
pub fn len(&self) -> PyResult<usize> {
|
||||
let v = unsafe { ffi::PySequence_Size(self.as_ptr()) };
|
||||
if v == -1 {
|
||||
Err(PyErr::fetch(self.py()))
|
||||
} else {
|
||||
crate::err::error_on_minusone(self.py(), v)?;
|
||||
Ok(v as usize)
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns whether the sequence is empty.
|
||||
#[inline]
|
||||
|
@ -128,17 +125,13 @@ impl PySequence {
|
|||
where
|
||||
I: ToPyObject,
|
||||
{
|
||||
let py = self.py();
|
||||
unsafe {
|
||||
err::error_on_minusone(
|
||||
py,
|
||||
ffi::PySequence_SetItem(
|
||||
self.as_ptr(),
|
||||
get_ssize_index(i),
|
||||
item.to_object(py).as_ptr(),
|
||||
),
|
||||
)
|
||||
fn inner(seq: &PySequence, i: usize, item: PyObject) -> PyResult<()> {
|
||||
err::error_on_minusone(seq.py(), unsafe {
|
||||
ffi::PySequence_SetItem(seq.as_ptr(), get_ssize_index(i), item.as_ptr())
|
||||
})
|
||||
}
|
||||
|
||||
inner(self, i, item.to_object(self.py()))
|
||||
}
|
||||
|
||||
/// Deletes the `i`th element of self.
|
||||
|
@ -146,12 +139,9 @@ impl PySequence {
|
|||
/// This is equivalent to the Python statement `del self[i]`.
|
||||
#[inline]
|
||||
pub fn del_item(&self, i: usize) -> PyResult<()> {
|
||||
unsafe {
|
||||
err::error_on_minusone(
|
||||
self.py(),
|
||||
ffi::PySequence_DelItem(self.as_ptr(), get_ssize_index(i)),
|
||||
)
|
||||
}
|
||||
err::error_on_minusone(self.py(), unsafe {
|
||||
ffi::PySequence_DelItem(self.as_ptr(), get_ssize_index(i))
|
||||
})
|
||||
}
|
||||
|
||||
/// 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`.
|
||||
#[inline]
|
||||
pub fn set_slice(&self, i1: usize, i2: usize, v: &PyAny) -> PyResult<()> {
|
||||
unsafe {
|
||||
err::error_on_minusone(
|
||||
self.py(),
|
||||
err::error_on_minusone(self.py(), unsafe {
|
||||
ffi::PySequence_SetSlice(
|
||||
self.as_ptr(),
|
||||
get_ssize_index(i1),
|
||||
get_ssize_index(i2),
|
||||
v.as_ptr(),
|
||||
),
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// 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]`.
|
||||
#[inline]
|
||||
pub fn del_slice(&self, i1: usize, i2: usize) -> PyResult<()> {
|
||||
unsafe {
|
||||
err::error_on_minusone(
|
||||
self.py(),
|
||||
ffi::PySequence_DelSlice(self.as_ptr(), get_ssize_index(i1), get_ssize_index(i2)),
|
||||
)
|
||||
}
|
||||
err::error_on_minusone(self.py(), unsafe {
|
||||
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
|
||||
|
@ -193,13 +177,13 @@ impl PySequence {
|
|||
where
|
||||
V: ToPyObject,
|
||||
{
|
||||
let r =
|
||||
unsafe { ffi::PySequence_Count(self.as_ptr(), value.to_object(self.py()).as_ptr()) };
|
||||
if r == -1 {
|
||||
Err(PyErr::fetch(self.py()))
|
||||
} else {
|
||||
fn inner(seq: &PySequence, value: PyObject) -> PyResult<usize> {
|
||||
let r = unsafe { ffi::PySequence_Count(seq.as_ptr(), value.as_ptr()) };
|
||||
crate::err::error_on_minusone(seq.py(), r)?;
|
||||
Ok(r as usize)
|
||||
}
|
||||
|
||||
inner(self, value.to_object(self.py()))
|
||||
}
|
||||
|
||||
/// Determines if self contains `value`.
|
||||
|
@ -210,15 +194,18 @@ impl PySequence {
|
|||
where
|
||||
V: ToPyObject,
|
||||
{
|
||||
let r =
|
||||
unsafe { ffi::PySequence_Contains(self.as_ptr(), value.to_object(self.py()).as_ptr()) };
|
||||
fn inner(seq: &PySequence, value: PyObject) -> PyResult<bool> {
|
||||
let r = unsafe { ffi::PySequence_Contains(seq.as_ptr(), value.as_ptr()) };
|
||||
match r {
|
||||
0 => Ok(false),
|
||||
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`.
|
||||
///
|
||||
/// This is equivalent to the Python expression `self.index(value)`.
|
||||
|
@ -227,13 +214,13 @@ impl PySequence {
|
|||
where
|
||||
V: ToPyObject,
|
||||
{
|
||||
let r =
|
||||
unsafe { ffi::PySequence_Index(self.as_ptr(), value.to_object(self.py()).as_ptr()) };
|
||||
if r == -1 {
|
||||
Err(PyErr::fetch(self.py()))
|
||||
} else {
|
||||
fn inner(seq: &PySequence, value: PyObject) -> PyResult<usize> {
|
||||
let r = unsafe { ffi::PySequence_Index(seq.as_ptr(), value.as_ptr()) };
|
||||
crate::err::error_on_minusone(seq.py(), r)?;
|
||||
Ok(r as usize)
|
||||
}
|
||||
|
||||
inner(self, value.to_object(self.py()))
|
||||
}
|
||||
|
||||
/// Returns a fresh list based on the Sequence.
|
||||
|
|
|
@ -71,13 +71,15 @@ impl PySet {
|
|||
where
|
||||
K: ToPyObject,
|
||||
{
|
||||
unsafe {
|
||||
match ffi::PySet_Contains(self.as_ptr(), key.to_object(self.py()).as_ptr()) {
|
||||
fn inner(set: &PySet, key: PyObject) -> PyResult<bool> {
|
||||
match unsafe { ffi::PySet_Contains(set.as_ptr(), key.as_ptr()) } {
|
||||
1 => Ok(true),
|
||||
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.
|
||||
|
@ -88,14 +90,12 @@ impl PySet {
|
|||
K: ToPyObject,
|
||||
{
|
||||
fn inner(set: &PySet, key: PyObject) -> PyResult<bool> {
|
||||
unsafe {
|
||||
match ffi::PySet_Discard(set.as_ptr(), key.as_ptr()) {
|
||||
match unsafe { ffi::PySet_Discard(set.as_ptr(), key.as_ptr()) } {
|
||||
1 => Ok(true),
|
||||
0 => Ok(false),
|
||||
_ => Err(PyErr::fetch(set.py())),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inner(self, key.to_object(self.py()))
|
||||
}
|
||||
|
@ -105,12 +105,13 @@ impl PySet {
|
|||
where
|
||||
K: ToPyObject,
|
||||
{
|
||||
unsafe {
|
||||
err::error_on_minusone(
|
||||
self.py(),
|
||||
ffi::PySet_Add(self.as_ptr(), key.to_object(self.py()).as_ptr()),
|
||||
)
|
||||
fn inner(set: &PySet, key: PyObject) -> PyResult<()> {
|
||||
err::error_on_minusone(set.py(), unsafe {
|
||||
ffi::PySet_Add(set.as_ptr(), key.as_ptr())
|
||||
})
|
||||
}
|
||||
|
||||
inner(self, key.to_object(self.py()))
|
||||
}
|
||||
|
||||
/// Removes and returns an arbitrary element from the set.
|
||||
|
@ -248,10 +249,7 @@ pub(crate) fn new_from_iter<T: ToPyObject>(
|
|||
py: Python<'_>,
|
||||
elements: impl IntoIterator<Item = T>,
|
||||
) -> PyResult<Py<PySet>> {
|
||||
fn new_from_iter_inner(
|
||||
py: Python<'_>,
|
||||
elements: &mut dyn Iterator<Item = PyObject>,
|
||||
) -> PyResult<Py<PySet>> {
|
||||
fn inner(py: Python<'_>, elements: &mut dyn Iterator<Item = PyObject>) -> PyResult<Py<PySet>> {
|
||||
let set: Py<PySet> = unsafe {
|
||||
// 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()))?
|
||||
|
@ -259,16 +257,14 @@ pub(crate) fn new_from_iter<T: ToPyObject>(
|
|||
let ptr = set.as_ptr();
|
||||
|
||||
for obj in elements {
|
||||
unsafe {
|
||||
err::error_on_minusone(py, ffi::PySet_Add(ptr, obj.as_ptr()))?;
|
||||
}
|
||||
err::error_on_minusone(py, unsafe { ffi::PySet_Add(ptr, obj.as_ptr()) })?;
|
||||
}
|
||||
|
||||
Ok(set)
|
||||
}
|
||||
|
||||
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)]
|
||||
|
|
|
@ -19,5 +19,5 @@ error[E0308]: mismatched types
|
|||
note: function defined here
|
||||
--> src/impl_/pymethods.rs
|
||||
|
|
||||
| pub unsafe fn call_traverse_impl<T>(
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
| pub unsafe fn _call_traverse<T>(
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
|
Loading…
Reference in a new issue