feature gate APIs using `into_gil_ref` (Part 1) (#4160)

This commit is contained in:
Icxolu 2024-05-09 09:58:44 +02:00 committed by GitHub
parent d803f7f8df
commit 635cb8075c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
22 changed files with 339 additions and 256 deletions

View File

@ -186,11 +186,11 @@ mod tests {
Python::with_gil(|py| { Python::with_gil(|py| {
let array: [f32; 4] = [0.0, -16.0, 16.0, 42.0]; let array: [f32; 4] = [0.0, -16.0, 16.0, 42.0];
let pyobject = array.to_object(py); let pyobject = array.to_object(py);
let pylist: &PyList = pyobject.extract(py).unwrap(); let pylist = pyobject.downcast_bound::<PyList>(py).unwrap();
assert_eq!(pylist[0].extract::<f32>().unwrap(), 0.0); assert_eq!(pylist.get_item(0).unwrap().extract::<f32>().unwrap(), 0.0);
assert_eq!(pylist[1].extract::<f32>().unwrap(), -16.0); assert_eq!(pylist.get_item(1).unwrap().extract::<f32>().unwrap(), -16.0);
assert_eq!(pylist[2].extract::<f32>().unwrap(), 16.0); assert_eq!(pylist.get_item(2).unwrap().extract::<f32>().unwrap(), 16.0);
assert_eq!(pylist[3].extract::<f32>().unwrap(), 42.0); assert_eq!(pylist.get_item(3).unwrap().extract::<f32>().unwrap(), 42.0);
}); });
} }
@ -213,11 +213,11 @@ mod tests {
Python::with_gil(|py| { Python::with_gil(|py| {
let array: [f32; 4] = [0.0, -16.0, 16.0, 42.0]; let array: [f32; 4] = [0.0, -16.0, 16.0, 42.0];
let pyobject = array.into_py(py); let pyobject = array.into_py(py);
let pylist: &PyList = pyobject.extract(py).unwrap(); let pylist = pyobject.downcast_bound::<PyList>(py).unwrap();
assert_eq!(pylist[0].extract::<f32>().unwrap(), 0.0); assert_eq!(pylist.get_item(0).unwrap().extract::<f32>().unwrap(), 0.0);
assert_eq!(pylist[1].extract::<f32>().unwrap(), -16.0); assert_eq!(pylist.get_item(1).unwrap().extract::<f32>().unwrap(), -16.0);
assert_eq!(pylist[2].extract::<f32>().unwrap(), 16.0); assert_eq!(pylist.get_item(2).unwrap().extract::<f32>().unwrap(), 16.0);
assert_eq!(pylist[3].extract::<f32>().unwrap(), 42.0); assert_eq!(pylist.get_item(3).unwrap().extract::<f32>().unwrap(), 42.0);
}); });
} }

View File

@ -667,6 +667,7 @@ impl<'py, T> Borrowed<'py, 'py, T>
where where
T: HasPyGilRef, T: HasPyGilRef,
{ {
#[cfg(feature = "gil-refs")]
pub(crate) fn into_gil_ref(self) -> &'py T::AsRefTarget { pub(crate) fn into_gil_ref(self) -> &'py T::AsRefTarget {
// Safety: self is a borrow over `'py`. // Safety: self is a borrow over `'py`.
#[allow(deprecated)] #[allow(deprecated)]

View File

@ -46,6 +46,7 @@ pub(crate) fn get_ssize_index(index: usize) -> Py_ssize_t {
} }
/// Implementations used for slice indexing PySequence, PyTuple, and PyList /// Implementations used for slice indexing PySequence, PyTuple, and PyList
#[cfg(feature = "gil-refs")]
macro_rules! index_impls { macro_rules! index_impls {
( (
$ty:ty, $ty:ty,
@ -154,6 +155,7 @@ macro_rules! index_impls {
#[inline(never)] #[inline(never)]
#[cold] #[cold]
#[track_caller] #[track_caller]
#[cfg(feature = "gil-refs")]
pub(crate) fn index_len_fail(index: usize, ty_name: &str, len: usize) -> ! { pub(crate) fn index_len_fail(index: usize, ty_name: &str, len: usize) -> ! {
panic!( panic!(
"index {} out of range for {} of length {}", "index {} out of range for {} of length {}",
@ -164,6 +166,7 @@ pub(crate) fn index_len_fail(index: usize, ty_name: &str, len: usize) -> ! {
#[inline(never)] #[inline(never)]
#[cold] #[cold]
#[track_caller] #[track_caller]
#[cfg(feature = "gil-refs")]
pub(crate) fn slice_start_index_len_fail(index: usize, ty_name: &str, len: usize) -> ! { pub(crate) fn slice_start_index_len_fail(index: usize, ty_name: &str, len: usize) -> ! {
panic!( panic!(
"range start index {} out of range for {} of length {}", "range start index {} out of range for {} of length {}",
@ -174,6 +177,7 @@ pub(crate) fn slice_start_index_len_fail(index: usize, ty_name: &str, len: usize
#[inline(never)] #[inline(never)]
#[cold] #[cold]
#[track_caller] #[track_caller]
#[cfg(feature = "gil-refs")]
pub(crate) fn slice_end_index_len_fail(index: usize, ty_name: &str, len: usize) -> ! { pub(crate) fn slice_end_index_len_fail(index: usize, ty_name: &str, len: usize) -> ! {
panic!( panic!(
"range end index {} out of range for {} of length {}", "range end index {} out of range for {} of length {}",
@ -184,6 +188,7 @@ pub(crate) fn slice_end_index_len_fail(index: usize, ty_name: &str, len: usize)
#[inline(never)] #[inline(never)]
#[cold] #[cold]
#[track_caller] #[track_caller]
#[cfg(feature = "gil-refs")]
pub(crate) fn slice_index_order_fail(index: usize, end: usize) -> ! { pub(crate) fn slice_index_order_fail(index: usize, end: usize) -> ! {
panic!("slice index starts at {} but ends at {}", index, end); panic!("slice index starts at {} but ends at {}", index, end);
} }

View File

@ -120,8 +120,8 @@ macro_rules! py_run_impl {
/// Wraps a Rust function annotated with [`#[pyfunction]`](macro@crate::pyfunction). /// Wraps a Rust function annotated with [`#[pyfunction]`](macro@crate::pyfunction).
/// ///
/// This can be used with [`PyModule::add_function`](crate::types::PyModule::add_function) to add free /// This can be used with [`PyModule::add_function`](crate::types::PyModuleMethods::add_function) to
/// functions to a [`PyModule`](crate::types::PyModule) - see its documentation for more /// add free functions to a [`PyModule`](crate::types::PyModule) - see its documentation for more
/// information. /// information.
/// ///
/// During the migration from the GIL Ref API to the Bound API, the return type of this macro will /// During the migration from the GIL Ref API to the Bound API, the return type of this macro will
@ -157,8 +157,9 @@ macro_rules! wrap_pyfunction {
/// Wraps a Rust function annotated with [`#[pyfunction]`](macro@crate::pyfunction). /// Wraps a Rust function annotated with [`#[pyfunction]`](macro@crate::pyfunction).
/// ///
/// This can be used with [`PyModule::add_function`](crate::types::PyModule::add_function) to add free /// This can be used with [`PyModule::add_function`](crate::types::PyModuleMethods::add_function) to
/// functions to a [`PyModule`](crate::types::PyModule) - see its documentation for more information. /// add free functions to a [`PyModule`](crate::types::PyModule) - see its documentation for more
/// information.
#[macro_export] #[macro_export]
macro_rules! wrap_pyfunction_bound { macro_rules! wrap_pyfunction_bound {
($function:path) => { ($function:path) => {
@ -183,7 +184,7 @@ macro_rules! wrap_pyfunction_bound {
/// Python module. /// Python module.
/// ///
/// Use this together with [`#[pymodule]`](crate::pymodule) and /// Use this together with [`#[pymodule]`](crate::pymodule) and
/// [`PyModule::add_wrapped`](crate::types::PyModule::add_wrapped). /// [`PyModule::add_wrapped`](crate::types::PyModuleMethods::add_wrapped).
#[macro_export] #[macro_export]
macro_rules! wrap_pymodule { macro_rules! wrap_pymodule {
($module:path) => { ($module:path) => {

View File

@ -114,15 +114,18 @@ mod inner {
} }
impl<'py> CatchWarnings<'py> { impl<'py> CatchWarnings<'py> {
pub fn enter<R>(py: Python<'py>, f: impl FnOnce(&PyList) -> PyResult<R>) -> PyResult<R> { pub fn enter<R>(
py: Python<'py>,
f: impl FnOnce(&Bound<'py, PyList>) -> PyResult<R>,
) -> PyResult<R> {
let warnings = py.import_bound("warnings")?; let warnings = py.import_bound("warnings")?;
let kwargs = [("record", true)].into_py_dict_bound(py); let kwargs = [("record", true)].into_py_dict_bound(py);
let catch_warnings = warnings let catch_warnings = warnings
.getattr("catch_warnings")? .getattr("catch_warnings")?
.call((), Some(&kwargs))?; .call((), Some(&kwargs))?;
let list = catch_warnings.call_method0("__enter__")?.extract()?; let list = catch_warnings.call_method0("__enter__")?.downcast_into()?;
let _guard = Self { catch_warnings }; let _guard = Self { catch_warnings };
f(list) f(&list)
} }
} }
@ -139,6 +142,7 @@ mod inner {
macro_rules! assert_warnings { macro_rules! assert_warnings {
($py:expr, $body:expr, [$(($category:ty, $message:literal)),+] $(,)? ) => {{ ($py:expr, $body:expr, [$(($category:ty, $message:literal)),+] $(,)? ) => {{
$crate::tests::common::CatchWarnings::enter($py, |w| { $crate::tests::common::CatchWarnings::enter($py, |w| {
use $crate::types::{PyListMethods, PyStringMethods};
$body; $body;
let expected_warnings = [$((<$category as $crate::type_object::PyTypeInfo>::type_object_bound($py), $message)),+]; let expected_warnings = [$((<$category as $crate::type_object::PyTypeInfo>::type_object_bound($py), $message)),+];
assert_eq!(w.len(), expected_warnings.len()); assert_eq!(w.len(), expected_warnings.len());

View File

@ -14,6 +14,7 @@ fn foo(_py: crate::Python<'_>, _m: &crate::types::PyModule) -> crate::PyResult<(
::std::result::Result::Ok(()) ::std::result::Result::Ok(())
} }
#[cfg(feature = "gil-refs")]
#[allow(deprecated)] #[allow(deprecated)]
#[crate::pymodule] #[crate::pymodule]
#[pyo3(crate = "crate")] #[pyo3(crate = "crate")]

View File

@ -491,6 +491,7 @@ impl<'a> Borrowed<'a, '_, PyByteArray> {
} }
} }
#[cfg(feature = "gil-refs")]
impl<'py> TryFrom<&'py PyAny> for &'py PyByteArray { impl<'py> TryFrom<&'py PyAny> for &'py PyByteArray {
type Error = crate::PyErr; type Error = crate::PyErr;

View File

@ -59,6 +59,7 @@ mod not_limited_impls {
use super::*; use super::*;
use std::ops::{Add, Div, Mul, Neg, Sub}; use std::ops::{Add, Div, Mul, Neg, Sub};
#[cfg(feature = "gil-refs")]
impl PyComplex { impl PyComplex {
/// Returns `|self|`. /// Returns `|self|`.
pub fn abs(&self) -> c_double { pub fn abs(&self) -> c_double {
@ -94,6 +95,7 @@ mod not_limited_impls {
} }
} }
#[cfg(feature = "gil-refs")]
impl<'py> $trait for &'py PyComplex { impl<'py> $trait for &'py PyComplex {
type Output = &'py PyComplex; type Output = &'py PyComplex;
fn $fn(self, other: &'py PyComplex) -> &'py PyComplex { fn $fn(self, other: &'py PyComplex) -> &'py PyComplex {
@ -136,6 +138,7 @@ mod not_limited_impls {
bin_ops!(Mul, mul, *, ffi::_Py_c_prod); bin_ops!(Mul, mul, *, ffi::_Py_c_prod);
bin_ops!(Div, div, /, ffi::_Py_c_quot); bin_ops!(Div, div, /, ffi::_Py_c_quot);
#[cfg(feature = "gil-refs")]
impl<'py> Neg for &'py PyComplex { impl<'py> Neg for &'py PyComplex {
type Output = &'py PyComplex; type Output = &'py PyComplex;
fn neg(self) -> &'py PyComplex { fn neg(self) -> &'py PyComplex {

View File

@ -6,7 +6,9 @@ use crate::instance::{Borrowed, Bound};
use crate::py_result_ext::PyResultExt; use crate::py_result_ext::PyResultExt;
use crate::types::any::PyAnyMethods; use crate::types::any::PyAnyMethods;
use crate::types::{PyAny, PyList}; use crate::types::{PyAny, PyList};
use crate::{ffi, PyNativeType, Python, ToPyObject}; #[cfg(feature = "gil-refs")]
use crate::PyNativeType;
use crate::{ffi, Python, ToPyObject};
/// Represents a Python `dict`. /// Represents a Python `dict`.
#[repr(transparent)] #[repr(transparent)]
@ -56,34 +58,11 @@ pyobject_native_type_core!(
); );
impl PyDict { impl PyDict {
/// Deprecated form of [`new_bound`][PyDict::new_bound].
#[cfg(feature = "gil-refs")]
#[deprecated(
since = "0.21.0",
note = "`PyDict::new` will be replaced by `PyDict::new_bound` in a future PyO3 version"
)]
#[inline]
pub fn new(py: Python<'_>) -> &PyDict {
Self::new_bound(py).into_gil_ref()
}
/// Creates a new empty dictionary. /// Creates a new empty dictionary.
pub fn new_bound(py: Python<'_>) -> Bound<'_, PyDict> { pub fn new_bound(py: Python<'_>) -> Bound<'_, PyDict> {
unsafe { ffi::PyDict_New().assume_owned(py).downcast_into_unchecked() } unsafe { ffi::PyDict_New().assume_owned(py).downcast_into_unchecked() }
} }
/// Deprecated form of [`from_sequence_bound`][PyDict::from_sequence_bound].
#[cfg(feature = "gil-refs")]
#[deprecated(
since = "0.21.0",
note = "`PyDict::from_sequence` will be replaced by `PyDict::from_sequence_bound` in a future PyO3 version"
)]
#[inline]
#[cfg(not(any(PyPy, GraalPy)))]
pub fn from_sequence(seq: &PyAny) -> PyResult<&PyDict> {
Self::from_sequence_bound(&seq.as_borrowed()).map(Bound::into_gil_ref)
}
/// Creates a new dictionary from the sequence given. /// Creates a new dictionary from the sequence given.
/// ///
/// The sequence must consist of `(PyObject, PyObject)`. This is /// The sequence must consist of `(PyObject, PyObject)`. This is
@ -100,6 +79,30 @@ impl PyDict {
})?; })?;
Ok(dict) Ok(dict)
} }
}
#[cfg(feature = "gil-refs")]
impl PyDict {
/// Deprecated form of [`new_bound`][PyDict::new_bound].
#[deprecated(
since = "0.21.0",
note = "`PyDict::new` will be replaced by `PyDict::new_bound` in a future PyO3 version"
)]
#[inline]
pub fn new(py: Python<'_>) -> &PyDict {
Self::new_bound(py).into_gil_ref()
}
/// Deprecated form of [`from_sequence_bound`][PyDict::from_sequence_bound].
#[deprecated(
since = "0.21.0",
note = "`PyDict::from_sequence` will be replaced by `PyDict::from_sequence_bound` in a future PyO3 version"
)]
#[inline]
#[cfg(not(any(PyPy, GraalPy)))]
pub fn from_sequence(seq: &PyAny) -> PyResult<&PyDict> {
Self::from_sequence_bound(&seq.as_borrowed()).map(Bound::into_gil_ref)
}
/// 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.
/// ///
@ -550,8 +553,10 @@ fn dict_len(dict: &Bound<'_, PyDict>) -> Py_ssize_t {
} }
/// PyO3 implementation of an iterator for a Python `dict` object. /// PyO3 implementation of an iterator for a Python `dict` object.
#[cfg(feature = "gil-refs")]
pub struct PyDictIterator<'py>(BoundDictIterator<'py>); pub struct PyDictIterator<'py>(BoundDictIterator<'py>);
#[cfg(feature = "gil-refs")]
impl<'py> Iterator for PyDictIterator<'py> { impl<'py> Iterator for PyDictIterator<'py> {
type Item = (&'py PyAny, &'py PyAny); type Item = (&'py PyAny, &'py PyAny);
@ -567,12 +572,14 @@ impl<'py> Iterator for PyDictIterator<'py> {
} }
} }
#[cfg(feature = "gil-refs")]
impl<'py> ExactSizeIterator for PyDictIterator<'py> { impl<'py> ExactSizeIterator for PyDictIterator<'py> {
fn len(&self) -> usize { fn len(&self) -> usize {
self.0.len() self.0.len()
} }
} }
#[cfg(feature = "gil-refs")]
impl<'a> IntoIterator for &'a PyDict { impl<'a> IntoIterator for &'a PyDict {
type Item = (&'a PyAny, &'a PyAny); type Item = (&'a PyAny, &'a PyAny);
type IntoIter = PyDictIterator<'a>; type IntoIter = PyDictIterator<'a>;

View File

@ -1,11 +1,13 @@
use crate::types::PyIterator; use crate::types::PyIterator;
#[cfg(feature = "gil-refs")]
use crate::PyNativeType;
use crate::{ use crate::{
err::{self, PyErr, PyResult}, err::{self, PyErr, PyResult},
ffi, ffi,
ffi_ptr_ext::FfiPtrExt, ffi_ptr_ext::FfiPtrExt,
py_result_ext::PyResultExt, py_result_ext::PyResultExt,
types::any::PyAnyMethods, types::any::PyAnyMethods,
Bound, PyAny, PyNativeType, PyObject, Python, ToPyObject, Bound, PyAny, PyObject, Python, ToPyObject,
}; };
use std::ptr; use std::ptr;
@ -74,20 +76,6 @@ pyobject_native_type_core!(
); );
impl PyFrozenSet { impl PyFrozenSet {
/// Deprecated form of [`PyFrozenSet::new_bound`].
#[inline]
#[cfg(feature = "gil-refs")]
#[deprecated(
since = "0.21.0",
note = "`PyFrozenSet::new` will be replaced by `PyFrozenSet::new_bound` in a future PyO3 version"
)]
pub fn new<'a, 'p, T: ToPyObject + 'a>(
py: Python<'p>,
elements: impl IntoIterator<Item = &'a T>,
) -> PyResult<&'p PyFrozenSet> {
Self::new_bound(py, elements).map(Bound::into_gil_ref)
}
/// Creates a new frozenset. /// Creates a new frozenset.
/// ///
/// May panic when running out of memory. /// May panic when running out of memory.
@ -99,16 +87,6 @@ impl PyFrozenSet {
new_from_iter(py, elements) new_from_iter(py, elements)
} }
/// Deprecated form of [`PyFrozenSet::empty_bound`].
#[cfg(feature = "gil-refs")]
#[deprecated(
since = "0.21.0",
note = "`PyFrozenSet::empty` will be replaced by `PyFrozenSet::empty_bound` in a future PyO3 version"
)]
pub fn empty(py: Python<'_>) -> PyResult<&'_ PyFrozenSet> {
Self::empty_bound(py).map(Bound::into_gil_ref)
}
/// Creates a new empty frozen set /// Creates a new empty frozen set
pub fn empty_bound(py: Python<'_>) -> PyResult<Bound<'_, PyFrozenSet>> { pub fn empty_bound(py: Python<'_>) -> PyResult<Bound<'_, PyFrozenSet>> {
unsafe { unsafe {
@ -117,6 +95,31 @@ impl PyFrozenSet {
.downcast_into_unchecked() .downcast_into_unchecked()
} }
} }
}
#[cfg(feature = "gil-refs")]
impl PyFrozenSet {
/// Deprecated form of [`PyFrozenSet::new_bound`].
#[inline]
#[deprecated(
since = "0.21.0",
note = "`PyFrozenSet::new` will be replaced by `PyFrozenSet::new_bound` in a future PyO3 version"
)]
pub fn new<'a, 'p, T: ToPyObject + 'a>(
py: Python<'p>,
elements: impl IntoIterator<Item = &'a T>,
) -> PyResult<&'p PyFrozenSet> {
Self::new_bound(py, elements).map(Bound::into_gil_ref)
}
/// Deprecated form of [`PyFrozenSet::empty_bound`].
#[deprecated(
since = "0.21.0",
note = "`PyFrozenSet::empty` will be replaced by `PyFrozenSet::empty_bound` in a future PyO3 version"
)]
pub fn empty(py: Python<'_>) -> PyResult<&'_ PyFrozenSet> {
Self::empty_bound(py).map(Bound::into_gil_ref)
}
/// Return the number of items in the set. /// Return the number of items in the set.
/// This is equivalent to len(p) on a set. /// This is equivalent to len(p) on a set.
@ -201,8 +204,10 @@ impl<'py> PyFrozenSetMethods<'py> for Bound<'py, PyFrozenSet> {
} }
/// PyO3 implementation of an iterator for a Python `frozenset` object. /// PyO3 implementation of an iterator for a Python `frozenset` object.
#[cfg(feature = "gil-refs")]
pub struct PyFrozenSetIterator<'py>(BoundFrozenSetIterator<'py>); pub struct PyFrozenSetIterator<'py>(BoundFrozenSetIterator<'py>);
#[cfg(feature = "gil-refs")]
impl<'py> Iterator for PyFrozenSetIterator<'py> { impl<'py> Iterator for PyFrozenSetIterator<'py> {
type Item = &'py super::PyAny; type Item = &'py super::PyAny;
@ -217,6 +222,7 @@ impl<'py> Iterator for PyFrozenSetIterator<'py> {
} }
} }
#[cfg(feature = "gil-refs")]
impl ExactSizeIterator for PyFrozenSetIterator<'_> { impl ExactSizeIterator for PyFrozenSetIterator<'_> {
#[inline] #[inline]
fn len(&self) -> usize { fn len(&self) -> usize {
@ -224,6 +230,7 @@ impl ExactSizeIterator for PyFrozenSetIterator<'_> {
} }
} }
#[cfg(feature = "gil-refs")]
impl<'py> IntoIterator for &'py PyFrozenSet { impl<'py> IntoIterator for &'py PyFrozenSet {
type Item = &'py PyAny; type Item = &'py PyAny;
type IntoIter = PyFrozenSetIterator<'py>; type IntoIter = PyFrozenSetIterator<'py>;

View File

@ -1,9 +1,9 @@
use crate::ffi_ptr_ext::FfiPtrExt; use crate::ffi_ptr_ext::FfiPtrExt;
use crate::instance::Borrowed; use crate::instance::Borrowed;
use crate::py_result_ext::PyResultExt; use crate::py_result_ext::PyResultExt;
use crate::{ffi, AsPyPointer, Bound, PyAny, PyErr, PyResult, PyTypeCheck};
#[cfg(feature = "gil-refs")] #[cfg(feature = "gil-refs")]
use crate::PyDowncastError; use crate::{PyDowncastError, PyNativeType};
use crate::{ffi, AsPyPointer, Bound, PyAny, PyErr, PyNativeType, PyResult, PyTypeCheck};
/// A Python iterator object. /// A Python iterator object.
/// ///
@ -54,6 +54,7 @@ impl PyIterator {
} }
} }
#[cfg(feature = "gil-refs")]
impl<'p> Iterator for &'p PyIterator { impl<'p> Iterator for &'p PyIterator {
type Item = PyResult<&'p PyAny>; type Item = PyResult<&'p PyAny>;

View File

@ -6,7 +6,9 @@ use crate::ffi_ptr_ext::FfiPtrExt;
use crate::instance::Borrowed; use crate::instance::Borrowed;
use crate::internal_tricks::get_ssize_index; use crate::internal_tricks::get_ssize_index;
use crate::types::{PySequence, PyTuple}; use crate::types::{PySequence, PyTuple};
use crate::{Bound, PyAny, PyNativeType, PyObject, Python, ToPyObject}; #[cfg(feature = "gil-refs")]
use crate::PyNativeType;
use crate::{Bound, PyAny, PyObject, Python, ToPyObject};
use crate::types::any::PyAnyMethods; use crate::types::any::PyAnyMethods;
use crate::types::sequence::PySequenceMethods; use crate::types::sequence::PySequenceMethods;
@ -55,26 +57,10 @@ pub(crate) fn new_from_iter<'py>(
} }
impl PyList { impl PyList {
/// Deprecated form of [`PyList::new_bound`].
#[inline]
#[track_caller]
#[cfg(feature = "gil-refs")]
#[deprecated(
since = "0.21.0",
note = "`PyList::new` will be replaced by `PyList::new_bound` in a future PyO3 version"
)]
pub fn new<T, U>(py: Python<'_>, elements: impl IntoIterator<Item = T, IntoIter = U>) -> &PyList
where
T: ToPyObject,
U: ExactSizeIterator<Item = T>,
{
Self::new_bound(py, elements).into_gil_ref()
}
/// Constructs a new list with the given elements. /// Constructs a new list with the given elements.
/// ///
/// If you want to create a [`PyList`] with elements of different or unknown types, or from an /// If you want to create a [`PyList`] with elements of different or unknown types, or from an
/// iterable that doesn't implement [`ExactSizeIterator`], use [`PyList::append`]. /// iterable that doesn't implement [`ExactSizeIterator`], use [`PyListMethods::append`].
/// ///
/// # Examples /// # Examples
/// ///
@ -109,17 +95,6 @@ impl PyList {
new_from_iter(py, &mut iter) new_from_iter(py, &mut iter)
} }
/// Deprecated form of [`PyList::empty_bound`].
#[inline]
#[cfg(feature = "gil-refs")]
#[deprecated(
since = "0.21.0",
note = "`PyList::empty` will be replaced by `PyList::empty_bound` in a future PyO3 version"
)]
pub fn empty(py: Python<'_>) -> &PyList {
Self::empty_bound(py).into_gil_ref()
}
/// Constructs a new empty list. /// Constructs a new empty list.
pub fn empty_bound(py: Python<'_>) -> Bound<'_, PyList> { pub fn empty_bound(py: Python<'_>) -> Bound<'_, PyList> {
unsafe { unsafe {
@ -128,6 +103,34 @@ impl PyList {
.downcast_into_unchecked() .downcast_into_unchecked()
} }
} }
}
#[cfg(feature = "gil-refs")]
impl PyList {
/// Deprecated form of [`PyList::new_bound`].
#[inline]
#[track_caller]
#[deprecated(
since = "0.21.0",
note = "`PyList::new` will be replaced by `PyList::new_bound` in a future PyO3 version"
)]
pub fn new<T, U>(py: Python<'_>, elements: impl IntoIterator<Item = T, IntoIter = U>) -> &PyList
where
T: ToPyObject,
U: ExactSizeIterator<Item = T>,
{
Self::new_bound(py, elements).into_gil_ref()
}
/// Deprecated form of [`PyList::empty_bound`].
#[inline]
#[deprecated(
since = "0.21.0",
note = "`PyList::empty` will be replaced by `PyList::empty_bound` in a future PyO3 version"
)]
pub fn empty(py: Python<'_>) -> &PyList {
Self::empty_bound(py).into_gil_ref()
}
/// Returns the length of the list. /// Returns the length of the list.
pub fn len(&self) -> usize { pub fn len(&self) -> usize {
@ -273,6 +276,7 @@ impl PyList {
} }
} }
#[cfg(feature = "gil-refs")]
index_impls!(PyList, "list", PyList::len, PyList::get_slice); index_impls!(PyList, "list", PyList::len, PyList::get_slice);
/// Implementation of functionality for [`PyList`]. /// Implementation of functionality for [`PyList`].
@ -586,8 +590,10 @@ impl<'py> PyListMethods<'py> for Bound<'py, PyList> {
} }
/// Used by `PyList::iter()`. /// Used by `PyList::iter()`.
#[cfg(feature = "gil-refs")]
pub struct PyListIterator<'a>(BoundListIterator<'a>); pub struct PyListIterator<'a>(BoundListIterator<'a>);
#[cfg(feature = "gil-refs")]
impl<'a> Iterator for PyListIterator<'a> { impl<'a> Iterator for PyListIterator<'a> {
type Item = &'a PyAny; type Item = &'a PyAny;
@ -602,6 +608,7 @@ impl<'a> Iterator for PyListIterator<'a> {
} }
} }
#[cfg(feature = "gil-refs")]
impl<'a> DoubleEndedIterator for PyListIterator<'a> { impl<'a> DoubleEndedIterator for PyListIterator<'a> {
#[inline] #[inline]
fn next_back(&mut self) -> Option<Self::Item> { fn next_back(&mut self) -> Option<Self::Item> {
@ -609,14 +616,17 @@ impl<'a> DoubleEndedIterator for PyListIterator<'a> {
} }
} }
#[cfg(feature = "gil-refs")]
impl<'a> ExactSizeIterator for PyListIterator<'a> { impl<'a> ExactSizeIterator for PyListIterator<'a> {
fn len(&self) -> usize { fn len(&self) -> usize {
self.0.len() self.0.len()
} }
} }
#[cfg(feature = "gil-refs")]
impl FusedIterator for PyListIterator<'_> {} impl FusedIterator for PyListIterator<'_> {}
#[cfg(feature = "gil-refs")]
impl<'a> IntoIterator for &'a PyList { impl<'a> IntoIterator for &'a PyList {
type Item = &'a PyAny; type Item = &'a PyAny;
type IntoIter = PyListIterator<'a>; type IntoIter = PyListIterator<'a>;

View File

@ -1,4 +1,4 @@
use crate::err::{PyDowncastError, PyResult}; use crate::err::PyResult;
use crate::ffi_ptr_ext::FfiPtrExt; use crate::ffi_ptr_ext::FfiPtrExt;
use crate::instance::Bound; use crate::instance::Bound;
use crate::py_result_ext::PyResultExt; use crate::py_result_ext::PyResultExt;
@ -6,7 +6,9 @@ use crate::sync::GILOnceCell;
use crate::type_object::PyTypeInfo; use crate::type_object::PyTypeInfo;
use crate::types::any::PyAnyMethods; use crate::types::any::PyAnyMethods;
use crate::types::{PyAny, PyDict, PySequence, PyType}; use crate::types::{PyAny, PyDict, PySequence, PyType};
use crate::{ffi, Py, PyNativeType, PyTypeCheck, Python, ToPyObject}; #[cfg(feature = "gil-refs")]
use crate::{err::PyDowncastError, PyNativeType};
use crate::{ffi, Py, PyTypeCheck, Python, ToPyObject};
/// Represents a reference to a Python object supporting the mapping protocol. /// Represents a reference to a Python object supporting the mapping protocol.
#[repr(transparent)] #[repr(transparent)]
@ -14,6 +16,18 @@ pub struct PyMapping(PyAny);
pyobject_native_type_named!(PyMapping); pyobject_native_type_named!(PyMapping);
pyobject_native_type_extract!(PyMapping); pyobject_native_type_extract!(PyMapping);
impl PyMapping {
/// Register a pyclass as a subclass of `collections.abc.Mapping` (from the Python standard
/// library). This is equivalent to `collections.abc.Mapping.register(T)` in Python.
/// This registration is required for a pyclass to be downcastable from `PyAny` to `PyMapping`.
pub fn register<T: PyTypeInfo>(py: Python<'_>) -> PyResult<()> {
let ty = T::type_object_bound(py);
get_mapping_abc(py)?.call_method1("register", (ty,))?;
Ok(())
}
}
#[cfg(feature = "gil-refs")]
impl PyMapping { impl PyMapping {
/// Returns the number of objects in the mapping. /// Returns the number of objects in the mapping.
/// ///
@ -92,15 +106,6 @@ impl PyMapping {
pub fn items(&self) -> PyResult<&PySequence> { pub fn items(&self) -> PyResult<&PySequence> {
self.as_borrowed().items().map(Bound::into_gil_ref) self.as_borrowed().items().map(Bound::into_gil_ref)
} }
/// Register a pyclass as a subclass of `collections.abc.Mapping` (from the Python standard
/// library). This is equvalent to `collections.abc.Mapping.register(T)` in Python.
/// This registration is required for a pyclass to be downcastable from `PyAny` to `PyMapping`.
pub fn register<T: PyTypeInfo>(py: Python<'_>) -> PyResult<()> {
let ty = T::type_object_bound(py);
get_mapping_abc(py)?.call_method1("register", (ty,))?;
Ok(())
}
} }
/// Implementation of functionality for [`PyMapping`]. /// Implementation of functionality for [`PyMapping`].
@ -255,6 +260,7 @@ impl PyTypeCheck for PyMapping {
} }
} }
#[cfg(feature = "gil-refs")]
#[allow(deprecated)] #[allow(deprecated)]
impl<'v> crate::PyTryFrom<'v> for PyMapping { impl<'v> crate::PyTryFrom<'v> for PyMapping {
/// Downcasting to `PyMapping` requires the concrete class to be a subclass (or registered /// Downcasting to `PyMapping` requires the concrete class to be a subclass (or registered

View File

@ -1,7 +1,9 @@
use crate::err::PyResult; use crate::err::PyResult;
use crate::ffi_ptr_ext::FfiPtrExt; use crate::ffi_ptr_ext::FfiPtrExt;
use crate::py_result_ext::PyResultExt; use crate::py_result_ext::PyResultExt;
use crate::{ffi, AsPyPointer, Bound, PyAny, PyNativeType}; #[cfg(feature = "gil-refs")]
use crate::PyNativeType;
use crate::{ffi, AsPyPointer, Bound, PyAny};
/// Represents a Python `memoryview`. /// Represents a Python `memoryview`.
#[repr(transparent)] #[repr(transparent)]
@ -31,6 +33,7 @@ impl PyMemoryView {
} }
} }
#[cfg(feature = "gil-refs")]
impl<'py> TryFrom<&'py PyAny> for &'py PyMemoryView { impl<'py> TryFrom<&'py PyAny> for &'py PyMemoryView {
type Error = crate::PyErr; type Error = crate::PyErr;

View File

@ -79,11 +79,17 @@ pub use self::typeobject::{PyType, PyTypeMethods};
/// the Limited API and PyPy, the underlying structures are opaque and that may not be possible. /// the Limited API and PyPy, the underlying structures are opaque and that may not be possible.
/// In these cases the iterators are implemented by forwarding to [`PyIterator`]. /// In these cases the iterators are implemented by forwarding to [`PyIterator`].
pub mod iter { pub mod iter {
pub use super::dict::{BoundDictIterator, PyDictIterator}; pub use super::dict::BoundDictIterator;
pub use super::frozenset::{BoundFrozenSetIterator, PyFrozenSetIterator}; pub use super::frozenset::BoundFrozenSetIterator;
pub use super::list::{BoundListIterator, PyListIterator}; pub use super::list::BoundListIterator;
pub use super::set::{BoundSetIterator, PySetIterator}; pub use super::set::BoundSetIterator;
pub use super::tuple::{BorrowedTupleIterator, BoundTupleIterator, PyTupleIterator}; pub use super::tuple::{BorrowedTupleIterator, BoundTupleIterator};
#[cfg(feature = "gil-refs")]
pub use super::{
dict::PyDictIterator, frozenset::PyFrozenSetIterator, list::PyListIterator,
set::PySetIterator, tuple::PyTupleIterator,
};
} }
/// Python objects that have a base type. /// Python objects that have a base type.

View File

@ -6,11 +6,12 @@ use crate::pyclass::PyClass;
use crate::types::{ use crate::types::{
any::PyAnyMethods, list::PyListMethods, PyAny, PyCFunction, PyDict, PyList, PyString, any::PyAnyMethods, list::PyListMethods, PyAny, PyCFunction, PyDict, PyList, PyString,
}; };
use crate::{exceptions, ffi, Bound, IntoPy, Py, PyNativeType, PyObject, Python}; use crate::{exceptions, ffi, Bound, IntoPy, Py, PyObject, Python};
use std::ffi::CString; use std::ffi::CString;
use std::str; use std::str;
use super::PyStringMethods; #[cfg(feature = "gil-refs")]
use {super::PyStringMethods, crate::PyNativeType};
/// Represents a Python [`module`][1] object. /// Represents a Python [`module`][1] object.
/// ///
@ -25,17 +26,6 @@ pub struct PyModule(PyAny);
pyobject_native_type_core!(PyModule, pyobject_native_static_type_object!(ffi::PyModule_Type), #checkfunction=ffi::PyModule_Check); pyobject_native_type_core!(PyModule, pyobject_native_static_type_object!(ffi::PyModule_Type), #checkfunction=ffi::PyModule_Check);
impl PyModule { impl PyModule {
/// Deprecated form of [`PyModule::new_bound`].
#[inline]
#[cfg(feature = "gil-refs")]
#[deprecated(
since = "0.21.0",
note = "`PyModule::new` will be replaced by `PyModule::new_bound` in a future PyO3 version"
)]
pub fn new<'py>(py: Python<'py>, name: &str) -> PyResult<&'py PyModule> {
Self::new_bound(py, name).map(Bound::into_gil_ref)
}
/// Creates a new module object with the `__name__` attribute set to `name`. /// Creates a new module object with the `__name__` attribute set to `name`.
/// ///
/// # Examples /// # Examples
@ -62,20 +52,6 @@ impl PyModule {
} }
} }
/// Deprecated form of [`PyModule::import_bound`].
#[inline]
#[cfg(feature = "gil-refs")]
#[deprecated(
since = "0.21.0",
note = "`PyModule::import` will be replaced by `PyModule::import_bound` in a future PyO3 version"
)]
pub fn import<N>(py: Python<'_>, name: N) -> PyResult<&PyModule>
where
N: IntoPy<Py<PyString>>,
{
Self::import_bound(py, name).map(Bound::into_gil_ref)
}
/// Imports the Python module with the specified name. /// Imports the Python module with the specified name.
/// ///
/// # Examples /// # Examples
@ -106,22 +82,6 @@ impl PyModule {
} }
} }
/// Deprecated form of [`PyModule::from_code_bound`].
#[inline]
#[cfg(feature = "gil-refs")]
#[deprecated(
since = "0.21.0",
note = "`PyModule::from_code` will be replaced by `PyModule::from_code_bound` in a future PyO3 version"
)]
pub fn from_code<'py>(
py: Python<'py>,
code: &str,
file_name: &str,
module_name: &str,
) -> PyResult<&'py PyModule> {
Self::from_code_bound(py, code, file_name, module_name).map(Bound::into_gil_ref)
}
/// Creates and loads a module named `module_name`, /// Creates and loads a module named `module_name`,
/// containing the Python code passed to `code` /// containing the Python code passed to `code`
/// and pretending to live at `file_name`. /// and pretending to live at `file_name`.
@ -195,6 +155,47 @@ impl PyModule {
.downcast_into() .downcast_into()
} }
} }
}
#[cfg(feature = "gil-refs")]
impl PyModule {
/// Deprecated form of [`PyModule::new_bound`].
#[inline]
#[deprecated(
since = "0.21.0",
note = "`PyModule::new` will be replaced by `PyModule::new_bound` in a future PyO3 version"
)]
pub fn new<'py>(py: Python<'py>, name: &str) -> PyResult<&'py PyModule> {
Self::new_bound(py, name).map(Bound::into_gil_ref)
}
/// Deprecated form of [`PyModule::import_bound`].
#[inline]
#[deprecated(
since = "0.21.0",
note = "`PyModule::import` will be replaced by `PyModule::import_bound` in a future PyO3 version"
)]
pub fn import<N>(py: Python<'_>, name: N) -> PyResult<&PyModule>
where
N: IntoPy<Py<PyString>>,
{
Self::import_bound(py, name).map(Bound::into_gil_ref)
}
/// Deprecated form of [`PyModule::from_code_bound`].
#[inline]
#[deprecated(
since = "0.21.0",
note = "`PyModule::from_code` will be replaced by `PyModule::from_code_bound` in a future PyO3 version"
)]
pub fn from_code<'py>(
py: Python<'py>,
code: &str,
file_name: &str,
module_name: &str,
) -> PyResult<&'py PyModule> {
Self::from_code_bound(py, code, file_name, module_name).map(Bound::into_gil_ref)
}
/// Returns the module's `__dict__` attribute, which contains the module's symbol table. /// Returns the module's `__dict__` attribute, which contains the module's symbol table.
pub fn dict(&self) -> &PyDict { pub fn dict(&self) -> &PyDict {
@ -433,8 +434,9 @@ pub trait PyModuleMethods<'py>: crate::sealed::Sealed {
/// Adds an attribute to the module. /// Adds an attribute to the module.
/// ///
/// For adding classes, functions or modules, prefer to use [`PyModule::add_class`], /// For adding classes, functions or modules, prefer to use [`PyModuleMethods::add_class`],
/// [`PyModule::add_function`] or [`PyModule::add_submodule`] instead, respectively. /// [`PyModuleMethods::add_function`] or [`PyModuleMethods::add_submodule`] instead,
/// respectively.
/// ///
/// # Examples /// # Examples
/// ///
@ -510,7 +512,8 @@ pub trait PyModuleMethods<'py>: crate::sealed::Sealed {
/// Adds a function or a (sub)module to a module, using the functions name as name. /// Adds a function or a (sub)module to a module, using the functions name as name.
/// ///
/// Prefer to use [`PyModule::add_function`] and/or [`PyModule::add_submodule`] instead. /// Prefer to use [`PyModuleMethods::add_function`] and/or [`PyModuleMethods::add_submodule`]
/// instead.
fn add_wrapped<T>(&self, wrapper: &impl Fn(Python<'py>) -> T) -> PyResult<()> fn add_wrapped<T>(&self, wrapper: &impl Fn(Python<'py>) -> T) -> PyResult<()>
where where
T: IntoPyCallbackOutput<PyObject>; T: IntoPyCallbackOutput<PyObject>;

View File

@ -1,4 +1,4 @@
use crate::err::{self, DowncastError, PyDowncastError, PyErr, PyResult}; use crate::err::{self, DowncastError, PyErr, PyResult};
use crate::exceptions::PyTypeError; use crate::exceptions::PyTypeError;
use crate::ffi_ptr_ext::FfiPtrExt; use crate::ffi_ptr_ext::FfiPtrExt;
#[cfg(feature = "experimental-inspect")] #[cfg(feature = "experimental-inspect")]
@ -9,7 +9,9 @@ use crate::py_result_ext::PyResultExt;
use crate::sync::GILOnceCell; use crate::sync::GILOnceCell;
use crate::type_object::PyTypeInfo; use crate::type_object::PyTypeInfo;
use crate::types::{any::PyAnyMethods, PyAny, PyList, PyString, PyTuple, PyType}; use crate::types::{any::PyAnyMethods, PyAny, PyList, PyString, PyTuple, PyType};
use crate::{ffi, FromPyObject, Py, PyNativeType, PyTypeCheck, Python, ToPyObject}; #[cfg(feature = "gil-refs")]
use crate::{err::PyDowncastError, PyNativeType};
use crate::{ffi, FromPyObject, Py, PyTypeCheck, Python, ToPyObject};
/// Represents a reference to a Python object supporting the sequence protocol. /// Represents a reference to a Python object supporting the sequence protocol.
#[repr(transparent)] #[repr(transparent)]
@ -17,6 +19,18 @@ pub struct PySequence(PyAny);
pyobject_native_type_named!(PySequence); pyobject_native_type_named!(PySequence);
pyobject_native_type_extract!(PySequence); pyobject_native_type_extract!(PySequence);
impl PySequence {
/// Register a pyclass as a subclass of `collections.abc.Sequence` (from the Python standard
/// library). This is equivalent to `collections.abc.Sequence.register(T)` in Python.
/// This registration is required for a pyclass to be downcastable from `PyAny` to `PySequence`.
pub fn register<T: PyTypeInfo>(py: Python<'_>) -> PyResult<()> {
let ty = T::type_object_bound(py);
get_sequence_abc(py)?.call_method1("register", (ty,))?;
Ok(())
}
}
#[cfg(feature = "gil-refs")]
impl PySequence { impl PySequence {
/// Returns the number of objects in sequence. /// Returns the number of objects in sequence.
/// ///
@ -175,15 +189,6 @@ impl PySequence {
pub fn to_tuple(&self) -> PyResult<&PyTuple> { pub fn to_tuple(&self) -> PyResult<&PyTuple> {
self.as_borrowed().to_tuple().map(Bound::into_gil_ref) self.as_borrowed().to_tuple().map(Bound::into_gil_ref)
} }
/// Register a pyclass as a subclass of `collections.abc.Sequence` (from the Python standard
/// library). This is equvalent to `collections.abc.Sequence.register(T)` in Python.
/// This registration is required for a pyclass to be downcastable from `PyAny` to `PySequence`.
pub fn register<T: PyTypeInfo>(py: Python<'_>) -> PyResult<()> {
let ty = T::type_object_bound(py);
get_sequence_abc(py)?.call_method1("register", (ty,))?;
Ok(())
}
} }
/// Implementation of functionality for [`PySequence`]. /// Implementation of functionality for [`PySequence`].
@ -465,16 +470,19 @@ impl<'py> PySequenceMethods<'py> for Bound<'py, PySequence> {
} }
#[inline] #[inline]
#[cfg(feature = "gil-refs")]
fn sequence_len(seq: &PySequence) -> usize { fn sequence_len(seq: &PySequence) -> usize {
seq.len().expect("failed to get sequence length") seq.len().expect("failed to get sequence length")
} }
#[inline] #[inline]
#[cfg(feature = "gil-refs")]
fn sequence_slice(seq: &PySequence, start: usize, end: usize) -> &PySequence { fn sequence_slice(seq: &PySequence, start: usize, end: usize) -> &PySequence {
seq.get_slice(start, end) seq.get_slice(start, end)
.expect("sequence slice operation failed") .expect("sequence slice operation failed")
} }
#[cfg(feature = "gil-refs")]
index_impls!(PySequence, "sequence", sequence_len, sequence_slice); index_impls!(PySequence, "sequence", sequence_len, sequence_slice);
impl<'py, T> FromPyObject<'py> for Vec<T> impl<'py, T> FromPyObject<'py> for Vec<T>
@ -539,6 +547,7 @@ impl PyTypeCheck for PySequence {
} }
} }
#[cfg(feature = "gil-refs")]
#[allow(deprecated)] #[allow(deprecated)]
impl<'v> crate::PyTryFrom<'v> for PySequence { impl<'v> crate::PyTryFrom<'v> for PySequence {
/// Downcasting to `PySequence` requires the concrete class to be a subclass (or registered /// Downcasting to `PySequence` requires the concrete class to be a subclass (or registered

View File

@ -1,11 +1,12 @@
use crate::types::PyIterator; use crate::types::PyIterator;
#[cfg(feature = "gil-refs")]
use crate::PyNativeType;
use crate::{ use crate::{
err::{self, PyErr, PyResult}, err::{self, PyErr, PyResult},
ffi_ptr_ext::FfiPtrExt, ffi_ptr_ext::FfiPtrExt,
instance::Bound, instance::Bound,
py_result_ext::PyResultExt, py_result_ext::PyResultExt,
types::any::PyAnyMethods, types::any::PyAnyMethods,
PyNativeType,
}; };
use crate::{ffi, PyAny, PyObject, Python, ToPyObject}; use crate::{ffi, PyAny, PyObject, Python, ToPyObject};
use std::ptr; use std::ptr;
@ -29,9 +30,31 @@ pyobject_native_type_core!(
#checkfunction=ffi::PySet_Check #checkfunction=ffi::PySet_Check
); );
impl PySet {
/// Creates a new set with elements from the given slice.
///
/// Returns an error if some element is not hashable.
#[inline]
pub fn new_bound<'a, 'p, T: ToPyObject + 'a>(
py: Python<'p>,
elements: impl IntoIterator<Item = &'a T>,
) -> PyResult<Bound<'p, PySet>> {
new_from_iter(py, elements)
}
/// Creates a new empty set.
pub fn empty_bound(py: Python<'_>) -> PyResult<Bound<'_, PySet>> {
unsafe {
ffi::PySet_New(ptr::null_mut())
.assume_owned_or_err(py)
.downcast_into_unchecked()
}
}
}
#[cfg(feature = "gil-refs")]
impl PySet { impl PySet {
/// Deprecated form of [`PySet::new_bound`]. /// Deprecated form of [`PySet::new_bound`].
#[cfg(feature = "gil-refs")]
#[deprecated( #[deprecated(
since = "0.21.0", since = "0.21.0",
note = "`PySet::new` will be replaced by `PySet::new_bound` in a future PyO3 version" note = "`PySet::new` will be replaced by `PySet::new_bound` in a future PyO3 version"
@ -44,19 +67,7 @@ impl PySet {
Self::new_bound(py, elements).map(Bound::into_gil_ref) Self::new_bound(py, elements).map(Bound::into_gil_ref)
} }
/// Creates a new set with elements from the given slice.
///
/// Returns an error if some element is not hashable.
#[inline]
pub fn new_bound<'a, 'p, T: ToPyObject + 'a>(
py: Python<'p>,
elements: impl IntoIterator<Item = &'a T>,
) -> PyResult<Bound<'p, PySet>> {
new_from_iter(py, elements)
}
/// Deprecated form of [`PySet::empty_bound`]. /// Deprecated form of [`PySet::empty_bound`].
#[cfg(feature = "gil-refs")]
#[deprecated( #[deprecated(
since = "0.21.2", since = "0.21.2",
note = "`PySet::empty` will be replaced by `PySet::empty_bound` in a future PyO3 version" note = "`PySet::empty` will be replaced by `PySet::empty_bound` in a future PyO3 version"
@ -65,15 +76,6 @@ impl PySet {
Self::empty_bound(py).map(Bound::into_gil_ref) Self::empty_bound(py).map(Bound::into_gil_ref)
} }
/// Creates a new empty set.
pub fn empty_bound(py: Python<'_>) -> PyResult<Bound<'_, PySet>> {
unsafe {
ffi::PySet_New(ptr::null_mut())
.assume_owned_or_err(py)
.downcast_into_unchecked()
}
}
/// Removes all elements from the set. /// Removes all elements from the set.
#[inline] #[inline]
pub fn clear(&self) { pub fn clear(&self) {
@ -259,8 +261,10 @@ impl<'py> PySetMethods<'py> for Bound<'py, PySet> {
} }
/// PyO3 implementation of an iterator for a Python `set` object. /// PyO3 implementation of an iterator for a Python `set` object.
#[cfg(feature = "gil-refs")]
pub struct PySetIterator<'py>(BoundSetIterator<'py>); pub struct PySetIterator<'py>(BoundSetIterator<'py>);
#[cfg(feature = "gil-refs")]
impl<'py> Iterator for PySetIterator<'py> { impl<'py> Iterator for PySetIterator<'py> {
type Item = &'py super::PyAny; type Item = &'py super::PyAny;
@ -279,12 +283,14 @@ impl<'py> Iterator for PySetIterator<'py> {
} }
} }
#[cfg(feature = "gil-refs")]
impl ExactSizeIterator for PySetIterator<'_> { impl ExactSizeIterator for PySetIterator<'_> {
fn len(&self) -> usize { fn len(&self) -> usize {
self.0.len() self.0.len()
} }
} }
#[cfg(feature = "gil-refs")]
impl<'py> IntoIterator for &'py PySet { impl<'py> IntoIterator for &'py PySet {
type Item = &'py PyAny; type Item = &'py PyAny;
type IntoIter = PySetIterator<'py>; type IntoIter = PySetIterator<'py>;

View File

@ -7,9 +7,11 @@ use crate::inspect::types::TypeInfo;
use crate::instance::Borrowed; use crate::instance::Borrowed;
use crate::internal_tricks::get_ssize_index; use crate::internal_tricks::get_ssize_index;
use crate::types::{any::PyAnyMethods, sequence::PySequenceMethods, PyList, PySequence}; use crate::types::{any::PyAnyMethods, sequence::PySequenceMethods, PyList, PySequence};
#[cfg(feature = "gil-refs")]
use crate::PyNativeType;
use crate::{ use crate::{
exceptions, Bound, FromPyObject, IntoPy, Py, PyAny, PyErr, PyNativeType, PyObject, PyResult, exceptions, Bound, FromPyObject, IntoPy, Py, PyAny, PyErr, PyObject, PyResult, Python,
Python, ToPyObject, ToPyObject,
}; };
#[inline] #[inline]
@ -57,24 +59,6 @@ pub struct PyTuple(PyAny);
pyobject_native_type_core!(PyTuple, pyobject_native_static_type_object!(ffi::PyTuple_Type), #checkfunction=ffi::PyTuple_Check); pyobject_native_type_core!(PyTuple, pyobject_native_static_type_object!(ffi::PyTuple_Type), #checkfunction=ffi::PyTuple_Check);
impl PyTuple { impl PyTuple {
/// Deprecated form of `PyTuple::new_bound`.
#[track_caller]
#[cfg(feature = "gil-refs")]
#[deprecated(
since = "0.21.0",
note = "`PyTuple::new` will be replaced by `PyTuple::new_bound` in a future PyO3 version"
)]
pub fn new<T, U>(
py: Python<'_>,
elements: impl IntoIterator<Item = T, IntoIter = U>,
) -> &PyTuple
where
T: ToPyObject,
U: ExactSizeIterator<Item = T>,
{
Self::new_bound(py, elements).into_gil_ref()
}
/// Constructs a new tuple with the given elements. /// Constructs a new tuple with the given elements.
/// ///
/// If you want to create a [`PyTuple`] with elements of different or unknown types, or from an /// If you want to create a [`PyTuple`] with elements of different or unknown types, or from an
@ -114,16 +98,6 @@ impl PyTuple {
new_from_iter(py, &mut elements) new_from_iter(py, &mut elements)
} }
/// Deprecated form of `PyTuple::empty_bound`.
#[cfg(feature = "gil-refs")]
#[deprecated(
since = "0.21.0",
note = "`PyTuple::empty` will be replaced by `PyTuple::empty_bound` in a future PyO3 version"
)]
pub fn empty(py: Python<'_>) -> &PyTuple {
Self::empty_bound(py).into_gil_ref()
}
/// Constructs an empty tuple (on the Python side, a singleton object). /// Constructs an empty tuple (on the Python side, a singleton object).
pub fn empty_bound(py: Python<'_>) -> Bound<'_, PyTuple> { pub fn empty_bound(py: Python<'_>) -> Bound<'_, PyTuple> {
unsafe { unsafe {
@ -132,6 +106,35 @@ impl PyTuple {
.downcast_into_unchecked() .downcast_into_unchecked()
} }
} }
}
#[cfg(feature = "gil-refs")]
impl PyTuple {
/// Deprecated form of `PyTuple::new_bound`.
#[track_caller]
#[deprecated(
since = "0.21.0",
note = "`PyTuple::new` will be replaced by `PyTuple::new_bound` in a future PyO3 version"
)]
pub fn new<T, U>(
py: Python<'_>,
elements: impl IntoIterator<Item = T, IntoIter = U>,
) -> &PyTuple
where
T: ToPyObject,
U: ExactSizeIterator<Item = T>,
{
Self::new_bound(py, elements).into_gil_ref()
}
/// Deprecated form of `PyTuple::empty_bound`.
#[deprecated(
since = "0.21.0",
note = "`PyTuple::empty` will be replaced by `PyTuple::empty_bound` in a future PyO3 version"
)]
pub fn empty(py: Python<'_>) -> &PyTuple {
Self::empty_bound(py).into_gil_ref()
}
/// Gets the length of the tuple. /// Gets the length of the tuple.
pub fn len(&self) -> usize { pub fn len(&self) -> usize {
@ -236,6 +239,7 @@ impl PyTuple {
} }
} }
#[cfg(feature = "gil-refs")]
index_impls!(PyTuple, "tuple", PyTuple::len, PyTuple::get_slice); index_impls!(PyTuple, "tuple", PyTuple::len, PyTuple::get_slice);
/// Implementation of functionality for [`PyTuple`]. /// Implementation of functionality for [`PyTuple`].
@ -443,8 +447,10 @@ impl<'a, 'py> Borrowed<'a, 'py, PyTuple> {
} }
/// Used by `PyTuple::iter()`. /// Used by `PyTuple::iter()`.
#[cfg(feature = "gil-refs")]
pub struct PyTupleIterator<'a>(BorrowedTupleIterator<'a, 'a>); pub struct PyTupleIterator<'a>(BorrowedTupleIterator<'a, 'a>);
#[cfg(feature = "gil-refs")]
impl<'a> Iterator for PyTupleIterator<'a> { impl<'a> Iterator for PyTupleIterator<'a> {
type Item = &'a PyAny; type Item = &'a PyAny;
@ -459,6 +465,7 @@ impl<'a> Iterator for PyTupleIterator<'a> {
} }
} }
#[cfg(feature = "gil-refs")]
impl<'a> DoubleEndedIterator for PyTupleIterator<'a> { impl<'a> DoubleEndedIterator for PyTupleIterator<'a> {
#[inline] #[inline]
fn next_back(&mut self) -> Option<Self::Item> { fn next_back(&mut self) -> Option<Self::Item> {
@ -466,14 +473,17 @@ impl<'a> DoubleEndedIterator for PyTupleIterator<'a> {
} }
} }
#[cfg(feature = "gil-refs")]
impl<'a> ExactSizeIterator for PyTupleIterator<'a> { impl<'a> ExactSizeIterator for PyTupleIterator<'a> {
fn len(&self) -> usize { fn len(&self) -> usize {
self.0.len() self.0.len()
} }
} }
#[cfg(feature = "gil-refs")]
impl FusedIterator for PyTupleIterator<'_> {} impl FusedIterator for PyTupleIterator<'_> {}
#[cfg(feature = "gil-refs")]
impl<'a> IntoIterator for &'a PyTuple { impl<'a> IntoIterator for &'a PyTuple {
type Item = &'a PyAny; type Item = &'a PyAny;
type IntoIter = PyTupleIterator<'a>; type IntoIter = PyTupleIterator<'a>;

View File

@ -10,6 +10,7 @@ fn basic_function(py: pyo3::Python<'_>, x: Option<pyo3::PyObject>) -> pyo3::PyOb
x.unwrap_or_else(|| py.None()) x.unwrap_or_else(|| py.None())
} }
#[cfg(feature = "gil-refs")]
#[allow(deprecated)] #[allow(deprecated)]
#[pyo3::pymodule] #[pyo3::pymodule]
fn basic_module(_py: pyo3::Python<'_>, m: &pyo3::types::PyModule) -> pyo3::PyResult<()> { fn basic_module(_py: pyo3::Python<'_>, m: &pyo3::types::PyModule) -> pyo3::PyResult<()> {
@ -108,7 +109,7 @@ impl BasicClass {
#[test] #[test]
fn test_basic() { fn test_basic() {
pyo3::Python::with_gil(|py| { pyo3::Python::with_gil(|py| {
let module = pyo3::wrap_pymodule!(basic_module)(py); let module = pyo3::wrap_pymodule!(basic_module_bound)(py);
let cls = py.get_type_bound::<BasicClass>(); let cls = py.get_type_bound::<BasicClass>();
let d = pyo3::types::IntoPyDict::into_py_dict_bound( let d = pyo3::types::IntoPyDict::into_py_dict_bound(
[ [

View File

@ -58,8 +58,8 @@ fn pyfunction_with_module<'py>(module: &Bound<'py, PyModule>) -> PyResult<Bound<
#[pyfunction] #[pyfunction]
#[pyo3(pass_module)] #[pyo3(pass_module)]
fn pyfunction_with_module_gil_ref(module: &PyModule) -> PyResult<&str> { fn pyfunction_with_module_gil_ref(_module: &PyModule) -> PyResult<&str> {
module.name() todo!()
} }
#[pyfunction] #[pyfunction]
@ -68,14 +68,12 @@ fn double(x: usize) -> usize {
} }
#[pymodule] #[pymodule]
fn module_gil_ref(m: &PyModule) -> PyResult<()> { fn module_gil_ref(_m: &PyModule) -> PyResult<()> {
m.add_function(wrap_pyfunction!(double, m)?)?;
Ok(()) Ok(())
} }
#[pymodule] #[pymodule]
fn module_gil_ref_with_explicit_py_arg(_py: Python<'_>, m: &PyModule) -> PyResult<()> { fn module_gil_ref_with_explicit_py_arg(_py: Python<'_>, _m: &PyModule) -> PyResult<()> {
m.add_function(wrap_pyfunction!(double, m)?)?;
Ok(()) Ok(())
} }

View File

@ -53,69 +53,69 @@ error: use of deprecated method `pyo3::deprecations::GilRefs::<T>::function_arg`
| ^ | ^
error: use of deprecated method `pyo3::deprecations::GilRefs::<T>::function_arg`: use `&Bound<'_, T>` instead for this function argument error: use of deprecated method `pyo3::deprecations::GilRefs::<T>::function_arg`: use `&Bound<'_, T>` instead for this function argument
--> tests/ui/deprecations.rs:61:43 --> tests/ui/deprecations.rs:61:44
| |
61 | fn pyfunction_with_module_gil_ref(module: &PyModule) -> PyResult<&str> { 61 | fn pyfunction_with_module_gil_ref(_module: &PyModule) -> PyResult<&str> {
| ^ | ^
error: use of deprecated method `pyo3::deprecations::GilRefs::<T>::function_arg`: use `&Bound<'_, T>` instead for this function argument error: use of deprecated method `pyo3::deprecations::GilRefs::<T>::function_arg`: use `&Bound<'_, T>` instead for this function argument
--> tests/ui/deprecations.rs:71:19 --> tests/ui/deprecations.rs:71:19
| |
71 | fn module_gil_ref(m: &PyModule) -> PyResult<()> { 71 | fn module_gil_ref(_m: &PyModule) -> PyResult<()> {
| ^ | ^^
error: use of deprecated method `pyo3::deprecations::GilRefs::<T>::function_arg`: use `&Bound<'_, T>` instead for this function argument error: use of deprecated method `pyo3::deprecations::GilRefs::<T>::function_arg`: use `&Bound<'_, T>` instead for this function argument
--> tests/ui/deprecations.rs:77:57 --> tests/ui/deprecations.rs:76:57
| |
77 | fn module_gil_ref_with_explicit_py_arg(_py: Python<'_>, m: &PyModule) -> PyResult<()> { 76 | fn module_gil_ref_with_explicit_py_arg(_py: Python<'_>, _m: &PyModule) -> PyResult<()> {
| ^ | ^^
error: use of deprecated method `pyo3::deprecations::GilRefs::<T>::from_py_with_arg`: use `&Bound<'_, PyAny>` as the argument for this `from_py_with` extractor error: use of deprecated method `pyo3::deprecations::GilRefs::<T>::from_py_with_arg`: use `&Bound<'_, PyAny>` as the argument for this `from_py_with` extractor
--> tests/ui/deprecations.rs:110:27 --> tests/ui/deprecations.rs:108:27
| |
110 | #[pyo3(from_py_with = "extract_gil_ref")] _gil_ref: i32, 108 | #[pyo3(from_py_with = "extract_gil_ref")] _gil_ref: i32,
| ^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^
error: use of deprecated method `pyo3::deprecations::GilRefs::<T>::function_arg`: use `&Bound<'_, T>` instead for this function argument error: use of deprecated method `pyo3::deprecations::GilRefs::<T>::function_arg`: use `&Bound<'_, T>` instead for this function argument
--> tests/ui/deprecations.rs:116:29 --> tests/ui/deprecations.rs:114:29
| |
116 | fn pyfunction_gil_ref(_any: &PyAny) {} 114 | fn pyfunction_gil_ref(_any: &PyAny) {}
| ^ | ^
error: use of deprecated method `pyo3::deprecations::OptionGilRefs::<std::option::Option<T>>::function_arg`: use `Option<&Bound<'_, T>>` instead for this function argument error: use of deprecated method `pyo3::deprecations::OptionGilRefs::<std::option::Option<T>>::function_arg`: use `Option<&Bound<'_, T>>` instead for this function argument
--> tests/ui/deprecations.rs:119:36 --> tests/ui/deprecations.rs:117:36
| |
119 | fn pyfunction_option_gil_ref(_any: Option<&PyAny>) {} 117 | fn pyfunction_option_gil_ref(_any: Option<&PyAny>) {}
| ^^^^^^ | ^^^^^^
error: use of deprecated method `pyo3::deprecations::GilRefs::<T>::from_py_with_arg`: use `&Bound<'_, PyAny>` as the argument for this `from_py_with` extractor error: use of deprecated method `pyo3::deprecations::GilRefs::<T>::from_py_with_arg`: use `&Bound<'_, PyAny>` as the argument for this `from_py_with` extractor
--> tests/ui/deprecations.rs:126:27 --> tests/ui/deprecations.rs:124:27
| |
126 | #[pyo3(from_py_with = "PyAny::len", item("my_object"))] 124 | #[pyo3(from_py_with = "PyAny::len", item("my_object"))]
| ^^^^^^^^^^^^ | ^^^^^^^^^^^^
error: use of deprecated method `pyo3::deprecations::GilRefs::<T>::from_py_with_arg`: use `&Bound<'_, PyAny>` as the argument for this `from_py_with` extractor error: use of deprecated method `pyo3::deprecations::GilRefs::<T>::from_py_with_arg`: use `&Bound<'_, PyAny>` as the argument for this `from_py_with` extractor
--> tests/ui/deprecations.rs:136:27 --> tests/ui/deprecations.rs:134:27
| |
136 | #[pyo3(from_py_with = "PyAny::len")] usize, 134 | #[pyo3(from_py_with = "PyAny::len")] usize,
| ^^^^^^^^^^^^ | ^^^^^^^^^^^^
error: use of deprecated method `pyo3::deprecations::GilRefs::<T>::from_py_with_arg`: use `&Bound<'_, PyAny>` as the argument for this `from_py_with` extractor error: use of deprecated method `pyo3::deprecations::GilRefs::<T>::from_py_with_arg`: use `&Bound<'_, PyAny>` as the argument for this `from_py_with` extractor
--> tests/ui/deprecations.rs:142:31 --> tests/ui/deprecations.rs:140:31
| |
142 | Zip(#[pyo3(from_py_with = "extract_gil_ref")] i32), 140 | Zip(#[pyo3(from_py_with = "extract_gil_ref")] i32),
| ^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^
error: use of deprecated method `pyo3::deprecations::GilRefs::<T>::from_py_with_arg`: use `&Bound<'_, PyAny>` as the argument for this `from_py_with` extractor error: use of deprecated method `pyo3::deprecations::GilRefs::<T>::from_py_with_arg`: use `&Bound<'_, PyAny>` as the argument for this `from_py_with` extractor
--> tests/ui/deprecations.rs:149:27 --> tests/ui/deprecations.rs:147:27
| |
149 | #[pyo3(from_py_with = "extract_gil_ref")] 147 | #[pyo3(from_py_with = "extract_gil_ref")]
| ^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^
error: use of deprecated method `pyo3::deprecations::GilRefs::<pyo3::Python<'_>>::is_python`: use `wrap_pyfunction_bound!` instead error: use of deprecated method `pyo3::deprecations::GilRefs::<pyo3::Python<'_>>::is_python`: use `wrap_pyfunction_bound!` instead
--> tests/ui/deprecations.rs:162:13 --> tests/ui/deprecations.rs:160:13
| |
162 | let _ = wrap_pyfunction!(double, py); 160 | let _ = wrap_pyfunction!(double, py);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| |
= note: this error originates in the macro `wrap_pyfunction` (in Nightly builds, run with -Z macro-backtrace for more info) = note: this error originates in the macro `wrap_pyfunction` (in Nightly builds, run with -Z macro-backtrace for more info)