feature gate deprecated APIs for `Python` (#4173)

This commit is contained in:
Icxolu 2024-05-10 20:28:30 +02:00 committed by GitHub
parent 1e8e09dce3
commit 444be3bafa
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 89 additions and 134 deletions

View File

@ -154,8 +154,7 @@ at the end of each loop iteration, before the `with_gil()` closure ends.
When doing this, you must be very careful to ensure that once the `GILPool` is
dropped you do not retain access to any owned references created after the
`GILPool` was created. Read the
[documentation for `Python::new_pool()`]({{#PYO3_DOCS_URL}}/pyo3/marker/struct.Python.html#method.new_pool)
`GILPool` was created. Read the documentation for `Python::new_pool()`
for more information on safety.
This memory management can also be applicable when writing extension modules.

View File

@ -1,14 +1,21 @@
//! Defines conversions between Rust and Python types.
use crate::err::{self, PyDowncastError, PyResult};
use crate::err::PyResult;
#[cfg(feature = "experimental-inspect")]
use crate::inspect::types::TypeInfo;
use crate::pyclass::boolean_struct::False;
use crate::types::any::PyAnyMethods;
use crate::types::PyTuple;
use crate::{
ffi, gil, Borrowed, Bound, Py, PyAny, PyClass, PyNativeType, PyObject, PyRef, PyRefMut, Python,
ffi, Borrowed, Bound, Py, PyAny, PyClass, PyNativeType, PyObject, PyRef, PyRefMut, Python,
};
#[cfg(feature = "gil-refs")]
use {
crate::{
err::{self, PyDowncastError},
gil,
},
std::ptr::NonNull,
};
use std::ptr::NonNull;
/// Returns a borrowed pointer to a Python object.
///
@ -385,6 +392,7 @@ where
/// If `T` implements `PyTryFrom`, we can convert `&PyAny` to `&T`.
///
/// This trait is similar to `std::convert::TryFrom`
#[cfg(feature = "gil-refs")]
#[deprecated(since = "0.21.0")]
pub trait PyTryFrom<'v>: Sized + PyNativeType {
/// Cast from a concrete Python object type to PyObject.
@ -416,6 +424,7 @@ pub trait PyTryFrom<'v>: Sized + PyNativeType {
/// Trait implemented by Python object types that allow a checked downcast.
/// This trait is similar to `std::convert::TryInto`
#[cfg(feature = "gil-refs")]
#[deprecated(since = "0.21.0")]
pub trait PyTryInto<T>: Sized {
/// Cast from PyObject to a concrete Python object type.
@ -506,6 +515,7 @@ impl IntoPy<Py<PyTuple>> for () {
/// # Safety
///
/// See safety notes on individual functions.
#[cfg(feature = "gil-refs")]
#[deprecated(since = "0.21.0")]
pub unsafe trait FromPyPointer<'p>: Sized {
/// Convert from an arbitrary `PyObject`.
@ -515,12 +525,9 @@ pub unsafe trait FromPyPointer<'p>: Sized {
/// Implementations must ensure the object does not get freed during `'p`
/// and ensure that `ptr` is of the correct type.
/// Note that it must be safe to decrement the reference count of `ptr`.
#[cfg_attr(
not(feature = "gil-refs"),
deprecated(
#[deprecated(
since = "0.21.0",
note = "use `Py::from_owned_ptr_or_opt(py, ptr)` or `Bound::from_owned_ptr_or_opt(py, ptr)` instead"
)
)]
unsafe fn from_owned_ptr_or_opt(py: Python<'p>, ptr: *mut ffi::PyObject) -> Option<&'p Self>;
/// Convert from an arbitrary `PyObject` or panic.
@ -528,12 +535,9 @@ pub unsafe trait FromPyPointer<'p>: Sized {
/// # Safety
///
/// Relies on [`from_owned_ptr_or_opt`](#method.from_owned_ptr_or_opt).
#[cfg_attr(
not(feature = "gil-refs"),
deprecated(
#[deprecated(
since = "0.21.0",
note = "use `Py::from_owned_ptr(py, ptr)` or `Bound::from_owned_ptr(py, ptr)` instead"
)
)]
unsafe fn from_owned_ptr_or_panic(py: Python<'p>, ptr: *mut ffi::PyObject) -> &'p Self {
#[allow(deprecated)]
@ -544,12 +548,9 @@ pub unsafe trait FromPyPointer<'p>: Sized {
/// # Safety
///
/// Relies on [`from_owned_ptr_or_opt`](#method.from_owned_ptr_or_opt).
#[cfg_attr(
not(feature = "gil-refs"),
deprecated(
#[deprecated(
since = "0.21.0",
note = "use `Py::from_owned_ptr(py, ptr)` or `Bound::from_owned_ptr(py, ptr)` instead"
)
)]
unsafe fn from_owned_ptr(py: Python<'p>, ptr: *mut ffi::PyObject) -> &'p Self {
#[allow(deprecated)]
@ -560,12 +561,9 @@ pub unsafe trait FromPyPointer<'p>: Sized {
/// # Safety
///
/// Relies on [`from_owned_ptr_or_opt`](#method.from_owned_ptr_or_opt).
#[cfg_attr(
not(feature = "gil-refs"),
deprecated(
#[deprecated(
since = "0.21.0",
note = "use `Py::from_owned_ptr_or_err(py, ptr)` or `Bound::from_owned_ptr_or_err(py, ptr)` instead"
)
)]
unsafe fn from_owned_ptr_or_err(py: Python<'p>, ptr: *mut ffi::PyObject) -> PyResult<&'p Self> {
#[allow(deprecated)]
@ -576,12 +574,9 @@ pub unsafe trait FromPyPointer<'p>: Sized {
/// # Safety
///
/// Implementations must ensure the object does not get freed during `'p` and avoid type confusion.
#[cfg_attr(
not(feature = "gil-refs"),
deprecated(
#[deprecated(
since = "0.21.0",
note = "use `Py::from_borrowed_ptr_or_opt(py, ptr)` or `Bound::from_borrowed_ptr_or_opt(py, ptr)` instead"
)
)]
unsafe fn from_borrowed_ptr_or_opt(py: Python<'p>, ptr: *mut ffi::PyObject)
-> Option<&'p Self>;
@ -590,12 +585,9 @@ pub unsafe trait FromPyPointer<'p>: Sized {
/// # Safety
///
/// Relies on unsafe fn [`from_borrowed_ptr_or_opt`](#method.from_borrowed_ptr_or_opt).
#[cfg_attr(
not(feature = "gil-refs"),
deprecated(
#[deprecated(
since = "0.21.0",
note = "use `Py::from_borrowed_ptr(py, ptr)` or `Bound::from_borrowed_ptr(py, ptr)` instead"
)
)]
unsafe fn from_borrowed_ptr_or_panic(py: Python<'p>, ptr: *mut ffi::PyObject) -> &'p Self {
#[allow(deprecated)]
@ -606,12 +598,9 @@ pub unsafe trait FromPyPointer<'p>: Sized {
/// # Safety
///
/// Relies on unsafe fn [`from_borrowed_ptr_or_opt`](#method.from_borrowed_ptr_or_opt).
#[cfg_attr(
not(feature = "gil-refs"),
deprecated(
#[deprecated(
since = "0.21.0",
note = "use `Py::from_borrowed_ptr(py, ptr)` or `Bound::from_borrowed_ptr(py, ptr)` instead"
)
)]
unsafe fn from_borrowed_ptr(py: Python<'p>, ptr: *mut ffi::PyObject) -> &'p Self {
#[allow(deprecated)]
@ -622,12 +611,9 @@ pub unsafe trait FromPyPointer<'p>: Sized {
/// # Safety
///
/// Relies on unsafe fn [`from_borrowed_ptr_or_opt`](#method.from_borrowed_ptr_or_opt).
#[cfg_attr(
not(feature = "gil-refs"),
deprecated(
#[deprecated(
since = "0.21.0",
note = "use `Py::from_borrowed_ptr_or_err(py, ptr)` or `Bound::from_borrowed_ptr_or_err(py, ptr)` instead"
)
)]
unsafe fn from_borrowed_ptr_or_err(
py: Python<'p>,
@ -638,6 +624,7 @@ pub unsafe trait FromPyPointer<'p>: Sized {
}
}
#[cfg(feature = "gil-refs")]
#[allow(deprecated)]
unsafe impl<'p, T> FromPyPointer<'p> for T
where

View File

@ -366,12 +366,12 @@ pub struct GILPool {
impl GILPool {
/// Creates a new [`GILPool`]. This function should only ever be called with the GIL held.
///
/// It is recommended not to use this API directly, but instead to use [`Python::new_pool`], as
/// It is recommended not to use this API directly, but instead to use `Python::new_pool`, as
/// that guarantees the GIL is held.
///
/// # Safety
///
/// As well as requiring the GIL, see the safety notes on [`Python::new_pool`].
/// As well as requiring the GIL, see the safety notes on `Python::new_pool`.
#[inline]
pub unsafe fn new() -> GILPool {
increment_gil_count();
@ -462,6 +462,7 @@ pub unsafe fn register_decref(obj: NonNull<ffi::PyObject>) {
///
/// # Safety
/// The object must be an owned Python reference.
#[cfg(feature = "gil-refs")]
pub unsafe fn register_owned(_py: Python<'_>, obj: NonNull<ffi::PyObject>) {
debug_assert!(gil_is_acquired());
// Ignores the error in case this function called from `atexit`.
@ -507,9 +508,12 @@ fn decrement_gil_count() {
mod tests {
#[allow(deprecated)]
use super::GILPool;
use super::{gil_is_acquired, GIL_COUNT, OWNED_OBJECTS, POOL};
use super::{gil_is_acquired, GIL_COUNT, POOL};
use crate::types::any::PyAnyMethods;
use crate::{ffi, gil, PyObject, Python};
use crate::{ffi, PyObject, Python};
#[cfg(feature = "gil-refs")]
use {super::OWNED_OBJECTS, crate::gil};
use std::ptr::NonNull;
#[cfg(not(target_arch = "wasm32"))]
use std::sync;
@ -518,6 +522,7 @@ mod tests {
py.eval_bound("object()", None, None).unwrap().unbind()
}
#[cfg(feature = "gil-refs")]
fn owned_object_count() -> usize {
#[cfg(debug_assertions)]
let len = OWNED_OBJECTS.with(|owned_objects| owned_objects.borrow().len());
@ -554,6 +559,7 @@ mod tests {
}
#[test]
#[cfg(feature = "gil-refs")]
#[allow(deprecated)]
fn test_owned() {
Python::with_gil(|py| {
@ -580,6 +586,7 @@ mod tests {
}
#[test]
#[cfg(feature = "gil-refs")]
#[allow(deprecated)]
fn test_owned_nested() {
Python::with_gil(|py| {

View File

@ -317,6 +317,7 @@
//! [`Ungil`]: crate::marker::Ungil
pub use crate::class::*;
pub use crate::conversion::{AsPyPointer, FromPyObject, IntoPy, ToPyObject};
#[cfg(feature = "gil-refs")]
#[allow(deprecated)]
pub use crate::conversion::{FromPyPointer, PyTryFrom, PyTryInto};
pub use crate::err::{

View File

@ -130,6 +130,7 @@ use crate::version::PythonVersionInfo;
use crate::PyNativeType;
use crate::{ffi, Bound, IntoPy, Py, PyObject, PyTypeInfo};
#[allow(deprecated)]
#[cfg(feature = "gil-refs")]
use crate::{gil::GILPool, FromPyPointer};
use std::ffi::{CStr, CString};
use std::marker::PhantomData;
@ -354,36 +355,9 @@ pub use nightly::Ungil;
/// # Releasing and freeing memory
///
/// The [`Python`] type can be used to create references to variables owned by the Python
/// interpreter, using functions such as `Python::eval` and `PyModule::import`. These
/// references are tied to a [`GILPool`] whose references are not cleared until it is dropped.
/// This can cause apparent "memory leaks" if it is kept around for a long time.
/// interpreter, using functions such as [`Python::eval_bound`] and [`PyModule::import_bound`].
///
/// ```rust
/// use pyo3::prelude::*;
/// use pyo3::types::PyString;
///
/// # fn main () -> PyResult<()> {
/// Python::with_gil(|py| -> PyResult<()> {
/// for _ in 0..10 {
/// let hello = py.eval_bound("\"Hello World!\"", None, None)?.downcast_into::<PyString>()?;
/// println!("Python says: {}", hello.to_cow()?);
/// // Normally variables in a loop scope are dropped here, but `hello` is a reference to
/// // something owned by the Python interpreter. Dropping this reference does nothing.
/// }
/// Ok(())
/// })
/// // This is where the `hello`'s reference counts start getting decremented.
/// # }
/// ```
///
/// The variable `hello` is dropped at the end of each loop iteration, but the lifetime of the
/// pointed-to memory is bound to [`Python::with_gil`]'s [`GILPool`] which will not be dropped until
/// the end of [`Python::with_gil`]'s scope. Only then is each `hello`'s Python reference count
/// decreased. This means that at the last line of the example there are 10 copies of `hello` in
/// Python's memory, not just one at a time as we might expect from Rust's [scoping rules].
///
/// See the [Memory Management] chapter of the guide for more information about how PyO3 uses
/// [`GILPool`] to manage memory.
/// See the [Memory Management] chapter of the guide for more information about how PyO3 manages memory.
///
/// [scoping rules]: https://doc.rust-lang.org/stable/book/ch04-01-what-is-ownership.html#ownership-rules
/// [`Py::clone_ref`]: crate::Py::clone_ref
@ -874,12 +848,10 @@ impl<'py> Python<'py> {
///
/// Callers must ensure that ensure that the cast is valid.
#[allow(clippy::wrong_self_convention, deprecated)]
#[cfg_attr(
not(feature = "gil-refs"),
deprecated(
#[cfg(feature = "gil-refs")]
#[deprecated(
since = "0.21.0",
note = "use `Py::from_owned_ptr(py, ptr)` or `Bound::from_owned_ptr(py, ptr)` instead"
)
)]
pub unsafe fn from_owned_ptr<T>(self, ptr: *mut ffi::PyObject) -> &'py T
where
@ -897,12 +869,10 @@ impl<'py> Python<'py> {
///
/// Callers must ensure that ensure that the cast is valid.
#[allow(clippy::wrong_self_convention, deprecated)]
#[cfg_attr(
not(feature = "gil-refs"),
deprecated(
#[cfg(feature = "gil-refs")]
#[deprecated(
since = "0.21.0",
note = "use `Py::from_owned_ptr_or_err(py, ptr)` or `Bound::from_owned_ptr_or_err(py, ptr)` instead"
)
)]
pub unsafe fn from_owned_ptr_or_err<T>(self, ptr: *mut ffi::PyObject) -> PyResult<&'py T>
where
@ -920,12 +890,10 @@ impl<'py> Python<'py> {
///
/// Callers must ensure that ensure that the cast is valid.
#[allow(clippy::wrong_self_convention, deprecated)]
#[cfg_attr(
not(feature = "gil-refs"),
deprecated(
#[cfg(feature = "gil-refs")]
#[deprecated(
since = "0.21.0",
note = "use `Py::from_owned_ptr_or_opt(py, ptr)` or `Bound::from_owned_ptr_or_opt(py, ptr)` instead"
)
)]
pub unsafe fn from_owned_ptr_or_opt<T>(self, ptr: *mut ffi::PyObject) -> Option<&'py T>
where
@ -942,12 +910,10 @@ impl<'py> Python<'py> {
///
/// Callers must ensure that ensure that the cast is valid.
#[allow(clippy::wrong_self_convention, deprecated)]
#[cfg_attr(
not(feature = "gil-refs"),
deprecated(
#[cfg(feature = "gil-refs")]
#[deprecated(
since = "0.21.0",
note = "use `Py::from_borrowed_ptr(py, ptr)` or `Bound::from_borrowed_ptr(py, ptr)` instead"
)
)]
pub unsafe fn from_borrowed_ptr<T>(self, ptr: *mut ffi::PyObject) -> &'py T
where
@ -964,12 +930,10 @@ impl<'py> Python<'py> {
///
/// Callers must ensure that ensure that the cast is valid.
#[allow(clippy::wrong_self_convention, deprecated)]
#[cfg_attr(
not(feature = "gil-refs"),
deprecated(
#[cfg(feature = "gil-refs")]
#[deprecated(
since = "0.21.0",
note = "use `Py::from_borrowed_ptr_or_err(py, ptr)` or `Bound::from_borrowed_ptr_or_err(py, ptr)` instead"
)
)]
pub unsafe fn from_borrowed_ptr_or_err<T>(self, ptr: *mut ffi::PyObject) -> PyResult<&'py T>
where
@ -986,12 +950,10 @@ impl<'py> Python<'py> {
///
/// Callers must ensure that ensure that the cast is valid.
#[allow(clippy::wrong_self_convention, deprecated)]
#[cfg_attr(
not(feature = "gil-refs"),
deprecated(
#[cfg(feature = "gil-refs")]
#[deprecated(
since = "0.21.0",
note = "use `Py::from_borrowed_ptr_or_opt(py, ptr)` or `Bound::from_borrowed_ptr_or_opt(py, ptr)` instead"
)
)]
pub unsafe fn from_borrowed_ptr_or_opt<T>(self, ptr: *mut ffi::PyObject) -> Option<&'py T>
where
@ -1103,12 +1065,10 @@ impl<'py> Python<'py> {
///
/// [`.python()`]: crate::GILPool::python
#[inline]
#[cfg_attr(
not(feature = "gil-refs"),
deprecated(
#[cfg(feature = "gil-refs")]
#[deprecated(
since = "0.21.0",
note = "code not using the GIL Refs API can safely remove use of `Python::new_pool`"
)
)]
#[allow(deprecated)]
pub unsafe fn new_pool(self) -> GILPool {
@ -1172,12 +1132,10 @@ impl Python<'_> {
/// });
/// ```
#[inline]
#[cfg_attr(
not(feature = "gil-refs"),
deprecated(
#[cfg(feature = "gil-refs")]
#[deprecated(
since = "0.21.0",
note = "code not using the GIL Refs API can safely remove use of `Python::with_pool`"
)
)]
#[allow(deprecated)]
pub fn with_pool<F, R>(&self, f: F) -> R

View File

@ -9,6 +9,7 @@
//! ```
pub use crate::conversion::{FromPyObject, IntoPy, ToPyObject};
#[cfg(feature = "gil-refs")]
#[allow(deprecated)]
pub use crate::conversion::{PyTryFrom, PyTryInto};
pub use crate::err::{PyErr, PyResult};

View File

@ -518,6 +518,7 @@ impl<T: PyClass> ToPyObject for &PyCell<T> {
}
}
#[cfg(feature = "gil-refs")]
#[allow(deprecated)]
impl<T: PyClass> AsRef<PyAny> for PyCell<T> {
fn as_ref(&self) -> &PyAny {
@ -528,6 +529,7 @@ impl<T: PyClass> AsRef<PyAny> for PyCell<T> {
}
}
#[cfg(feature = "gil-refs")]
#[allow(deprecated)]
impl<T: PyClass> Deref for PyCell<T> {
type Target = PyAny;