feature gate `as/into_gil_ref` APIs (Part 3) (#4172)

This commit is contained in:
Icxolu 2024-05-10 19:03:57 +02:00 committed by GitHub
parent aef0a05719
commit 1e8e09dce3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
14 changed files with 191 additions and 147 deletions

View File

@ -1649,7 +1649,7 @@ However, for `#[pyproto]` and some functions, you need to manually fix the code.
In 0.8 object creation was done with `PyRef::new` and `PyRefMut::new`.
In 0.9 these have both been removed.
To upgrade code, please use
[`PyCell::new`]({{#PYO3_DOCS_URL}}/pyo3/pycell/struct.PyCell.html#method.new) instead.
`PyCell::new` instead.
If you need [`PyRef`] or [`PyRefMut`], just call `.borrow()` or `.borrow_mut()`
on the newly-created `PyCell`.

View File

@ -446,8 +446,10 @@ Like PyO3's Python native types, the GIL Ref `&PyCell<T>` implements `Deref<Targ
`PyCell<T>` was used to access `&T` and `&mut T` via `PyRef<T>` and `PyRefMut<T>` respectively.
```rust
#![allow(unused_imports)]
# use pyo3::prelude::*;
# #[pyclass] struct MyClass { }
# #[cfg(feature = "gil-refs")]
# Python::with_gil(|py| -> PyResult<()> {
#[allow(deprecated)] // &PyCell is part of the deprecated GIL Refs API
let cell: &PyCell<MyClass> = PyCell::new(py, MyClass {})?;

View File

@ -222,9 +222,7 @@ pub trait FromPyObject<'py>: Sized {
///
/// Implementors are encouraged to implement this method and leave `extract` defaulted, as
/// this will be most compatible with PyO3's future API.
fn extract_bound(ob: &Bound<'py, PyAny>) -> PyResult<Self> {
Self::extract(ob.clone().into_gil_ref())
}
fn extract_bound(ob: &Bound<'py, PyAny>) -> PyResult<Self>;
/// Extracts the type hint information for this type when it appears as an argument.
///
@ -350,8 +348,8 @@ impl<'py, T> FromPyObject<'py> for &'py crate::PyCell<T>
where
T: PyClass,
{
fn extract(obj: &'py PyAny) -> PyResult<Self> {
obj.downcast().map_err(Into::into)
fn extract_bound(obj: &Bound<'py, PyAny>) -> PyResult<Self> {
obj.clone().into_gil_ref().downcast().map_err(Into::into)
}
}

View File

@ -20,8 +20,8 @@ impl<'a> IntoPy<PyObject> for &'a [u8] {
#[cfg(feature = "gil-refs")]
impl<'py> crate::FromPyObject<'py> for &'py [u8] {
fn extract(obj: &'py PyAny) -> PyResult<Self> {
Ok(obj.downcast::<PyBytes>()?.as_bytes())
fn extract_bound(obj: &crate::Bound<'py, PyAny>) -> PyResult<Self> {
Ok(obj.clone().into_gil_ref().downcast::<PyBytes>()?.as_bytes())
}
#[cfg(feature = "experimental-inspect")]

View File

@ -116,8 +116,8 @@ impl<'a> IntoPy<PyObject> for &'a String {
/// Accepts Python `str` objects.
#[cfg(feature = "gil-refs")]
impl<'py> FromPyObject<'py> for &'py str {
fn extract(ob: &'py PyAny) -> PyResult<Self> {
ob.downcast::<PyString>()?.to_str()
fn extract_bound(ob: &Bound<'py, PyAny>) -> PyResult<Self> {
ob.clone().into_gil_ref().downcast::<PyString>()?.to_str()
}
#[cfg(feature = "experimental-inspect")]

View File

@ -4,6 +4,7 @@ use crate::{exceptions::PyTypeError, FromPyObject, PyAny, PyErr, PyResult, Pytho
pub enum Extractor<'a, 'py, T> {
Bound(fn(&'a Bound<'py, PyAny>) -> PyResult<T>),
#[cfg(feature = "gil-refs")]
GilRef(fn(&'a PyAny) -> PyResult<T>),
}
@ -13,6 +14,7 @@ impl<'a, 'py, T> From<fn(&'a Bound<'py, PyAny>) -> PyResult<T>> for Extractor<'a
}
}
#[cfg(feature = "gil-refs")]
impl<'a, T> From<fn(&'a PyAny) -> PyResult<T>> for Extractor<'a, '_, T> {
fn from(value: fn(&'a PyAny) -> PyResult<T>) -> Self {
Self::GilRef(value)
@ -23,6 +25,7 @@ impl<'a, 'py, T> Extractor<'a, 'py, T> {
pub(crate) fn call(self, obj: &'a Bound<'py, PyAny>) -> PyResult<T> {
match self {
Extractor::Bound(f) => f(obj),
#[cfg(feature = "gil-refs")]
Extractor::GilRef(f) => f(obj.as_gil_ref()),
}
}

View File

@ -1,6 +1,6 @@
use crate::{
types::{PyCFunction, PyModule},
Borrowed, Bound, PyNativeType, PyResult, Python,
Borrowed, Bound, PyResult, Python,
};
pub use crate::impl_::pymethods::PyMethodDef;
@ -37,14 +37,24 @@ impl<'py> WrapPyFunctionArg<'py, Bound<'py, PyCFunction>> for &'_ Borrowed<'_, '
// For Python<'py>, only the GIL Ref form exists to avoid causing type inference to kick in.
// The `wrap_pyfunction_bound!` macro is needed for the Bound form.
#[cfg(feature = "gil-refs")]
impl<'py> WrapPyFunctionArg<'py, &'py PyCFunction> for Python<'py> {
fn wrap_pyfunction(self, method_def: &PyMethodDef) -> PyResult<&'py PyCFunction> {
PyCFunction::internal_new(self, method_def, None).map(Bound::into_gil_ref)
}
}
#[cfg(not(feature = "gil-refs"))]
impl<'py> WrapPyFunctionArg<'py, Bound<'py, PyCFunction>> for Python<'py> {
fn wrap_pyfunction(self, method_def: &PyMethodDef) -> PyResult<Bound<'py, PyCFunction>> {
PyCFunction::internal_new(self, method_def, None)
}
}
#[cfg(feature = "gil-refs")]
impl<'py> WrapPyFunctionArg<'py, &'py PyCFunction> for &'py PyModule {
fn wrap_pyfunction(self, method_def: &PyMethodDef) -> PyResult<&'py PyCFunction> {
use crate::PyNativeType;
PyCFunction::internal_new(self.py(), method_def, Some(&self.as_borrowed()))
.map(Bound::into_gil_ref)
}
@ -62,6 +72,7 @@ where
}
}
#[cfg(feature = "gil-refs")]
impl<'py> WrapPyFunctionArg<'py, Bound<'py, PyCFunction>> for OnlyBound<Python<'py>> {
fn wrap_pyfunction(self, method_def: &PyMethodDef) -> PyResult<Bound<'py, PyCFunction>> {
PyCFunction::internal_new(self.0, method_def, None)

View File

@ -5,7 +5,9 @@ use crate::impl_::panic::PanicTrap;
use crate::internal_tricks::extract_c_string;
use crate::pycell::{PyBorrowError, PyBorrowMutError};
use crate::pyclass::boolean_struct::False;
use crate::types::{any::PyAnyMethods, PyModule, PyType};
use crate::types::any::PyAnyMethods;
#[cfg(feature = "gil-refs")]
use crate::types::{PyModule, PyType};
use crate::{
ffi, Borrowed, Bound, DowncastError, Py, PyAny, PyClass, PyClassInitializer, PyErr, PyObject,
PyRef, PyRefMut, PyResult, PyTraverseError, PyTypeCheck, PyVisit, Python,
@ -492,6 +494,7 @@ impl<'a, 'py> BoundRef<'a, 'py, PyAny> {
// GIL Ref implementations for &'a T ran into trouble with orphan rules,
// so explicit implementations are used instead for the two relevant types.
#[cfg(feature = "gil-refs")]
impl<'a> From<BoundRef<'a, 'a, PyType>> for &'a PyType {
#[inline]
fn from(bound: BoundRef<'a, 'a, PyType>) -> Self {
@ -499,6 +502,7 @@ impl<'a> From<BoundRef<'a, 'a, PyType>> for &'a PyType {
}
}
#[cfg(feature = "gil-refs")]
impl<'a> From<BoundRef<'a, 'a, PyModule>> for &'a PyModule {
#[inline]
fn from(bound: BoundRef<'a, 'a, PyModule>) -> Self {
@ -507,6 +511,7 @@ impl<'a> From<BoundRef<'a, 'a, PyModule>> for &'a PyModule {
}
#[allow(deprecated)]
#[cfg(feature = "gil-refs")]
impl<'a, 'py, T: PyClass> From<BoundRef<'a, 'py, T>> for &'a crate::PyCell<T> {
#[inline]
fn from(bound: BoundRef<'a, 'py, T>) -> Self {
@ -518,7 +523,7 @@ impl<'a, 'py, T: PyClass> TryFrom<BoundRef<'a, 'py, T>> for PyRef<'py, T> {
type Error = PyBorrowError;
#[inline]
fn try_from(value: BoundRef<'a, 'py, T>) -> Result<Self, Self::Error> {
value.0.clone().into_gil_ref().try_into()
value.0.try_borrow()
}
}
@ -526,7 +531,7 @@ impl<'a, 'py, T: PyClass<Frozen = False>> TryFrom<BoundRef<'a, 'py, T>> for PyRe
type Error = PyBorrowMutError;
#[inline]
fn try_from(value: BoundRef<'a, 'py, T>) -> Result<Self, Self::Error> {
value.0.clone().into_gil_ref().try_into()
value.0.try_borrow_mut()
}
}

View File

@ -492,6 +492,7 @@ impl<'py, T> Bound<'py, T> {
///
/// This is a helper to be used for migration from the deprecated "GIL Refs" API.
#[inline]
#[cfg(feature = "gil-refs")]
pub fn as_gil_ref(&'py self) -> &'py T::AsRefTarget
where
T: HasPyGilRef,
@ -507,6 +508,7 @@ impl<'py, T> Bound<'py, T> {
///
/// This is a helper to be used for migration from the deprecated "GIL Refs" API.
#[inline]
#[cfg(feature = "gil-refs")]
pub fn into_gil_ref(self) -> &'py T::AsRefTarget
where
T: HasPyGilRef,

View File

@ -201,11 +201,12 @@ use crate::pyclass::{
boolean_struct::{False, True},
PyClass,
};
use crate::pyclass_init::PyClassInitializer;
use crate::type_object::{PyLayout, PySizedLayout};
use crate::types::any::PyAnyMethods;
use crate::types::PyAny;
use crate::{ffi, Bound, IntoPy, PyErr, PyNativeType, PyObject, PyResult, PyTypeCheck, Python};
use crate::{ffi, Bound, IntoPy, PyErr, PyNativeType, PyObject, PyTypeCheck, Python};
#[cfg(feature = "gil-refs")]
use crate::{pyclass_init::PyClassInitializer, PyResult};
use std::fmt;
use std::mem::ManuallyDrop;
use std::ops::{Deref, DerefMut};
@ -222,7 +223,7 @@ use self::impl_::{PyClassObject, PyClassObjectLayout};
/// # Examples
///
/// This example demonstrates getting a mutable reference of the contained `PyClass`.
/// ```rust
/// ```rust,ignore
/// use pyo3::prelude::*;
///
/// #[pyclass]
@ -272,12 +273,10 @@ impl<T: PyClass> PyCell<T> {
///
/// In cases where the value in the cell does not need to be accessed immediately after
/// creation, consider [`Py::new`](crate::Py::new) as a more efficient alternative.
#[cfg_attr(
not(feature = "gil-refs"),
deprecated(
#[cfg(feature = "gil-refs")]
#[deprecated(
since = "0.21.0",
note = "use `Bound::new(py, value)` or `Py::new(py, value)` instead of `PyCell::new(py, value)`"
)
)]
pub fn new(py: Python<'_>, value: impl Into<PyClassInitializer<T>>) -> PyResult<&Self> {
Bound::new(py, value).map(Bound::into_gil_ref)
@ -317,7 +316,7 @@ impl<T: PyClass> PyCell<T> {
///
/// # Examples
///
/// ```
/// ```ignore
/// # use pyo3::prelude::*;
/// #[pyclass]
/// struct Class {}
@ -347,7 +346,7 @@ impl<T: PyClass> PyCell<T> {
///
/// # Examples
///
/// ```
/// ```ignore
/// # use pyo3::prelude::*;
/// #[pyclass]
/// struct Class {}
@ -380,7 +379,7 @@ impl<T: PyClass> PyCell<T> {
///
/// # Examples
///
/// ```
/// ```ignore
/// # use pyo3::prelude::*;
/// #[pyclass]
/// struct Class {}
@ -417,7 +416,7 @@ impl<T: PyClass> PyCell<T> {
///
/// # Examples
///
/// ```
/// ```ignore
/// use std::sync::atomic::{AtomicUsize, Ordering};
/// # use pyo3::prelude::*;
///
@ -561,14 +560,14 @@ impl<T: PyClass + fmt::Debug> fmt::Debug for PyCell<T> {
}
}
/// A wrapper type for an immutably borrowed value from a [`PyCell`]`<T>`.
/// A wrapper type for an immutably borrowed value from a [`Bound<'py, T>`].
///
/// See the [`PyCell`] documentation for more information.
/// See the [`Bound`] documentation for more information.
///
/// # Examples
///
/// You can use `PyRef` as an alternative to a `&self` receiver when
/// - you need to access the pointer of the `PyCell`, or
/// You can use [`PyRef`] as an alternative to a `&self` receiver when
/// - you need to access the pointer of the [`Bound`], or
/// - you want to get a super class.
/// ```
/// # use pyo3::prelude::*;
@ -599,7 +598,7 @@ impl<T: PyClass + fmt::Debug> fmt::Debug for PyCell<T> {
/// }
/// # Python::with_gil(|py| {
/// # let sub = Py::new(py, Child::new()).unwrap();
/// # pyo3::py_run!(py, sub, "assert sub.format() == 'Caterpillar(base: Butterfly, cnt: 5)', sub.format()");
/// # pyo3::py_run!(py, sub, "assert sub.format() == 'Caterpillar(base: Butterfly, cnt: 4)', sub.format()");
/// # });
/// ```
///
@ -1004,6 +1003,10 @@ mod tests {
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
struct SomeClass(i32);
#[cfg(feature = "gil-refs")]
mod deprecated {
use super::*;
#[test]
fn pycell_replace() {
Python::with_gil(|py| {
@ -1100,6 +1103,7 @@ mod tests {
cell.swap(cell2);
})
}
}
#[test]
fn test_as_ptr() {

View File

@ -41,7 +41,10 @@ fn append_to_inittab() {
#[crate::pymodule]
#[pyo3(crate = "crate")]
#[allow(clippy::unnecessary_wraps)]
fn module_for_inittab(_: crate::Python<'_>, _: &crate::types::PyModule) -> crate::PyResult<()> {
fn module_for_inittab(
_: crate::Python<'_>,
_: &crate::Bound<'_, crate::types::PyModule>,
) -> crate::PyResult<()> {
::std::result::Result::Ok(())
}
crate::append_to_inittab!(module_for_inittab);

View File

@ -7,6 +7,7 @@ fn do_something(x: i32) -> crate::PyResult<i32> {
::std::result::Result::Ok(x)
}
#[cfg(feature = "gil-refs")]
#[allow(deprecated)]
#[crate::pymodule]
#[pyo3(crate = "crate")]
@ -14,6 +15,15 @@ fn foo(_py: crate::Python<'_>, _m: &crate::types::PyModule) -> crate::PyResult<(
::std::result::Result::Ok(())
}
#[crate::pymodule]
#[pyo3(crate = "crate")]
fn foo_bound(
_py: crate::Python<'_>,
_m: &crate::Bound<'_, crate::types::PyModule>,
) -> crate::PyResult<()> {
::std::result::Result::Ok(())
}
#[cfg(feature = "gil-refs")]
#[allow(deprecated)]
#[crate::pymodule]
@ -34,7 +44,7 @@ fn my_module_bound(m: &crate::Bound<'_, crate::types::PyModule>) -> crate::PyRes
)?;
<crate::Bound<'_, crate::types::PyModule> as crate::types::PyModuleMethods>::add_wrapped(
m,
crate::wrap_pymodule!(foo),
crate::wrap_pymodule!(foo_bound),
)?;
::std::result::Result::Ok(())

View File

@ -6,7 +6,9 @@ use crate::py_result_ext::PyResultExt;
use crate::types::any::PyAnyMethods;
use crate::types::bytes::PyBytesMethods;
use crate::types::PyBytes;
use crate::{ffi, Bound, IntoPy, Py, PyAny, PyNativeType, PyResult, Python};
#[cfg(feature = "gil-refs")]
use crate::PyNativeType;
use crate::{ffi, Bound, IntoPy, Py, PyAny, PyResult, Python};
use std::borrow::Cow;
use std::os::raw::c_char;
use std::str;
@ -135,16 +137,6 @@ pub struct PyString(PyAny);
pyobject_native_type_core!(PyString, pyobject_native_static_type_object!(ffi::PyUnicode_Type), #checkfunction=ffi::PyUnicode_Check);
impl PyString {
/// Deprecated form of [`PyString::new_bound`].
#[cfg(feature = "gil-refs")]
#[deprecated(
since = "0.21.0",
note = "`PyString::new` will be replaced by `PyString::new_bound` in a future PyO3 version"
)]
pub fn new<'py>(py: Python<'py>, s: &str) -> &'py Self {
Self::new_bound(py, s).into_gil_ref()
}
/// Creates a new Python string object.
///
/// Panics if out of memory.
@ -158,16 +150,6 @@ impl PyString {
}
}
/// Deprecated form of [`PyString::intern_bound`].
#[cfg(feature = "gil-refs")]
#[deprecated(
since = "0.21.0",
note = "`PyString::intern` will be replaced by `PyString::intern_bound` in a future PyO3 version"
)]
pub fn intern<'py>(py: Python<'py>, s: &str) -> &'py Self {
Self::intern_bound(py, s).into_gil_ref()
}
/// Intern the given string
///
/// This will return a reference to the same Python string object if called repeatedly with the same string.
@ -188,16 +170,6 @@ impl PyString {
}
}
/// Deprecated form of [`PyString::from_object_bound`].
#[cfg(feature = "gil-refs")]
#[deprecated(
since = "0.21.0",
note = "`PyString::from_object` will be replaced by `PyString::from_object_bound` in a future PyO3 version"
)]
pub fn from_object<'py>(src: &'py PyAny, encoding: &str, errors: &str) -> PyResult<&'py Self> {
Self::from_object_bound(&src.as_borrowed(), encoding, errors).map(Bound::into_gil_ref)
}
/// Attempts to create a Python string from a Python [bytes-like object].
///
/// [bytes-like object]: (https://docs.python.org/3/glossary.html#term-bytes-like-object).
@ -216,6 +188,36 @@ impl PyString {
.downcast_into_unchecked()
}
}
}
#[cfg(feature = "gil-refs")]
impl PyString {
/// Deprecated form of [`PyString::new_bound`].
#[deprecated(
since = "0.21.0",
note = "`PyString::new` will be replaced by `PyString::new_bound` in a future PyO3 version"
)]
pub fn new<'py>(py: Python<'py>, s: &str) -> &'py Self {
Self::new_bound(py, s).into_gil_ref()
}
/// Deprecated form of [`PyString::intern_bound`].
#[deprecated(
since = "0.21.0",
note = "`PyString::intern` will be replaced by `PyString::intern_bound` in a future PyO3 version"
)]
pub fn intern<'py>(py: Python<'py>, s: &str) -> &'py Self {
Self::intern_bound(py, s).into_gil_ref()
}
/// Deprecated form of [`PyString::from_object_bound`].
#[deprecated(
since = "0.21.0",
note = "`PyString::from_object` will be replaced by `PyString::from_object_bound` in a future PyO3 version"
)]
pub fn from_object<'py>(src: &'py PyAny, encoding: &str, errors: &str) -> PyResult<&'py Self> {
Self::from_object_bound(&src.as_borrowed(), encoding, errors).map(Bound::into_gil_ref)
}
/// Gets the Python string as a Rust UTF-8 string slice.
///

View File

@ -5,6 +5,7 @@ use pyo3::{prelude::*, types::PyCFunction};
#[pyfunction]
fn f() {}
#[cfg(feature = "gil-refs")]
pub fn add_wrapped(wrapper: &impl Fn(Python<'_>) -> PyResult<&PyCFunction>) {
let _ = wrapper;
}
@ -12,7 +13,10 @@ pub fn add_wrapped(wrapper: &impl Fn(Python<'_>) -> PyResult<&PyCFunction>) {
#[test]
fn wrap_pyfunction_deduction() {
#[allow(deprecated)]
#[cfg(feature = "gil-refs")]
add_wrapped(wrap_pyfunction!(f));
#[cfg(not(feature = "gil-refs"))]
add_wrapped_bound(wrap_pyfunction!(f));
}
pub fn add_wrapped_bound(wrapper: &impl Fn(Python<'_>) -> PyResult<Bound<'_, PyCFunction>>) {