Skip to content

Commit

Permalink
feature gate as/into_gil_ref APIs (Part 3) (#4172)
Browse files Browse the repository at this point in the history
  • Loading branch information
Icxolu committed May 10, 2024
1 parent aef0a05 commit 1e8e09d
Show file tree
Hide file tree
Showing 14 changed files with 196 additions and 152 deletions.
2 changes: 1 addition & 1 deletion guide/src/migration.md
Expand Up @@ -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`.

Expand Down
2 changes: 2 additions & 0 deletions guide/src/types.md
Expand Up @@ -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 {})?;
Expand Down
8 changes: 3 additions & 5 deletions src/conversion.rs
Expand Up @@ -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.
///
Expand Down Expand Up @@ -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)
}
}

Expand Down
4 changes: 2 additions & 2 deletions src/conversions/std/slice.rs
Expand Up @@ -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")]
Expand Down
4 changes: 2 additions & 2 deletions src/conversions/std/string.rs
Expand Up @@ -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")]
Expand Down
3 changes: 3 additions & 0 deletions src/impl_/frompyobject.rs
Expand Up @@ -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>),
}

Expand All @@ -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)
Expand All @@ -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()),
}
}
Expand Down
13 changes: 12 additions & 1 deletion src/impl_/pyfunction.rs
@@ -1,6 +1,6 @@
use crate::{
types::{PyCFunction, PyModule},
Borrowed, Bound, PyNativeType, PyResult, Python,
Borrowed, Bound, PyResult, Python,
};

pub use crate::impl_::pymethods::PyMethodDef;
Expand Down Expand Up @@ -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)
}
Expand All @@ -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)
Expand Down
11 changes: 8 additions & 3 deletions src/impl_/pymethods.rs
Expand Up @@ -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,
Expand Down Expand Up @@ -492,13 +494,15 @@ 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 {
bound.0.as_gil_ref()
}
}

#[cfg(feature = "gil-refs")]
impl<'a> From<BoundRef<'a, 'a, PyModule>> for &'a PyModule {
#[inline]
fn from(bound: BoundRef<'a, 'a, PyModule>) -> Self {
Expand All @@ -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 {
Expand All @@ -518,15 +523,15 @@ 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()
}
}

impl<'a, 'py, T: PyClass<Frozen = False>> TryFrom<BoundRef<'a, 'py, T>> for PyRefMut<'py, T> {
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()
}
}

Expand Down
2 changes: 2 additions & 0 deletions src/instance.rs
Expand Up @@ -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,
Expand All @@ -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,
Expand Down

0 comments on commit 1e8e09d

Please sign in to comment.