diff --git a/guide/src/class.md b/guide/src/class.md index d0dcf262259..0e70a741a76 100644 --- a/guide/src/class.md +++ b/guide/src/class.md @@ -415,9 +415,8 @@ Currently, only classes defined in Rust and builtins provided by PyO3 can be inh To initialize a class, which inherits from another class, use the `PyClassInitializer` API. -To get a parent class from a child, use [`PyRef`] instead of `&self` for methods, or [`PyRefMut`] instead of `&mut self`. -Then you can access a parent class by `self_.as_super()` as `&PyRef`, or by `self_.into_super()` as `PyRef` (and similar for the `PyRefMut` case). -For convenience, `self_.as_ref()` can also be used to get `&Self::BaseClass` directly; however, this approach does not let you access base classes higher in the inheritance hierarchy, for which you would need to chain multiple `as_super` or `into_super` calls. +To get a parent class from a child, use [`PyClassGuard`] instead of `&self` for methods, or [`PyClassGuardMut`] instead of `&mut self`. +Then you can access a parent class by `self_.as_super()` as `&PyClassGuard`, or by `self_.into_super()` as `PyClassGuard` (and similar for the `PyRefMut` case). ```rust # use pyo3::prelude::*; @@ -452,8 +451,8 @@ impl SubClass { .add_subclass(SubClass { val2: 15 }) } - fn method2(self_: PyRef<'_, Self>) -> PyResult { - let super_ = self_.as_super(); // Get &PyRef + fn method2(self_: PyClassGuard<'_, Self>) -> PyResult { + let super_ = self_.as_super(); // Get &PyClassGuard super_.method1().map(|x| x * self_.val2) } } @@ -470,24 +469,24 @@ impl SubSubClass { PyClassInitializer::from(SubClass::new()).add_subclass(SubSubClass { val3: 20 }) } - fn method3(self_: PyRef<'_, Self>) -> PyResult { - let base = self_.as_super().as_super(); // Get &PyRef<'_, BaseClass> + fn method3(self_: PyClassGuard<'_, Self>) -> PyResult { + let base = self_.as_super().as_super(); // Get &PyClassGuard<'_, BaseClass> base.method1().map(|x| x * self_.val3) } - fn method4(self_: PyRef<'_, Self>) -> PyResult { + fn method4(self_: PyClassGuard<'_, Self>) -> PyResult { let v = self_.val3; - let super_ = self_.into_super(); // Get PyRef<'_, SubClass> + let super_ = self_.into_super(); // Get PyClassGuard<'_, SubClass> SubClass::method2(super_).map(|x| x * v) } - fn get_values(self_: PyRef<'_, Self>) -> (usize, usize, usize) { + fn get_values(self_: PyClassGuard<'_, Self>) -> (usize, usize, usize) { let val1 = self_.as_super().as_super().val1; let val2 = self_.as_super().val2; (val1, val2, self_.val3) } - fn double_values(mut self_: PyRefMut<'_, Self>) { + fn double_values(mut self_: PyClassGuardMut<'_, Self>) { self_.as_super().as_super().val1 *= 2; self_.as_super().val2 *= 2; self_.val3 *= 2; @@ -940,7 +939,7 @@ Class objects can be used as arguments to `#[pyfunction]`s and `#[pymethods]` in - `Py` or `Bound<'py, T>` smart pointers to the class Python object, - `&T` or `&mut T` references to the Rust data contained in the Python object, or -- `PyRef` and `PyRefMut` reference wrappers. +- `PyClassGuard` and `PyClassGuardMut` reference wrappers. Examples of each of these below: @@ -961,7 +960,7 @@ fn increment_field(my_class: &mut MyClass) { // Take a reference wrapper when borrowing should be automatic, // but access to the Python object is still needed #[pyfunction] -fn print_field_and_return_me(my_class: PyRef<'_, MyClass>) -> PyRef<'_, MyClass> { +fn print_field_and_return_me(my_class: PyClassGuard<'_, MyClass>) -> PyClassGuard<'_, MyClass> { println!("{}", my_class.my_field); my_class } @@ -1575,8 +1574,8 @@ impl pyo3::impl_::pyclass::PyClassImpl for MyClass { [`Py`]: {{#PYO3_DOCS_URL}}/pyo3/struct.Py.html [`Bound<'py, T>`]: {{#PYO3_DOCS_URL}}/pyo3/struct.Bound.html [`PyClass`]: {{#PYO3_DOCS_URL}}/pyo3/pyclass/trait.PyClass.html -[`PyRef`]: {{#PYO3_DOCS_URL}}/pyo3/pycell/struct.PyRef.html -[`PyRefMut`]: {{#PYO3_DOCS_URL}}/pyo3/pycell/struct.PyRefMut.html +[`PyClassGuard`]: {{#PYO3_DOCS_URL}}/pyo3/pyclass/struct.PyClassGuard.html +[`PyClassGuardMut`]: {{#PYO3_DOCS_URL}}/pyo3/pyclass/struct.PyClassGuardMut.html [`PyClassInitializer`]: {{#PYO3_DOCS_URL}}/pyo3/pyclass_init/struct.PyClassInitializer.html [`Arc`]: https://doc.rust-lang.org/std/sync/struct.Arc.html diff --git a/guide/src/class/numeric.md b/guide/src/class/numeric.md index 8957838dcb9..13adebb72b2 100644 --- a/guide/src/class/numeric.md +++ b/guide/src/class/numeric.md @@ -135,7 +135,7 @@ impl Number { # #[pymethods] impl Number { - fn __pos__(slf: PyRef<'_, Self>) -> PyRef<'_, Self> { + fn __pos__(slf: PyClassGuard<'_, Self>) -> PyClassGuard<'_, Self> { slf } diff --git a/guide/src/class/protocols.md b/guide/src/class/protocols.md index a0d73fb37c0..8db611f1017 100644 --- a/guide/src/class/protocols.md +++ b/guide/src/class/protocols.md @@ -33,7 +33,7 @@ The following sections list all magic methods for which PyO3 implements the nece The given signatures should be interpreted as follows: - All methods take a receiver as first argument, shown as ``. - It can be `&self`, `&mut self` or a `Bound` reference like `self_: PyRef<'_, Self>` and `self_: PyRefMut<'_, Self>`, as described [in the parent section](../class.md#inheritance). + It can be `&self`, `&mut self` or a `Bound` reference like `self_: PyClassGuard<'_, Self>` and `self_: PyClassGuardMut<'_, Self>`, as described [in the parent section](../class.md#inheritance). - An optional `Python<'py>` argument is always allowed as the first argument. - Return values can be optionally wrapped in `PyResult`. - `object` means that any type is allowed that can be extracted from a Python @@ -196,10 +196,10 @@ struct MyIterator { #[pymethods] impl MyIterator { - fn __iter__(slf: PyRef<'_, Self>) -> PyRef<'_, Self> { + fn __iter__(slf: PyClassGuard<'_, Self>) -> PyClassGuard<'_, Self> { slf } - fn __next__(slf: PyRefMut<'_, Self>) -> Option> { + fn __next__(slf: PyClassGuardMut<'_, Self>) -> Option> { slf.iter.lock().unwrap().next() } } @@ -219,11 +219,11 @@ struct Iter { #[pymethods] impl Iter { - fn __iter__(slf: PyRef<'_, Self>) -> PyRef<'_, Self> { + fn __iter__(slf: PyClassGuard<'_, Self>) -> PyClassGuard<'_, Self> { slf } - fn __next__(mut slf: PyRefMut<'_, Self>) -> Option { + fn __next__(mut slf: PyClassGuardMut<'_, Self>) -> Option { slf.inner.next() } } @@ -235,11 +235,11 @@ struct Container { #[pymethods] impl Container { - fn __iter__(slf: PyRef<'_, Self>) -> PyResult> { + fn __iter__(slf: PyClassGuard<'_, Self>, py: Python<'_>) -> PyResult> { let iter = Iter { inner: slf.iter.clone().into_iter(), }; - Py::new(slf.py(), iter) + Py::new(py, iter) } } diff --git a/guide/src/conversions/tables.md b/guide/src/conversions/tables.md index d62ae5ad00f..0382ec257ab 100644 --- a/guide/src/conversions/tables.md +++ b/guide/src/conversions/tables.md @@ -54,8 +54,8 @@ It is also worth remembering the following special types: | `Python<'py>` | A token used to prove attachment to the Python interpreter. | | `Bound<'py, T>` | A Python object with a lifetime which binds it to the attachment to the Python interpreter. This provides access to most of PyO3's APIs. | | `Py` | A Python object not connected to any lifetime of attachment to the Python interpreter. This can be sent to other threads. | -| `PyRef` | A `#[pyclass]` borrowed immutably. | -| `PyRefMut` | A `#[pyclass]` borrowed mutably. | +| `PyClassGuard` | A `#[pyclass]` borrowed immutably. | +| `PyClassGuardMut` | A `#[pyclass]` borrowed mutably. | For more detail on accepting `#[pyclass]` values as function arguments, see [the section of this guide on Python Classes](../class.md). @@ -105,8 +105,8 @@ Finally, the following Rust types are also able to convert to Python as return v | `BTreeSet` | `Set[T]` | | `Py` | `T` | | `Bound` | `T` | -| `PyRef` | `T` | -| `PyRefMut` | `T` | +| `PyClassGuard` | `T` | +| `PyClassGuardMut` | `T` | [^1]: Requires the `num-bigint` optional feature. diff --git a/guide/src/conversions/traits.md b/guide/src/conversions/traits.md index 83e958a7c9a..e0bee7720bf 100644 --- a/guide/src/conversions/traits.md +++ b/guide/src/conversions/traits.md @@ -23,7 +23,7 @@ let v: Vec = list.extract()?; This method is available for many Python object types, and can produce a wide variety of Rust types, which you can check out in the implementor list of [`FromPyObject`]. [`FromPyObject`] is also implemented for your own Rust types wrapped as Python objects (see [the chapter about classes](../class.md)). -There, in order to both be able to operate on mutable references *and* satisfy Rust's rules of non-aliasing mutable references, you have to extract the PyO3 reference wrappers [`PyRef`] and [`PyRefMut`]. +There, in order to both be able to operate on mutable references *and* satisfy Rust's rules of non-aliasing mutable references, you have to extract the PyO3 reference wrappers [`PyClassGuard`] and [`PyClassGuardMut`]. They work like the reference wrappers of `std::cell::RefCell` and ensure (at runtime) that Rust borrows are allowed. ### Deriving [`FromPyObject`] @@ -756,8 +756,8 @@ In the example above we used `BoundObject::into_any` and `BoundObject::unbind` t [`IntoPyObject`]: {{#PYO3_DOCS_URL}}/pyo3/conversion/trait.IntoPyObject.html [`IntoPyObjectExt`]: {{#PYO3_DOCS_URL}}/pyo3/conversion/trait.IntoPyObjectExt.html -[`PyRef`]: {{#PYO3_DOCS_URL}}/pyo3/pycell/struct.PyRef.html -[`PyRefMut`]: {{#PYO3_DOCS_URL}}/pyo3/pycell/struct.PyRefMut.html +[`PyClassGuard`]: {{#PYO3_DOCS_URL}}/pyo3/pyclass/struct.PyClassGuard.html +[`PyClassGuardMut`]: {{#PYO3_DOCS_URL}}/pyo3/pyclass/struct.PyClassGuardMut.html [`BoundObject`]: {{#PYO3_DOCS_URL}}/pyo3/instance/trait.BoundObject.html [`Result`]: https://doc.rust-lang.org/stable/std/result/enum.Result.html diff --git a/newsfragments/6120.changed.md b/newsfragments/6120.changed.md new file mode 100644 index 00000000000..589581c8112 --- /dev/null +++ b/newsfragments/6120.changed.md @@ -0,0 +1 @@ +deprecate `PyRef` and `PyRefMut` in favor of `PyClassGuard` and `PyClassGuardMut` respectively diff --git a/pytests/src/awaitable.rs b/pytests/src/awaitable.rs index e13a569c3c6..e64e76ce79d 100644 --- a/pytests/src/awaitable.rs +++ b/pytests/src/awaitable.rs @@ -27,11 +27,11 @@ pub mod awaitable { } } - fn __await__(pyself: PyRef<'_, Self>) -> PyRef<'_, Self> { + fn __await__(pyself: PyClassGuard<'_, Self>) -> PyClassGuard<'_, Self> { pyself } - fn __iter__(pyself: PyRef<'_, Self>) -> PyRef<'_, Self> { + fn __iter__(pyself: PyClassGuard<'_, Self>) -> PyClassGuard<'_, Self> { pyself } @@ -79,15 +79,15 @@ pub mod awaitable { } } - fn __await__(pyself: PyRef<'_, Self>) -> PyRef<'_, Self> { + fn __await__(pyself: PyClassGuard<'_, Self>) -> PyClassGuard<'_, Self> { pyself } - fn __iter__(pyself: PyRef<'_, Self>) -> PyRef<'_, Self> { + fn __iter__(pyself: PyClassGuard<'_, Self>) -> PyClassGuard<'_, Self> { pyself } - fn __next__(mut pyself: PyRefMut<'_, Self>) -> PyResult> { + fn __next__(mut pyself: PyClassGuardMut<'_, Self>) -> PyResult> { match pyself.result { Some(_) => match pyself.result.take().unwrap() { Ok(v) => Err(PyStopIteration::new_err(v)), @@ -97,20 +97,20 @@ pub mod awaitable { } } - fn send<'py>( - pyself: PyRefMut<'py, Self>, - _value: Bound<'py, PyAny>, - ) -> PyResult> { + fn send<'a>( + pyself: PyClassGuardMut<'a, Self>, + _value: Bound<'_, PyAny>, + ) -> PyResult> { Self::__next__(pyself) } #[pyo3(signature = (_value, _a = None, _b = None))] - fn throw<'py>( - pyself: PyRefMut<'py, Self>, - _value: Bound<'py, PyAny>, - _a: Option>, - _b: Option>, - ) -> PyResult> { + fn throw<'a>( + pyself: PyClassGuardMut<'a, Self>, + _value: Bound<'_, PyAny>, + _a: Option>, + _b: Option>, + ) -> PyResult> { Self::__next__(pyself) } diff --git a/pytests/src/pyclasses.rs b/pytests/src/pyclasses.rs index a1caa584d46..989baac1f8f 100644 --- a/pytests/src/pyclasses.rs +++ b/pytests/src/pyclasses.rs @@ -297,7 +297,7 @@ impl Number { Self(self.0 ^ other.0) } - fn __pos__(slf: PyRef<'_, Self>) -> PyRef<'_, Self> { + fn __pos__(slf: PyClassGuard<'_, Self>) -> PyClassGuard<'_, Self> { slf } @@ -309,7 +309,7 @@ impl Number { } } - fn __abs__(slf: PyRef<'_, Self>) -> PyRef<'_, Self> { + fn __abs__(slf: PyClassGuard<'_, Self>) -> PyClassGuard<'_, Self> { slf } diff --git a/src/conversion.rs b/src/conversion.rs index 200793ab81f..463975df40e 100644 --- a/src/conversion.rs +++ b/src/conversion.rs @@ -8,9 +8,10 @@ use crate::pyclass::{PyClassGuardError, PyClassGuardMutError}; use crate::types::PyList; use crate::types::PyTuple; use crate::{ - Borrowed, Bound, BoundObject, Py, PyAny, PyClass, PyClassGuard, PyErr, PyRef, PyRefMut, - PyTypeCheck, Python, + Borrowed, Bound, BoundObject, Py, PyAny, PyClass, PyClassGuard, PyErr, PyTypeCheck, Python, }; +#[expect(deprecated)] +use crate::{PyRef, PyRefMut}; use core::convert::Infallible; use core::marker::PhantomData; @@ -524,6 +525,7 @@ where } } +#[expect(deprecated)] impl<'a, 'py, T> FromPyObject<'a, 'py> for PyRef<'py, T> where T: PyClass, @@ -541,6 +543,7 @@ where } } +#[expect(deprecated)] impl<'a, 'py, T> FromPyObject<'a, 'py> for PyRefMut<'py, T> where T: PyClass, diff --git a/src/instance.rs b/src/instance.rs index 8aa8371d04f..beaa22f675b 100644 --- a/src/instance.rs +++ b/src/instance.rs @@ -12,10 +12,12 @@ use crate::pyclass::boolean_struct::{False, True}; use crate::types::{any::PyAnyMethods, string::PyStringMethods, typeobject::PyTypeMethods}; use crate::types::{DerefToPyAny, PyDict, PyString}; use crate::{ - ffi, CastError, CastIntoError, FromPyObject, PyAny, PyClass, PyClassInitializer, PyRef, - PyRefMut, PyTypeInfo, Python, + ffi, CastError, CastIntoError, FromPyObject, PyAny, PyClass, PyClassInitializer, PyTypeInfo, + Python, }; use crate::{internal::state, PyTypeCheck}; +#[expect(deprecated)] +use crate::{PyRef, PyRefMut}; use core::marker::PhantomData; use core::mem::ManuallyDrop; use core::ops::Deref; @@ -150,8 +152,8 @@ impl<'py, T> Bound<'py, T> { /// /// class_bound.borrow_mut().i += 1; /// - /// // Alternatively you can get a `PyRefMut` directly - /// let class_ref: PyRefMut<'_, Class> = class.extract()?; + /// // Alternatively you can get a `PyClassGuardMut` directly + /// let class_ref: PyClassGuardMut<'_, Class> = class.extract()?; /// assert_eq!(class_ref.i, 1); /// Ok(()) /// }) @@ -546,6 +548,7 @@ where /// /// Panics if the value is currently mutably borrowed. For a non-panicking variant, use /// [`try_borrow`](#method.try_borrow). + #[expect(deprecated)] #[inline] #[track_caller] pub fn borrow(&self) -> PyRef<'py, T> { @@ -581,6 +584,7 @@ where /// # Panics /// Panics if the value is currently borrowed. For a non-panicking variant, use /// [`try_borrow_mut`](#method.try_borrow_mut). + #[expect(deprecated)] #[inline] #[track_caller] pub fn borrow_mut(&self) -> PyRefMut<'py, T> @@ -597,6 +601,7 @@ where /// This is the non-panicking variant of [`borrow`](#method.borrow). /// /// For frozen classes, the simpler [`get`][Self::get] is available. + #[expect(deprecated)] #[inline] pub fn try_borrow(&self) -> Result, PyBorrowError> { PyRef::try_borrow(self) @@ -607,6 +612,7 @@ where /// The borrow lasts while the returned [`PyRefMut`] exists. /// /// This is the non-panicking variant of [`borrow_mut`](#method.borrow_mut). + #[expect(deprecated)] #[inline] pub fn try_borrow_mut(&self) -> Result, PyBorrowMutError> where @@ -1613,6 +1619,7 @@ where /// /// Panics if the value is currently mutably borrowed. For a non-panicking variant, use /// [`try_borrow`](#method.try_borrow). + #[expect(deprecated)] #[inline] #[track_caller] pub fn borrow<'py>(&'py self, py: Python<'py>) -> PyRef<'py, T> { @@ -1650,6 +1657,7 @@ where /// # Panics /// Panics if the value is currently borrowed. For a non-panicking variant, use /// [`try_borrow_mut`](#method.try_borrow_mut). + #[expect(deprecated)] #[inline] #[track_caller] pub fn borrow_mut<'py>(&'py self, py: Python<'py>) -> PyRefMut<'py, T> @@ -1668,6 +1676,7 @@ where /// For frozen classes, the simpler [`get`][Self::get] is available. /// /// Equivalent to `self.bind(py).try_borrow()` - see [`Bound::try_borrow`]. + #[expect(deprecated)] #[inline] pub fn try_borrow<'py>(&'py self, py: Python<'py>) -> Result, PyBorrowError> { self.bind(py).try_borrow() @@ -1680,6 +1689,7 @@ where /// This is the non-panicking variant of [`borrow_mut`](#method.borrow_mut). /// /// Equivalent to `self.bind(py).try_borrow_mut()` - see [`Bound::try_borrow_mut`]. + #[expect(deprecated)] #[inline] pub fn try_borrow_mut<'py>( &'py self, @@ -2215,6 +2225,7 @@ impl core::convert::From> for Py { } } +#[expect(deprecated)] impl<'py, T> core::convert::From> for Py where T: PyClass, @@ -2226,6 +2237,7 @@ where } } +#[expect(deprecated)] impl<'py, T> core::convert::From> for Py where T: PyClass, @@ -2394,8 +2406,8 @@ impl Py { /// /// class_bound.borrow_mut().i += 1; /// - /// // Alternatively you can get a `PyRefMut` directly - /// let class_ref: PyRefMut<'_, Class> = class.extract(py)?; + /// // Alternatively you can get a `PyClassGuardMut` directly + /// let class_ref: PyClassGuardMut<'_, Class> = class.extract(py)?; /// assert_eq!(class_ref.i, 1); /// Ok(()) /// }) diff --git a/src/lib.rs b/src/lib.rs index 8dd6148b675..23f37782c38 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -350,6 +350,7 @@ pub use crate::instance::{Borrowed, Bound, BoundObject, Py}; #[cfg(not(any(PyPy, GraalPy)))] pub use crate::interpreter_lifecycle::with_embedded_python_interpreter; pub use crate::marker::Python; +#[expect(deprecated)] pub use crate::pycell::{PyRef, PyRefMut}; pub use crate::pyclass::{PyClass, PyClassGuard, PyClassGuardMut}; pub use crate::pyclass_init::PyClassInitializer; diff --git a/src/marker.rs b/src/marker.rs index 99d21bd1593..81788aacfb0 100644 --- a/src/marker.rs +++ b/src/marker.rs @@ -277,7 +277,9 @@ mod nightly { // This means that PyString, PyList, etc all inherit !Ungil from this. impl !Ungil for crate::PyAny {} + #[expect(deprecated)] impl !Ungil for crate::PyRef<'_, T> {} + #[expect(deprecated)] impl !Ungil for crate::PyRefMut<'_, T> {} // FFI pointees diff --git a/src/prelude.rs b/src/prelude.rs index 33a6f23534e..92e79150a22 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -12,6 +12,7 @@ pub use crate::conversion::{FromPyObject, FromPyObjectOwned, IntoPyObject}; pub use crate::err::{PyErr, PyResult}; pub use crate::instance::{Borrowed, Bound, Py}; pub use crate::marker::Python; +#[expect(deprecated)] pub use crate::pycell::{PyRef, PyRefMut}; pub use crate::pyclass_init::PyClassInitializer; pub use crate::types::{PyAny, PyModule}; diff --git a/src/pycell.rs b/src/pycell.rs index 5b3edbc9b37..a2370bfd50d 100644 --- a/src/pycell.rs +++ b/src/pycell.rs @@ -100,6 +100,7 @@ //! //! // We borrow the guard and then dereference //! // it to get a mutable reference to Number +//! # #[expect(deprecated)] //! let mut guard: PyRefMut<'_, Number> = n.bind(py).borrow_mut(); //! let n_mutable: &mut Number = &mut *guard; //! @@ -241,6 +242,7 @@ use impl_::{PyClassBorrowChecker, PyClassObjectBaseLayout, PyClassObjectLayout}; /// .add_subclass(Child { name: "Caterpillar" }) /// } /// +/// # #[expect(deprecated)] /// fn format(slf: PyRef<'_, Self>) -> String { /// // We can get *mut ffi::PyObject from PyRef /// let refcnt = unsafe { pyo3::ffi::Py_REFCNT(slf.as_ptr()) }; @@ -257,12 +259,14 @@ use impl_::{PyClassBorrowChecker, PyClassObjectBaseLayout, PyClassObjectLayout}; /// /// See the [module-level documentation](self) for more information. #[repr(transparent)] +#[deprecated(since = "0.30.0", note = "use `PyClassGuard` instead")] pub struct PyRef<'p, T: PyClass> { // TODO: once the GIL Ref API is removed, consider adding a lifetime parameter to `PyRef` to // store `Borrowed` here instead, avoiding reference counting overhead. inner: Bound<'p, T>, } +#[expect(deprecated)] impl<'p, T: PyClass> PyRef<'p, T> { /// Returns a `Python` token that is bound to the lifetime of the `PyRef`. pub fn py(&self) -> Python<'p> { @@ -270,6 +274,7 @@ impl<'p, T: PyClass> PyRef<'p, T> { } } +#[expect(deprecated)] impl AsRef for PyRef<'_, T> where T: PyClass, @@ -280,6 +285,7 @@ where } } +#[expect(deprecated)] impl<'py, T: PyClass> PyRef<'py, T> { /// Returns the raw FFI pointer represented by self. /// @@ -319,6 +325,7 @@ impl<'py, T: PyClass> PyRef<'py, T> { } } +#[expect(deprecated)] impl<'p, T> PyRef<'p, T> where T: PyClass, @@ -358,6 +365,7 @@ where /// .add_subclass(Base2 { name2: "base2" }) /// .add_subclass(Self { name3: "sub" }) /// } + /// # #[expect(deprecated)] /// fn name(slf: PyRef<'_, Self>) -> String { /// let subname = slf.name3; /// let super_ = slf.into_super(); @@ -441,6 +449,7 @@ where /// fn sub_name_len(&self) -> usize { /// self.sub_name.len() /// } + /// # #[expect(deprecated)] /// fn format_name_lengths(slf: PyRef<'_, Self>) -> String { /// format!("{} {}", slf.as_super().base_name_len(), slf.sub_name_len()) /// } @@ -461,6 +470,7 @@ where } } +#[expect(deprecated)] impl Deref for PyRef<'_, T> { type Target = T; @@ -470,6 +480,7 @@ impl Deref for PyRef<'_, T> { } } +#[expect(deprecated)] impl Drop for PyRef<'_, T> { fn drop(&mut self) { self.inner @@ -479,6 +490,7 @@ impl Drop for PyRef<'_, T> { } } +#[expect(deprecated)] impl<'py, T: PyClass> IntoPyObject<'py> for PyRef<'py, T> { type Target = T; type Output = Bound<'py, T>; @@ -492,6 +504,7 @@ impl<'py, T: PyClass> IntoPyObject<'py> for PyRef<'py, T> { } } +#[expect(deprecated)] impl<'a, 'py, T: PyClass> IntoPyObject<'py> for &'a PyRef<'py, T> { type Target = T; type Output = Borrowed<'a, 'py, T>; @@ -505,12 +518,14 @@ impl<'a, 'py, T: PyClass> IntoPyObject<'py> for &'a PyRef<'py, T> { } } +#[expect(deprecated)] impl fmt::Debug for PyRef<'_, T> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Debug::fmt(&**self, f) } } +#[expect(deprecated)] impl<'py, T: PyClass> TryFrom<&Bound<'py, T>> for PyRef<'py, T> { type Error = PyBorrowError; #[inline] @@ -522,6 +537,7 @@ impl<'py, T: PyClass> TryFrom<&Bound<'py, T>> for PyRef<'py, T> { /// A wrapper type for a mutably borrowed value from a [`Bound<'py, T>`]. /// /// See the [module-level documentation](self) for more information. +#[deprecated(since = "0.30.0", note = "use `PyClassGuardMut` instead")] #[repr(transparent)] pub struct PyRefMut<'p, T: PyClass> { // TODO: once the GIL Ref API is removed, consider adding a lifetime parameter to `PyRef` to @@ -529,6 +545,7 @@ pub struct PyRefMut<'p, T: PyClass> { inner: Bound<'p, T>, } +#[expect(deprecated)] impl<'p, T: PyClass> PyRefMut<'p, T> { /// Returns a `Python` token that is bound to the lifetime of the `PyRefMut`. pub fn py(&self) -> Python<'p> { @@ -536,6 +553,7 @@ impl<'p, T: PyClass> PyRefMut<'p, T> { } } +#[expect(deprecated)] impl AsRef for PyRefMut<'_, T> where T: PyClass, @@ -546,6 +564,7 @@ where } } +#[expect(deprecated)] impl AsMut for PyRefMut<'_, T> where T: PyClass, @@ -556,6 +575,7 @@ where } } +#[expect(deprecated)] impl<'py, T: PyClass> PyRefMut<'py, T> { /// Returns the raw FFI pointer represented by self. /// @@ -602,6 +622,7 @@ impl<'py, T: PyClass> PyRefMut<'py, T> { } } +#[expect(deprecated)] impl<'p, T> PyRefMut<'p, T> where T: PyClass, @@ -641,6 +662,7 @@ where } } +#[expect(deprecated)] impl> Deref for PyRefMut<'_, T> { type Target = T; @@ -650,6 +672,7 @@ impl> Deref for PyRefMut<'_, T> { } } +#[expect(deprecated)] impl> DerefMut for PyRefMut<'_, T> { #[inline] fn deref_mut(&mut self) -> &mut T { @@ -657,6 +680,7 @@ impl> DerefMut for PyRefMut<'_, T> { } } +#[expect(deprecated)] impl> Drop for PyRefMut<'_, T> { fn drop(&mut self) { self.inner @@ -666,6 +690,7 @@ impl> Drop for PyRefMut<'_, T> { } } +#[expect(deprecated)] impl<'py, T: PyClass> IntoPyObject<'py> for PyRefMut<'py, T> { type Target = T; type Output = Bound<'py, T>; @@ -679,6 +704,7 @@ impl<'py, T: PyClass> IntoPyObject<'py> for PyRefMut<'py, T> { } } +#[expect(deprecated)] impl<'a, 'py, T: PyClass> IntoPyObject<'py> for &'a PyRefMut<'py, T> { type Target = T; type Output = Borrowed<'a, 'py, T>; @@ -692,12 +718,14 @@ impl<'a, 'py, T: PyClass> IntoPyObject<'py> for &'a PyRefMut<'py } } +#[expect(deprecated)] impl + fmt::Debug> fmt::Debug for PyRefMut<'_, T> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Debug::fmt(self.deref(), f) } } +#[expect(deprecated)] impl<'py, T: PyClass> TryFrom<&Bound<'py, T>> for PyRefMut<'py, T> { type Error = PyBorrowMutError; #[inline] @@ -833,12 +861,14 @@ mod tests { crate::Py::new(py, init).expect("allocation error") } + #[expect(deprecated)] fn get_values(self_: PyRef<'_, Self>) -> (usize, usize, usize) { let val1 = self_.as_super().as_super().val1; let val2 = self_.as_super().val2; (val1, val2, self_.val3) } + #[expect(deprecated)] fn double_values(mut self_: PyRefMut<'_, Self>) { self_.as_super().as_super().val1 *= 2; self_.as_super().val2 *= 2; diff --git a/src/pycell/impl_.rs b/src/pycell/impl_.rs index 2475acd937f..6bd405b0271 100644 --- a/src/pycell/impl_.rs +++ b/src/pycell/impl_.rs @@ -736,37 +736,43 @@ mod tests { // Cannot take any other mutable or immutable borrows whilst the object is borrowed mutably assert!(mmm_bound - .extract::>() + .extract::>() .is_err()); assert!(mmm_bound - .extract::>() + .extract::>() .is_err()); - assert!(mmm_bound.extract::>().is_err()); assert!(mmm_bound - .extract::>() + .extract::>() .is_err()); assert!(mmm_bound - .extract::>() + .extract::>() + .is_err()); + assert!(mmm_bound + .extract::>() + .is_err()); + assert!(mmm_bound + .extract::>() .is_err()); - assert!(mmm_bound.extract::>().is_err()); // With the borrow dropped, all other borrow attempts will succeed drop(mmm_refmut); assert!(mmm_bound - .extract::>() + .extract::>() + .is_ok()); + assert!(mmm_bound + .extract::>() .is_ok()); + assert!(mmm_bound.extract::>().is_ok()); assert!(mmm_bound - .extract::>() + .extract::>() .is_ok()); - assert!(mmm_bound.extract::>().is_ok()); assert!(mmm_bound - .extract::>() + .extract::>() .is_ok()); assert!(mmm_bound - .extract::>() + .extract::>() .is_ok()); - assert!(mmm_bound.extract::>().is_ok()); }) } @@ -787,32 +793,36 @@ mod tests { // Further immutable borrows are ok assert!(mmm_bound - .extract::>() + .extract::>() .is_ok()); assert!(mmm_bound - .extract::>() + .extract::>() .is_ok()); - assert!(mmm_bound.extract::>().is_ok()); + assert!(mmm_bound.extract::>().is_ok()); // Further mutable borrows are not ok assert!(mmm_bound - .extract::>() + .extract::>() + .is_err()); + assert!(mmm_bound + .extract::>() .is_err()); assert!(mmm_bound - .extract::>() + .extract::>() .is_err()); - assert!(mmm_bound.extract::>().is_err()); // With the borrow dropped, all mutable borrow attempts will succeed drop(mmm_refmut); assert!(mmm_bound - .extract::>() + .extract::>() + .is_ok()); + assert!(mmm_bound + .extract::>() .is_ok()); assert!(mmm_bound - .extract::>() + .extract::>() .is_ok()); - assert!(mmm_bound.extract::>().is_ok()); }) } diff --git a/src/tests/hygiene/pymethods.rs b/src/tests/hygiene/pymethods.rs index ded2123d939..ff87f18a524 100644 --- a/src/tests/hygiene/pymethods.rs +++ b/src/tests/hygiene/pymethods.rs @@ -123,7 +123,7 @@ impl Dummy { fn __delitem__(&self, key: u32) {} - fn __iter__(_: crate::pycell::PyRef<'_, Self>, py: crate::Python<'_>) -> crate::Py { + fn __iter__(_: crate::PyClassGuard<'_, Self>, py: crate::Python<'_>) -> crate::Py { crate::Py::new(py, DummyIter {}).unwrap() } @@ -132,7 +132,7 @@ impl Dummy { } fn __reversed__( - slf: crate::pycell::PyRef<'_, Self>, + slf: crate::PyClassGuard<'_, Self>, py: crate::Python<'_>, ) -> crate::Py { crate::Py::new(py, DummyIter {}).unwrap() @@ -274,19 +274,19 @@ impl Dummy { fn __ior__(&mut self, other: &Self) {} - fn __neg__(slf: crate::pycell::PyRef<'_, Self>) -> crate::pycell::PyRef<'_, Self> { + fn __neg__(slf: crate::PyClassGuard<'_, Self>) -> crate::PyClassGuard<'_, Self> { slf } - fn __pos__(slf: crate::pycell::PyRef<'_, Self>) -> crate::pycell::PyRef<'_, Self> { + fn __pos__(slf: crate::PyClassGuard<'_, Self>) -> crate::PyClassGuard<'_, Self> { slf } - fn __abs__(slf: crate::pycell::PyRef<'_, Self>) -> crate::pycell::PyRef<'_, Self> { + fn __abs__(slf: crate::PyClassGuard<'_, Self>) -> crate::PyClassGuard<'_, Self> { slf } - fn __invert__(slf: crate::pycell::PyRef<'_, Self>) -> crate::pycell::PyRef<'_, Self> { + fn __invert__(slf: crate::PyClassGuard<'_, Self>) -> crate::PyClassGuard<'_, Self> { slf } @@ -344,7 +344,7 @@ impl Dummy { // Awaitable Objects ////////////////////// - fn __await__(slf: crate::pycell::PyRef<'_, Self>) -> crate::pycell::PyRef<'_, Self> { + fn __await__(slf: crate::PyClassGuard<'_, Self>) -> crate::PyClassGuard<'_, Self> { slf } @@ -354,7 +354,7 @@ impl Dummy { ////////////////////// fn __aiter__( - slf: crate::pycell::PyRef<'_, Self>, + slf: crate::PyClassGuard<'_, Self>, py: crate::Python<'_>, ) -> crate::Py { crate::Py::new(py, DummyIter {}).unwrap() @@ -484,10 +484,10 @@ impl WarningDummy { } #[pyo3(warn(message = "this method raises warning"))] - fn method_with_warning(_slf: crate::PyRef<'_, Self>) {} + fn method_with_warning(_slf: crate::PyClassGuard<'_, Self>) {} #[pyo3(warn(message = "this method raises warning", category = crate::exceptions::PyFutureWarning))] - fn method_with_warning_and_custom_category(_slf: crate::PyRef<'_, Self>) {} + fn method_with_warning_and_custom_category(_slf: crate::PyClassGuard<'_, Self>) {} #[cfg(any(not(Py_LIMITED_API), Py_3_12))] #[pyo3(warn(message = "this method raises user-defined warning", category = UserDefinedWarning))] @@ -525,7 +525,7 @@ impl WarningDummy { } #[pyo3(warn(message = "the + op method raises warning"))] - fn __add__(&self, other: crate::PyRef<'_, Self>) -> Self { + fn __add__(&self, other: crate::PyClassGuard<'_, Self>) -> Self { Self { value: self.value + other.value, } diff --git a/tests/test_arithmetics.rs b/tests/test_arithmetics.rs index 2cf21e59601..ee867e47e89 100644 --- a/tests/test_arithmetics.rs +++ b/tests/test_arithmetics.rs @@ -403,43 +403,43 @@ impl LhsAndRhs { // "BA" // } - fn __add__(lhs: PyRef<'_, Self>, rhs: &Bound<'_, PyAny>) -> String { + fn __add__(lhs: PyClassGuard<'_, Self>, rhs: &Bound<'_, PyAny>) -> String { format!("{lhs:?} + {rhs:?}") } - fn __sub__(lhs: PyRef<'_, Self>, rhs: &Bound<'_, PyAny>) -> String { + fn __sub__(lhs: PyClassGuard<'_, Self>, rhs: &Bound<'_, PyAny>) -> String { format!("{lhs:?} - {rhs:?}") } - fn __mul__(lhs: PyRef<'_, Self>, rhs: &Bound<'_, PyAny>) -> String { + fn __mul__(lhs: PyClassGuard<'_, Self>, rhs: &Bound<'_, PyAny>) -> String { format!("{lhs:?} * {rhs:?}") } - fn __lshift__(lhs: PyRef<'_, Self>, rhs: &Bound<'_, PyAny>) -> String { + fn __lshift__(lhs: PyClassGuard<'_, Self>, rhs: &Bound<'_, PyAny>) -> String { format!("{lhs:?} << {rhs:?}") } - fn __rshift__(lhs: PyRef<'_, Self>, rhs: &Bound<'_, PyAny>) -> String { + fn __rshift__(lhs: PyClassGuard<'_, Self>, rhs: &Bound<'_, PyAny>) -> String { format!("{lhs:?} >> {rhs:?}") } - fn __and__(lhs: PyRef<'_, Self>, rhs: &Bound<'_, PyAny>) -> String { + fn __and__(lhs: PyClassGuard<'_, Self>, rhs: &Bound<'_, PyAny>) -> String { format!("{lhs:?} & {rhs:?}") } - fn __xor__(lhs: PyRef<'_, Self>, rhs: &Bound<'_, PyAny>) -> String { + fn __xor__(lhs: PyClassGuard<'_, Self>, rhs: &Bound<'_, PyAny>) -> String { format!("{lhs:?} ^ {rhs:?}") } - fn __or__(lhs: PyRef<'_, Self>, rhs: &Bound<'_, PyAny>) -> String { + fn __or__(lhs: PyClassGuard<'_, Self>, rhs: &Bound<'_, PyAny>) -> String { format!("{lhs:?} | {rhs:?}") } - fn __pow__(lhs: PyRef<'_, Self>, rhs: &Bound<'_, PyAny>, _mod: Option) -> String { + fn __pow__(lhs: PyClassGuard<'_, Self>, rhs: &Bound<'_, PyAny>, _mod: Option) -> String { format!("{lhs:?} ** {rhs:?}") } - fn __matmul__(lhs: PyRef<'_, Self>, rhs: &Bound<'_, PyAny>) -> String { + fn __matmul__(lhs: PyClassGuard<'_, Self>, rhs: &Bound<'_, PyAny>) -> String { format!("{lhs:?} @ {rhs:?}") } @@ -640,67 +640,115 @@ mod return_not_implemented { "RC_Self" } - fn __richcmp__(&self, other: PyRef<'_, Self>, _op: CompareOp) -> Py { - other.py().None() + fn __richcmp__( + &self, + py: Python<'_>, + _other: PyClassGuard<'_, Self>, + _op: CompareOp, + ) -> Py { + py.None() } - fn __add__<'p>(slf: PyRef<'p, Self>, _other: PyRef<'p, Self>) -> PyRef<'p, Self> { + fn __add__<'p>( + slf: PyClassGuard<'p, Self>, + _other: PyClassGuard<'p, Self>, + ) -> PyClassGuard<'p, Self> { slf } - fn __sub__<'p>(slf: PyRef<'p, Self>, _other: PyRef<'p, Self>) -> PyRef<'p, Self> { + fn __sub__<'p>( + slf: PyClassGuard<'p, Self>, + _other: PyClassGuard<'p, Self>, + ) -> PyClassGuard<'p, Self> { slf } - fn __mul__<'p>(slf: PyRef<'p, Self>, _other: PyRef<'p, Self>) -> PyRef<'p, Self> { + fn __mul__<'p>( + slf: PyClassGuard<'p, Self>, + _other: PyClassGuard<'p, Self>, + ) -> PyClassGuard<'p, Self> { slf } - fn __matmul__<'p>(slf: PyRef<'p, Self>, _other: PyRef<'p, Self>) -> PyRef<'p, Self> { + fn __matmul__<'p>( + slf: PyClassGuard<'p, Self>, + _other: PyClassGuard<'p, Self>, + ) -> PyClassGuard<'p, Self> { slf } - fn __truediv__<'p>(slf: PyRef<'p, Self>, _other: PyRef<'p, Self>) -> PyRef<'p, Self> { + fn __truediv__<'p>( + slf: PyClassGuard<'p, Self>, + _other: PyClassGuard<'p, Self>, + ) -> PyClassGuard<'p, Self> { slf } - fn __floordiv__<'p>(slf: PyRef<'p, Self>, _other: PyRef<'p, Self>) -> PyRef<'p, Self> { + fn __floordiv__<'p>( + slf: PyClassGuard<'p, Self>, + _other: PyClassGuard<'p, Self>, + ) -> PyClassGuard<'p, Self> { slf } - fn __mod__<'p>(slf: PyRef<'p, Self>, _other: PyRef<'p, Self>) -> PyRef<'p, Self> { + fn __mod__<'p>( + slf: PyClassGuard<'p, Self>, + _other: PyClassGuard<'p, Self>, + ) -> PyClassGuard<'p, Self> { slf } - fn __pow__(slf: PyRef<'_, Self>, _other: u8, _modulo: Option) -> PyRef<'_, Self> { + fn __pow__( + slf: PyClassGuard<'_, Self>, + _other: u8, + _modulo: Option, + ) -> PyClassGuard<'_, Self> { slf } - fn __lshift__<'p>(slf: PyRef<'p, Self>, _other: PyRef<'p, Self>) -> PyRef<'p, Self> { + fn __lshift__<'p>( + slf: PyClassGuard<'p, Self>, + _other: PyClassGuard<'p, Self>, + ) -> PyClassGuard<'p, Self> { slf } - fn __rshift__<'p>(slf: PyRef<'p, Self>, _other: PyRef<'p, Self>) -> PyRef<'p, Self> { + fn __rshift__<'p>( + slf: PyClassGuard<'p, Self>, + _other: PyClassGuard<'p, Self>, + ) -> PyClassGuard<'p, Self> { slf } - fn __divmod__<'p>(slf: PyRef<'p, Self>, _other: PyRef<'p, Self>) -> PyRef<'p, Self> { + fn __divmod__<'p>( + slf: PyClassGuard<'p, Self>, + _other: PyClassGuard<'p, Self>, + ) -> PyClassGuard<'p, Self> { slf } - fn __and__<'p>(slf: PyRef<'p, Self>, _other: PyRef<'p, Self>) -> PyRef<'p, Self> { + fn __and__<'p>( + slf: PyClassGuard<'p, Self>, + _other: PyClassGuard<'p, Self>, + ) -> PyClassGuard<'p, Self> { slf } - fn __or__<'p>(slf: PyRef<'p, Self>, _other: PyRef<'p, Self>) -> PyRef<'p, Self> { + fn __or__<'p>( + slf: PyClassGuard<'p, Self>, + _other: PyClassGuard<'p, Self>, + ) -> PyClassGuard<'p, Self> { slf } - fn __xor__<'p>(slf: PyRef<'p, Self>, _other: PyRef<'p, Self>) -> PyRef<'p, Self> { + fn __xor__<'p>( + slf: PyClassGuard<'p, Self>, + _other: PyClassGuard<'p, Self>, + ) -> PyClassGuard<'p, Self> { slf } // Inplace assignments - fn __iadd__(&mut self, _other: PyRef<'_, Self>) {} - fn __isub__(&mut self, _other: PyRef<'_, Self>) {} - fn __imul__(&mut self, _other: PyRef<'_, Self>) {} - fn __imatmul__(&mut self, _other: PyRef<'_, Self>) {} - fn __itruediv__(&mut self, _other: PyRef<'_, Self>) {} - fn __ifloordiv__(&mut self, _other: PyRef<'_, Self>) {} - fn __imod__(&mut self, _other: PyRef<'_, Self>) {} - fn __ilshift__(&mut self, _other: PyRef<'_, Self>) {} - fn __irshift__(&mut self, _other: PyRef<'_, Self>) {} - fn __iand__(&mut self, _other: PyRef<'_, Self>) {} - fn __ior__(&mut self, _other: PyRef<'_, Self>) {} - fn __ixor__(&mut self, _other: PyRef<'_, Self>) {} - fn __ipow__(&mut self, _other: PyRef<'_, Self>, _modulo: Option) {} + fn __iadd__(&mut self, _other: PyClassGuard<'_, Self>) {} + fn __isub__(&mut self, _other: PyClassGuard<'_, Self>) {} + fn __imul__(&mut self, _other: PyClassGuard<'_, Self>) {} + fn __imatmul__(&mut self, _other: PyClassGuard<'_, Self>) {} + fn __itruediv__(&mut self, _other: PyClassGuard<'_, Self>) {} + fn __ifloordiv__(&mut self, _other: PyClassGuard<'_, Self>) {} + fn __imod__(&mut self, _other: PyClassGuard<'_, Self>) {} + fn __ilshift__(&mut self, _other: PyClassGuard<'_, Self>) {} + fn __irshift__(&mut self, _other: PyClassGuard<'_, Self>) {} + fn __iand__(&mut self, _other: PyClassGuard<'_, Self>) {} + fn __ior__(&mut self, _other: PyClassGuard<'_, Self>) {} + fn __ixor__(&mut self, _other: PyClassGuard<'_, Self>) {} + fn __ipow__(&mut self, _other: PyClassGuard<'_, Self>, _modulo: Option) {} } fn _test_binary_dunder(dunder: &str) { diff --git a/tests/test_buffer.rs b/tests/test_buffer.rs index 8cbfd752d95..e438e6d438b 100644 --- a/tests/test_buffer.rs +++ b/tests/test_buffer.rs @@ -29,7 +29,7 @@ struct TestBufferErrors { #[pymethods] impl TestBufferErrors { unsafe fn __getbuffer__( - slf: PyRefMut<'_, Self>, + slf: Bound<'_, Self>, view: *mut ffi::Py_buffer, flags: c_int, ) -> PyResult<()> { @@ -41,7 +41,8 @@ impl TestBufferErrors { return Err(PyBufferError::new_err("Object is not writable")); } - let bytes = &slf.buf; + let borrow = slf.borrow_mut(); + let bytes = &borrow.buf; unsafe { (*view).buf = bytes.as_ptr() as *mut c_void; @@ -60,7 +61,7 @@ impl TestBufferErrors { (*view).suboffsets = ptr::null_mut(); (*view).internal = ptr::null_mut(); - if let Some(err) = &slf.error { + if let Some(err) = &borrow.error { use TestGetBufferError::*; match err { NullShape => { diff --git a/tests/test_class_conversion.rs b/tests/test_class_conversion.rs index f7ad6ea86ef..ccc638b4661 100644 --- a/tests/test_class_conversion.rs +++ b/tests/test_class_conversion.rs @@ -21,11 +21,11 @@ fn test_cloneable_pyclass() { let c2: Cloneable = py_c.extract(py).unwrap(); assert_eq!(c, c2); { - let rc: PyRef<'_, Cloneable> = py_c.extract(py).unwrap(); + let rc: PyClassGuard<'_, Cloneable> = py_c.extract(py).unwrap(); assert_eq!(&c, &*rc); - // Drops PyRef before taking PyRefMut + // Drops PyClassGuard before taking PyClassGuardMut } - let mrc: PyRefMut<'_, Cloneable> = py_c.extract(py).unwrap(); + let mrc: PyClassGuardMut<'_, Cloneable> = py_c.extract(py).unwrap(); assert_eq!(&c, &*mrc); }); } @@ -127,16 +127,16 @@ fn test_pyref_as_base() { let cell = Bound::new(py, initializer).unwrap(); // First try PyRefMut - let sub: PyRefMut<'_, SubClass> = cell.borrow_mut(); - let mut base: PyRefMut<'_, BaseClass> = sub.into_super(); + let sub = cell.borrow_mut(); + let mut base = sub.into_super(); assert_eq!(120, base.value); base.value = 999; assert_eq!(999, base.value); drop(base); // Repeat for PyRef - let sub: PyRef<'_, SubClass> = cell.borrow(); - let base: PyRef<'_, BaseClass> = sub.into_super(); + let sub = cell.borrow(); + let base = sub.into_super(); assert_eq!(999, base.value); }); } diff --git a/tests/test_gc.rs b/tests/test_gc.rs index 822168096a5..648783ca3b2 100644 --- a/tests/test_gc.rs +++ b/tests/test_gc.rs @@ -469,6 +469,7 @@ fn traverse_cannot_be_hijacked() { fn __traverse__(&self, visit: PyVisit<'_>) -> Result<(), PyTraverseError>; } + #[expect(deprecated)] impl Traversable for PyRef<'_, HijackedTraverse> { fn __traverse__(&self, _visit: PyVisit<'_>) -> Result<(), PyTraverseError> { self.hijacked.store(true, Ordering::Release); diff --git a/tests/test_getter_setter.rs b/tests/test_getter_setter.rs index 582cfd89c5f..9bd231f0969 100644 --- a/tests/test_getter_setter.rs +++ b/tests/test_getter_setter.rs @@ -137,12 +137,12 @@ struct RefGetterSetter { #[pymethods] impl RefGetterSetter { #[getter] - fn get_num(slf: PyRef<'_, Self>) -> i32 { + fn get_num(slf: PyClassGuard<'_, Self>) -> i32 { slf.num } #[setter] - fn set_num(mut slf: PyRefMut<'_, Self>, value: i32) { + fn set_num(mut slf: PyClassGuardMut<'_, Self>, value: i32) { slf.num = value; } } diff --git a/tests/test_methods.rs b/tests/test_methods.rs index c0fec231f36..e0c02fe0b9e 100644 --- a/tests/test_methods.rs +++ b/tests/test_methods.rs @@ -796,7 +796,7 @@ impl MethodWithPyClassArg { value: self.value + other.value, } } - fn add_pyref(&self, other: PyRef<'_, MethodWithPyClassArg>) -> MethodWithPyClassArg { + fn add_pyref(&self, other: PyClassGuard<'_, MethodWithPyClassArg>) -> MethodWithPyClassArg { MethodWithPyClassArg { value: self.value + other.value, } @@ -804,7 +804,7 @@ impl MethodWithPyClassArg { fn inplace_add(&self, other: &mut MethodWithPyClassArg) { other.value += self.value; } - fn inplace_add_pyref(&self, mut other: PyRefMut<'_, MethodWithPyClassArg>) { + fn inplace_add_pyref(&self, mut other: PyClassGuardMut<'_, MethodWithPyClassArg>) { other.value += self.value; } #[pyo3(signature=(other = None))] @@ -1269,10 +1269,10 @@ fn test_pymethods_warn() { } #[pyo3(warn(message = "this method raises warning"))] - fn method_with_warning(_slf: PyRef<'_, Self>) {} + fn method_with_warning(_slf: PyClassGuard<'_, Self>) {} #[pyo3(warn(message = "this method raises warning", category = PyFutureWarning))] - fn method_with_warning_and_custom_category(_slf: PyRef<'_, Self>) {} + fn method_with_warning_and_custom_category(_slf: PyClassGuard<'_, Self>) {} #[cfg(any(not(Py_LIMITED_API), Py_3_12))] #[pyo3(warn(message = "this method raises user-defined warning", category = UserDefinedWarning))] @@ -1308,7 +1308,7 @@ fn test_pymethods_warn() { } #[pyo3(warn(message = "the + op method raises warning"))] - fn __add__(&self, other: PyRef<'_, Self>) -> Self { + fn __add__(&self, other: PyClassGuard<'_, Self>) -> Self { Self { value: self.value + other.value, } diff --git a/tests/test_proto_methods.rs b/tests/test_proto_methods.rs index c172d954a7a..83c4a210d63 100644 --- a/tests/test_proto_methods.rs +++ b/tests/test_proto_methods.rs @@ -424,11 +424,11 @@ struct Iterator { #[pymethods] impl Iterator { - fn __iter__(slf: PyRef<'_, Self>) -> PyRef<'_, Self> { + fn __iter__(slf: PyClassGuard<'_, Self>) -> PyClassGuard<'_, Self> { slf } - fn __next__(slf: PyRefMut<'_, Self>) -> Option { + fn __next__(slf: PyClassGuardMut<'_, Self>) -> Option { slf.iter.lock().unwrap().next() } } @@ -748,11 +748,11 @@ impl OnceFuture { } } - fn __await__(slf: PyRef<'_, Self>) -> PyRef<'_, Self> { + fn __await__(slf: PyClassGuard<'_, Self>) -> PyClassGuard<'_, Self> { slf } - fn __iter__(slf: PyRef<'_, Self>) -> PyRef<'_, Self> { + fn __iter__(slf: PyClassGuard<'_, Self>) -> PyClassGuard<'_, Self> { slf } fn __next__<'py>(&mut self, py: Python<'py>) -> Option<&Bound<'py, PyAny>> { @@ -809,7 +809,7 @@ impl AsyncIterator { } } - fn __aiter__(slf: PyRef<'_, Self>) -> PyRef<'_, Self> { + fn __aiter__(slf: PyClassGuard<'_, Self>) -> PyClassGuard<'_, Self> { slf } @@ -872,10 +872,10 @@ impl DescrCounter { } /// Each access will increase the count fn __get__<'a>( - mut slf: PyRefMut<'a, Self>, + mut slf: PyClassGuardMut<'a, Self>, _instance: &Bound<'_, PyAny>, _owner: Option<&Bound<'_, PyType>>, - ) -> PyRefMut<'a, Self> { + ) -> PyClassGuardMut<'a, Self> { slf.count += 1; slf } diff --git a/tests/test_pyself.rs b/tests/test_pyself.rs index 7a34dedbc7e..5511683e3be 100644 --- a/tests/test_pyself.rs +++ b/tests/test_pyself.rs @@ -34,7 +34,7 @@ impl Reader { } } fn get_iter_and_reset( - mut slf: PyRefMut<'_, Self>, + mut slf: PyClassGuardMut<'_, Self>, keys: Py, py: Python<'_>, ) -> PyResult { @@ -59,16 +59,15 @@ struct Iter { #[pymethods] impl Iter { #[expect(clippy::self_named_constructors)] - fn __iter__(slf: PyRef<'_, Self>) -> PyRef<'_, Self> { + fn __iter__(slf: PyClassGuard<'_, Self>) -> PyClassGuard<'_, Self> { slf } - fn __next__(mut slf: PyRefMut<'_, Self>) -> PyResult>> { - let bytes = slf.keys.bind(slf.py()).as_bytes(); + fn __next__(mut slf: PyClassGuardMut<'_, Self>, py: Python<'_>) -> PyResult>> { + let bytes = slf.keys.bind(py).as_bytes(); match bytes.get(slf.idx) { Some(&b) => { slf.idx += 1; - let py = slf.py(); let reader = slf.reader.bind(py); let reader_ref = reader.try_borrow()?; let res = reader_ref diff --git a/tests/test_sequence.rs b/tests/test_sequence.rs index 55d20353577..73eb022bb79 100644 --- a/tests/test_sequence.rs +++ b/tests/test_sequence.rs @@ -75,9 +75,12 @@ impl ByteSequence { Self { elements } } - fn __inplace_concat__(mut slf: PyRefMut<'_, Self>, other: &Self) -> Py { + fn __inplace_concat__<'a>( + mut slf: PyClassGuardMut<'a, Self>, + other: &Self, + ) -> PyClassGuardMut<'a, Self> { slf.elements.extend_from_slice(&other.elements); - slf.into() + slf } fn __repeat__(&self, count: isize) -> PyResult { @@ -92,14 +95,18 @@ impl ByteSequence { } } - fn __inplace_repeat__(mut slf: PyRefMut<'_, Self>, count: isize) -> PyResult> { + fn __inplace_repeat__( + mut slf: PyClassGuardMut<'_, Self>, + py: Python<'_>, + count: isize, + ) -> PyResult> { if count >= 0 { let mut elements = Vec::with_capacity(slf.elements.len() * count as usize); for _ in 0..count { elements.extend(&slf.elements); } slf.elements = elements; - Ok(slf.into()) + Ok(slf.into_pyobject(py)?.to_owned().unbind()) } else { Err(PyValueError::new_err("invalid repeat count")) } diff --git a/tests/test_various.rs b/tests/test_various.rs index cf2ae82b5ff..9ace7c4cd2e 100644 --- a/tests/test_various.rs +++ b/tests/test_various.rs @@ -18,7 +18,7 @@ impl MutRefArg { fn get(&self) -> i32 { self.n } - fn set_other(&self, mut other: PyRefMut<'_, MutRefArg>) { + fn set_other(&self, mut other: PyClassGuardMut<'_, MutRefArg>) { other.n = 100; } } diff --git a/tests/ui/invalid_async.rs b/tests/ui/invalid_async.rs index 915f30e35f1..6b802c6a2a0 100644 --- a/tests/ui/invalid_async.rs +++ b/tests/ui/invalid_async.rs @@ -11,7 +11,7 @@ pub(crate) struct AsyncRange { } #[pymethods] impl AsyncRange { - async fn __anext__(mut _pyself: PyRefMut<'_, Self>) -> PyResult { + async fn __anext__(mut _pyself: PyClassGuardMut<'_, Self>) -> PyResult { //~^ ERROR: async functions are only supported with the `experimental-async` feature Ok(0) } diff --git a/tests/ui/invalid_async.stderr b/tests/ui/invalid_async.stderr index 35649d07955..470f710f639 100644 --- a/tests/ui/invalid_async.stderr +++ b/tests/ui/invalid_async.stderr @@ -7,7 +7,7 @@ error: async functions are only supported with the `experimental-async` feature error: async functions are only supported with the `experimental-async` feature --> tests/ui/invalid_async.rs:14:5 | -14 | async fn __anext__(mut _pyself: PyRefMut<'_, Self>) -> PyResult { +14 | async fn __anext__(mut _pyself: PyClassGuardMut<'_, Self>) -> PyResult { | ^^^^^ error: async functions are only supported with the `experimental-async` feature diff --git a/tests/ui/traverse.rs b/tests/ui/traverse.rs index d65d46e3e71..4037784787f 100644 --- a/tests/ui/traverse.rs +++ b/tests/ui/traverse.rs @@ -7,8 +7,9 @@ struct TraverseTriesToTakePyRef {} #[pymethods] impl TraverseTriesToTakePyRef { + #[expect(deprecated)] fn __traverse__(_slf: PyRef, _visit: PyVisit) -> Result<(), PyTraverseError> { -//~^ ERROR: __traverse__ may not take a receiver other than `&self`. Usually, an implementation of `__traverse__(&self, visit: PyVisit<'_>) -> Result<(), PyTraverseError>` should do nothing but calls to `visit.call`. Most importantly, safe access to the Python interpreter is prohibited inside implementations of `__traverse__`, i.e. `Python::attach` will panic. + //~^ ERROR: __traverse__ may not take a receiver other than `&self`. Usually, an implementation of `__traverse__(&self, visit: PyVisit<'_>) -> Result<(), PyTraverseError>` should do nothing but calls to `visit.call`. Most importantly, safe access to the Python interpreter is prohibited inside implementations of `__traverse__`, i.e. `Python::attach` will panic. Ok(()) } } @@ -18,8 +19,9 @@ struct TraverseTriesToTakePyRefMut {} #[pymethods] impl TraverseTriesToTakePyRefMut { + #[expect(deprecated)] fn __traverse__(_slf: PyRefMut, _visit: PyVisit) -> Result<(), PyTraverseError> { -//~^ ERROR: __traverse__ may not take a receiver other than `&self`. Usually, an implementation of `__traverse__(&self, visit: PyVisit<'_>) -> Result<(), PyTraverseError>` should do nothing but calls to `visit.call`. Most importantly, safe access to the Python interpreter is prohibited inside implementations of `__traverse__`, i.e. `Python::attach` will panic. + //~^ ERROR: __traverse__ may not take a receiver other than `&self`. Usually, an implementation of `__traverse__(&self, visit: PyVisit<'_>) -> Result<(), PyTraverseError>` should do nothing but calls to `visit.call`. Most importantly, safe access to the Python interpreter is prohibited inside implementations of `__traverse__`, i.e. `Python::attach` will panic. Ok(()) } } @@ -30,7 +32,7 @@ struct TraverseTriesToTakeBound {} #[pymethods] impl TraverseTriesToTakeBound { fn __traverse__(_slf: Bound<'_, Self>, _visit: PyVisit) -> Result<(), PyTraverseError> { -//~^ ERROR: __traverse__ may not take a receiver other than `&self`. Usually, an implementation of `__traverse__(&self, visit: PyVisit<'_>) -> Result<(), PyTraverseError>` should do nothing but calls to `visit.call`. Most importantly, safe access to the Python interpreter is prohibited inside implementations of `__traverse__`, i.e. `Python::attach` will panic. + //~^ ERROR: __traverse__ may not take a receiver other than `&self`. Usually, an implementation of `__traverse__(&self, visit: PyVisit<'_>) -> Result<(), PyTraverseError>` should do nothing but calls to `visit.call`. Most importantly, safe access to the Python interpreter is prohibited inside implementations of `__traverse__`, i.e. `Python::attach` will panic. Ok(()) } } @@ -41,7 +43,7 @@ struct TraverseTriesToTakeMutSelf {} #[pymethods] impl TraverseTriesToTakeMutSelf { fn __traverse__(&mut self, _visit: PyVisit) -> Result<(), PyTraverseError> { -//~^ ERROR: __traverse__ may not take a receiver other than `&self`. Usually, an implementation of `__traverse__(&self, visit: PyVisit<'_>) -> Result<(), PyTraverseError>` should do nothing but calls to `visit.call`. Most importantly, safe access to the Python interpreter is prohibited inside implementations of `__traverse__`, i.e. `Python::attach` will panic. + //~^ ERROR: __traverse__ may not take a receiver other than `&self`. Usually, an implementation of `__traverse__(&self, visit: PyVisit<'_>) -> Result<(), PyTraverseError>` should do nothing but calls to `visit.call`. Most importantly, safe access to the Python interpreter is prohibited inside implementations of `__traverse__`, i.e. `Python::attach` will panic. Ok(()) } } @@ -62,7 +64,7 @@ struct Class; #[pymethods] impl Class { fn __traverse__(&self, _py: Python<'_>, _visit: PyVisit<'_>) -> Result<(), PyTraverseError> { -//~^ ERROR: __traverse__ may not take `Python`. Usually, an implementation of `__traverse__(&self, visit: PyVisit<'_>) -> Result<(), PyTraverseError>` should do nothing but calls to `visit.call`. Most importantly, safe access to the Python interpreter is prohibited inside implementations of `__traverse__`, i.e. `Python::attach` will panic. + //~^ ERROR: __traverse__ may not take `Python`. Usually, an implementation of `__traverse__(&self, visit: PyVisit<'_>) -> Result<(), PyTraverseError>` should do nothing but calls to `visit.call`. Most importantly, safe access to the Python interpreter is prohibited inside implementations of `__traverse__`, i.e. `Python::attach` will panic. Ok(()) } diff --git a/tests/ui/traverse.stderr b/tests/ui/traverse.stderr index 701ce4bccb4..43f3f6c25b7 100644 --- a/tests/ui/traverse.stderr +++ b/tests/ui/traverse.stderr @@ -1,31 +1,31 @@ error: __traverse__ may not take a receiver other than `&self`. Usually, an implementation of `__traverse__(&self, visit: PyVisit<'_>) -> Result<(), PyTraverseError>` should do nothing but calls to `visit.call`. Most importantly, safe access to the Python interpreter is prohibited inside implementations of `__traverse__`, i.e. `Python::attach` will panic. - --> tests/ui/traverse.rs:10:27 + --> tests/ui/traverse.rs:11:27 | -10 | fn __traverse__(_slf: PyRef, _visit: PyVisit) -> Result<(), PyTraverseError> { +11 | fn __traverse__(_slf: PyRef, _visit: PyVisit) -> Result<(), PyTraverseError> { | ^^^^^ error: __traverse__ may not take a receiver other than `&self`. Usually, an implementation of `__traverse__(&self, visit: PyVisit<'_>) -> Result<(), PyTraverseError>` should do nothing but calls to `visit.call`. Most importantly, safe access to the Python interpreter is prohibited inside implementations of `__traverse__`, i.e. `Python::attach` will panic. - --> tests/ui/traverse.rs:21:27 + --> tests/ui/traverse.rs:23:27 | -21 | fn __traverse__(_slf: PyRefMut, _visit: PyVisit) -> Result<(), PyTraverseError> { +23 | fn __traverse__(_slf: PyRefMut, _visit: PyVisit) -> Result<(), PyTraverseError> { | ^^^^^^^^ error: __traverse__ may not take a receiver other than `&self`. Usually, an implementation of `__traverse__(&self, visit: PyVisit<'_>) -> Result<(), PyTraverseError>` should do nothing but calls to `visit.call`. Most importantly, safe access to the Python interpreter is prohibited inside implementations of `__traverse__`, i.e. `Python::attach` will panic. - --> tests/ui/traverse.rs:32:27 + --> tests/ui/traverse.rs:34:27 | -32 | fn __traverse__(_slf: Bound<'_, Self>, _visit: PyVisit) -> Result<(), PyTraverseError> { +34 | fn __traverse__(_slf: Bound<'_, Self>, _visit: PyVisit) -> Result<(), PyTraverseError> { | ^^^^^ error: __traverse__ may not take a receiver other than `&self`. Usually, an implementation of `__traverse__(&self, visit: PyVisit<'_>) -> Result<(), PyTraverseError>` should do nothing but calls to `visit.call`. Most importantly, safe access to the Python interpreter is prohibited inside implementations of `__traverse__`, i.e. `Python::attach` will panic. - --> tests/ui/traverse.rs:43:21 + --> tests/ui/traverse.rs:45:21 | -43 | fn __traverse__(&mut self, _visit: PyVisit) -> Result<(), PyTraverseError> { +45 | fn __traverse__(&mut self, _visit: PyVisit) -> Result<(), PyTraverseError> { | ^ error: __traverse__ may not take `Python`. Usually, an implementation of `__traverse__(&self, visit: PyVisit<'_>) -> Result<(), PyTraverseError>` should do nothing but calls to `visit.call`. Most importantly, safe access to the Python interpreter is prohibited inside implementations of `__traverse__`, i.e. `Python::attach` will panic. - --> tests/ui/traverse.rs:64:33 + --> tests/ui/traverse.rs:66:33 | -64 | fn __traverse__(&self, _py: Python<'_>, _visit: PyVisit<'_>) -> Result<(), PyTraverseError> { +66 | fn __traverse__(&self, _py: Python<'_>, _visit: PyVisit<'_>) -> Result<(), PyTraverseError> { | ^^^^^^^^^^ error: aborting due to 5 previous errors