diff --git a/guide/src/memory.md b/guide/src/memory.md index cd4af4f8f13..a6640e65cf3 100644 --- a/guide/src/memory.md +++ b/guide/src/memory.md @@ -177,9 +177,11 @@ What happens to the memory when the last `Py` is dropped and its reference count reaches zero? It depends whether or not we are holding the GIL. ```rust +# #![allow(unused_imports)] # use pyo3::prelude::*; # use pyo3::types::PyString; # fn main() -> PyResult<()> { +# #[cfg(feature = "gil-refs")] Python::with_gil(|py| -> PyResult<()> { #[allow(deprecated)] // py.eval() is part of the GIL Refs API let hello: Py = py.eval("\"Hello World!\"", None, None)?.extract()?; @@ -203,9 +205,12 @@ This example wasn't very interesting. We could have just used a GIL-bound we are *not* holding the GIL? ```rust +# #![allow(unused_imports)] # use pyo3::prelude::*; # use pyo3::types::PyString; # fn main() -> PyResult<()> { +# #[cfg(feature = "gil-refs")] +# { let hello: Py = Python::with_gil(|py| { #[allow(deprecated)] // py.eval() is part of the GIL Refs API py.eval("\"Hello World!\"", None, None)?.extract() @@ -224,6 +229,7 @@ Python::with_gil(|py| // Memory for `hello` is released here. # () ); +# } # Ok(()) # } ``` @@ -237,9 +243,12 @@ We can avoid the delay in releasing memory if we are careful to drop the `Py` while the GIL is held. ```rust +# #![allow(unused_imports)] # use pyo3::prelude::*; # use pyo3::types::PyString; # fn main() -> PyResult<()> { +# #[cfg(feature = "gil-refs")] +# { #[allow(deprecated)] // py.eval() is part of the GIL Refs API let hello: Py = Python::with_gil(|py| py.eval("\"Hello World!\"", None, None)?.extract())?; @@ -252,6 +261,7 @@ Python::with_gil(|py| { } drop(hello); // Memory released here. }); +# } # Ok(()) # } ``` @@ -263,9 +273,12 @@ that rather than being released immediately, the memory will not be released until the GIL is dropped. ```rust +# #![allow(unused_imports)] # use pyo3::prelude::*; # use pyo3::types::PyString; # fn main() -> PyResult<()> { +# #[cfg(feature = "gil-refs")] +# { #[allow(deprecated)] // py.eval() is part of the GIL Refs API let hello: Py = Python::with_gil(|py| py.eval("\"Hello World!\"", None, None)?.extract())?; @@ -280,6 +293,7 @@ Python::with_gil(|py| { // Do more stuff... // Memory released here at end of `with_gil()` closure. }); +# } # Ok(()) # } ``` diff --git a/guide/src/python-from-rust/function-calls.md b/guide/src/python-from-rust/function-calls.md index f97de1f24ce..c19d6fafabc 100644 --- a/guide/src/python-from-rust/function-calls.md +++ b/guide/src/python-from-rust/function-calls.md @@ -107,7 +107,7 @@ fn main() -> PyResult<()> {
-During PyO3's [migration from "GIL Refs" to the `Bound` smart pointer](../migration.md#migrating-from-the-gil-refs-api-to-boundt), [`Py::call`]({{#PYO3_DOCS_URL}}/pyo3/struct.Py.html#method.call) is temporarily named `call_bound` (and `call_method` is temporarily `call_method_bound`). +During PyO3's [migration from "GIL Refs" to the `Bound` smart pointer](../migration.md#migrating-from-the-gil-refs-api-to-boundt), `Py::call` is temporarily named [`Py::call_bound`]({{#PYO3_DOCS_URL}}/pyo3/struct.Py.html#method.call_bound) (and `call_method` is temporarily `call_method_bound`). (This temporary naming is only the case for the `Py` smart pointer. The methods on the `&PyAny` GIL Ref such as `call` have not been given replacements, and the methods on the `Bound` smart pointer such as [`Bound::call`]({{#PYO3_DOCS_URL}}/pyo3/types/trait.PyAnyMethods.html#tymethod.call) already use follow the newest API conventions.) diff --git a/guide/src/types.md b/guide/src/types.md index 82040de2c43..d28fb7e15d6 100644 --- a/guide/src/types.md +++ b/guide/src/types.md @@ -353,8 +353,10 @@ let _: Py = obj.extract()?; For a `&PyAny` object reference `any` where the underlying object is a `#[pyclass]`: ```rust +# #![allow(unused_imports)] # use pyo3::prelude::*; # #[pyclass] #[derive(Clone)] struct MyClass { } +# #[cfg(feature = "gil-refs")] # Python::with_gil(|py| -> PyResult<()> { #[allow(deprecated)] // into_ref is part of the deprecated GIL Refs API let obj: &PyAny = Py::new(py, MyClass {})?.into_ref(py); diff --git a/src/err/mod.rs b/src/err/mod.rs index 4f46f360094..d923761af1d 100644 --- a/src/err/mod.rs +++ b/src/err/mod.rs @@ -64,6 +64,7 @@ impl<'a> PyDowncastError<'a> { /// Compatibility API to convert the Bound variant `DowncastError` into the /// gil-ref variant + #[cfg(feature = "gil-refs")] pub(crate) fn from_downcast_err(DowncastError { from, to }: DowncastError<'a, 'a>) -> Self { #[allow(deprecated)] let from = unsafe { from.py().from_borrowed_ptr(from.as_ptr()) }; diff --git a/src/instance.rs b/src/instance.rs index cc892a2dd44..11d45df6f78 100644 --- a/src/instance.rs +++ b/src/instance.rs @@ -1,4 +1,4 @@ -use crate::err::{self, PyDowncastError, PyErr, PyResult}; +use crate::err::{self, PyErr, PyResult}; use crate::impl_::pycell::PyClassObject; use crate::pycell::{PyBorrowError, PyBorrowMutError}; use crate::pyclass::boolean_struct::{False, True}; @@ -721,12 +721,12 @@ impl IntoPy for Borrowed<'_, '_, T> { /// /// This type does not auto-dereference to the inner object because you must prove you hold the GIL to access it. /// Instead, call one of its methods to access the inner object: -/// - [`Py::as_ref`], to borrow a GIL-bound reference to the contained object. +/// - [`Py::bind`] or [`Py::into_bound`], to borrow a GIL-bound reference to the contained object. /// - [`Py::borrow`], [`Py::try_borrow`], [`Py::borrow_mut`], or [`Py::try_borrow_mut`], /// to get a (mutable) reference to a contained pyclass, using a scheme similar to std's [`RefCell`]. -/// See the [`PyCell` guide entry](https://pyo3.rs/latest/class.html#pycell-and-interior-mutability) +/// See the [guide entry](https://pyo3.rs/latest/class.html#bound-and-interior-mutability) /// for more information. -/// - You can call methods directly on `Py` with [`Py::call`], [`Py::call_method`] and friends. +/// - You can call methods directly on `Py` with [`Py::call_bound`], [`Py::call_method_bound`] and friends. /// These require passing in the [`Python<'py>`](crate::Python) token but are otherwise similar to the corresponding /// methods on [`PyAny`]. /// @@ -991,12 +991,10 @@ where /// assert!(my_class_cell.try_borrow().is_ok()); /// }); /// ``` - #[cfg_attr( - not(feature = "gil-refs"), - deprecated( - since = "0.21.0", - note = "use `obj.bind(py)` instead of `obj.as_ref(py)`" - ) + #[cfg(feature = "gil-refs")] + #[deprecated( + since = "0.21.0", + note = "use `obj.bind(py)` instead of `obj.as_ref(py)`" )] pub fn as_ref<'py>(&'py self, _py: Python<'py>) -> &'py T::AsRefTarget { let any = self.as_ptr() as *const PyAny; @@ -1046,12 +1044,10 @@ where /// obj.into_ref(py) /// } /// ``` - #[cfg_attr( - not(feature = "gil-refs"), - deprecated( - since = "0.21.0", - note = "use `obj.into_bound(py)` instead of `obj.into_ref(py)`" - ) + #[cfg(feature = "gil-refs")] + #[deprecated( + since = "0.21.0", + note = "use `obj.into_bound(py)` instead of `obj.into_ref(py)`" )] pub fn into_ref(self, py: Python<'_>) -> &T::AsRefTarget { #[allow(deprecated)] @@ -1464,12 +1460,10 @@ impl Py { } /// Deprecated form of [`call_bound`][Py::call_bound]. - #[cfg_attr( - not(feature = "gil-refs"), - deprecated( - since = "0.21.0", - note = "`call` will be replaced by `call_bound` in a future PyO3 version" - ) + #[cfg(feature = "gil-refs")] + #[deprecated( + since = "0.21.0", + note = "`call` will be replaced by `call_bound` in a future PyO3 version" )] #[inline] pub fn call(&self, py: Python<'_>, args: A, kwargs: Option<&PyDict>) -> PyResult @@ -1506,12 +1500,10 @@ impl Py { } /// Deprecated form of [`call_method_bound`][Py::call_method_bound]. - #[cfg_attr( - not(feature = "gil-refs"), - deprecated( - since = "0.21.0", - note = "`call_method` will be replaced by `call_method_bound` in a future PyO3 version" - ) + #[cfg(feature = "gil-refs")] + #[deprecated( + since = "0.21.0", + note = "`call_method` will be replaced by `call_method_bound` in a future PyO3 version" )] #[inline] pub fn call_method( @@ -1779,6 +1771,7 @@ impl std::convert::From> for Py { } // `&PyCell` can be converted to `Py` +#[cfg(feature = "gil-refs")] #[allow(deprecated)] impl std::convert::From<&crate::PyCell> for Py where @@ -1844,10 +1837,7 @@ where { /// Extracts `Self` from the source `PyObject`. fn extract_bound(ob: &Bound<'py, PyAny>) -> PyResult { - // TODO update MSRV past 1.59 and use .cloned() to make - // clippy happy - #[allow(clippy::map_clone)] - ob.downcast().map(Clone::clone).map_err(Into::into) + ob.downcast().cloned().map_err(Into::into) } } @@ -1888,21 +1878,22 @@ pub type PyObject = Py; impl PyObject { /// Deprecated form of [`PyObject::downcast_bound`] - #[cfg_attr( - not(feature = "gil-refs"), - deprecated( - since = "0.21.0", - note = "`PyObject::downcast` will be replaced by `PyObject::downcast_bound` in a future PyO3 version" - ) + #[cfg(feature = "gil-refs")] + #[deprecated( + since = "0.21.0", + note = "`PyObject::downcast` will be replaced by `PyObject::downcast_bound` in a future PyO3 version" )] #[inline] - pub fn downcast<'py, T>(&'py self, py: Python<'py>) -> Result<&'py T, PyDowncastError<'py>> + pub fn downcast<'py, T>( + &'py self, + py: Python<'py>, + ) -> Result<&'py T, crate::err::PyDowncastError<'py>> where T: PyTypeCheck, { self.downcast_bound::(py) .map(Bound::as_gil_ref) - .map_err(PyDowncastError::from_downcast_err) + .map_err(crate::err::PyDowncastError::from_downcast_err) } /// Downcast this `PyObject` to a concrete Python type or pyclass. /// @@ -1970,12 +1961,10 @@ impl PyObject { /// # Safety /// /// Callers must ensure that the type is valid or risk type confusion. - #[cfg_attr( - not(feature = "gil-refs"), - deprecated( - since = "0.21.0", - note = "`PyObject::downcast_unchecked` will be replaced by `PyObject::downcast_bound_unchecked` in a future PyO3 version" - ) + #[cfg(feature = "gil-refs")] + #[deprecated( + since = "0.21.0", + note = "`PyObject::downcast_unchecked` will be replaced by `PyObject::downcast_bound_unchecked` in a future PyO3 version" )] #[inline] pub unsafe fn downcast_unchecked<'py, T>(&'py self, py: Python<'py>) -> &T @@ -1997,35 +1986,31 @@ impl PyObject { } #[cfg(test)] -#[cfg_attr(not(feature = "gil-refs"), allow(deprecated))] mod tests { use super::{Bound, Py, PyObject}; use crate::types::any::PyAnyMethods; use crate::types::{dict::IntoPyDict, PyDict, PyString}; use crate::types::{PyCapsule, PyStringMethods}; - use crate::{ffi, Borrowed, PyAny, PyNativeType, PyResult, Python, ToPyObject}; + use crate::{ffi, Borrowed, PyAny, PyResult, Python, ToPyObject}; #[test] fn test_call() { Python::with_gil(|py| { - let obj = py.get_type::().to_object(py); + let obj = py.get_type_bound::().to_object(py); - let assert_repr = |obj: &PyAny, expected: &str| { - assert_eq!(obj.repr().unwrap().to_str().unwrap(), expected); + let assert_repr = |obj: &Bound<'_, PyAny>, expected: &str| { + assert_eq!(obj.repr().unwrap().to_cow().unwrap(), expected); }; - assert_repr(obj.call0(py).unwrap().as_ref(py), "{}"); - assert_repr(obj.call1(py, ()).unwrap().as_ref(py), "{}"); - assert_repr(obj.call(py, (), None).unwrap().as_ref(py), "{}"); + assert_repr(obj.call0(py).unwrap().bind(py), "{}"); + assert_repr(obj.call1(py, ()).unwrap().bind(py), "{}"); + assert_repr(obj.call_bound(py, (), None).unwrap().bind(py), "{}"); - assert_repr( - obj.call1(py, ((('x', 1),),)).unwrap().as_ref(py), - "{'x': 1}", - ); + assert_repr(obj.call1(py, ((('x', 1),),)).unwrap().bind(py), "{'x': 1}"); assert_repr( obj.call_bound(py, (), Some(&[('x', 1)].into_py_dict_bound(py))) .unwrap() - .as_ref(py), + .bind(py), "{'x': 1}", ); }) @@ -2037,7 +2022,7 @@ mod tests { let obj: PyObject = PyDict::new_bound(py).into(); assert!(obj.call_method0(py, "asdf").is_err()); assert!(obj - .call_method(py, "nonexistent_method", (1,), None) + .call_method_bound(py, "nonexistent_method", (1,), None) .is_err()); assert!(obj.call_method0(py, "nonexistent_method").is_err()); assert!(obj.call_method1(py, "nonexistent_method", (1,)).is_err()); @@ -2083,7 +2068,7 @@ a = A() assert!(instance .getattr(py, "foo")? - .as_ref(py) + .bind(py) .eq(PyString::new_bound(py, "bar"))?); instance.getattr(py, "foo")?; @@ -2109,7 +2094,7 @@ a = A() instance.getattr(py, foo).unwrap_err(); instance.setattr(py, foo, bar)?; - assert!(instance.getattr(py, foo)?.as_ref(py).eq(bar)?); + assert!(instance.getattr(py, foo)?.bind(py).eq(bar)?); Ok(()) }) } @@ -2117,7 +2102,7 @@ a = A() #[test] fn invalid_attr() -> PyResult<()> { Python::with_gil(|py| { - let instance: Py = py.eval("object()", None, None)?.into(); + let instance: Py = py.eval_bound("object()", None, None)?.into(); instance.getattr(py, "foo").unwrap_err(); @@ -2130,7 +2115,7 @@ a = A() #[test] fn test_py2_from_py_object() { Python::with_gil(|py| { - let instance: &PyAny = py.eval("object()", None, None).unwrap(); + let instance = py.eval_bound("object()", None, None).unwrap(); let ptr = instance.as_ptr(); let instance: Bound<'_, PyAny> = instance.extract().unwrap(); assert_eq!(instance.as_ptr(), ptr); @@ -2141,7 +2126,7 @@ a = A() fn test_py2_into_py_object() { Python::with_gil(|py| { let instance = py - .eval("object()", None, None) + .eval_bound("object()", None, None) .unwrap() .as_borrowed() .to_owned(); diff --git a/src/marker.rs b/src/marker.rs index b1f2d399209..29aae69d4f2 100644 --- a/src/marker.rs +++ b/src/marker.rs @@ -116,18 +116,17 @@ //! [`SendWrapper`]: https://docs.rs/send_wrapper/latest/send_wrapper/struct.SendWrapper.html //! [`Rc`]: std::rc::Rc //! [`Py`]: crate::Py -use crate::err::{self, PyDowncastError, PyErr, PyResult}; +use crate::err::{self, PyErr, PyResult}; use crate::ffi_ptr_ext::FfiPtrExt; use crate::gil::{GILGuard, SuspendGIL}; use crate::impl_::not_send::NotSend; use crate::py_result_ext::PyResultExt; -use crate::type_object::HasPyGilRef; use crate::types::any::PyAnyMethods; use crate::types::{ PyAny, PyDict, PyEllipsis, PyModule, PyNone, PyNotImplemented, PyString, PyType, }; use crate::version::PythonVersionInfo; -use crate::{ffi, Bound, IntoPy, Py, PyNativeType, PyObject, PyTypeCheck, PyTypeInfo}; +use crate::{ffi, Bound, IntoPy, Py, PyNativeType, PyObject, PyTypeInfo}; #[allow(deprecated)] use crate::{gil::GILPool, FromPyPointer}; use std::ffi::{CStr, CString}; @@ -839,16 +838,17 @@ impl<'py> Python<'py> { } /// Registers the object in the release pool, and tries to downcast to specific type. - #[cfg_attr( - not(feature = "gil-refs"), - deprecated( - since = "0.21.0", - note = "use `obj.downcast_bound::(py)` instead of `py.checked_cast_as::(obj)`" - ) + #[cfg(feature = "gil-refs")] + #[deprecated( + since = "0.21.0", + note = "use `obj.downcast_bound::(py)` instead of `py.checked_cast_as::(obj)`" )] - pub fn checked_cast_as(self, obj: PyObject) -> Result<&'py T, PyDowncastError<'py>> + pub fn checked_cast_as( + self, + obj: PyObject, + ) -> Result<&'py T, crate::err::PyDowncastError<'py>> where - T: PyTypeCheck, + T: crate::PyTypeCheck, { #[allow(deprecated)] obj.into_ref(self).downcast() @@ -860,16 +860,14 @@ impl<'py> Python<'py> { /// # Safety /// /// Callers must ensure that ensure that the cast is valid. - #[cfg_attr( - not(feature = "gil-refs"), - deprecated( - since = "0.21.0", - note = "use `obj.downcast_bound_unchecked::(py)` instead of `py.cast_as::(obj)`" - ) + #[cfg(feature = "gil-refs")] + #[deprecated( + since = "0.21.0", + note = "use `obj.downcast_bound_unchecked::(py)` instead of `py.cast_as::(obj)`" )] pub unsafe fn cast_as(self, obj: PyObject) -> &'py T where - T: HasPyGilRef, + T: crate::type_object::HasPyGilRef, { #[allow(deprecated)] obj.into_ref(self).downcast_unchecked() diff --git a/src/types/any.rs b/src/types/any.rs index 8b0bac44ca6..1854308ae7f 100644 --- a/src/types/any.rs +++ b/src/types/any.rs @@ -2705,17 +2705,16 @@ class SimpleClass: } #[test] - #[allow(deprecated)] fn test_is_ellipsis() { Python::with_gil(|py| { let v = py - .eval("...", None, None) + .eval_bound("...", None, None) .map_err(|e| e.display(py)) .unwrap(); assert!(v.is_ellipsis()); - let not_ellipsis = 5.to_object(py).into_ref(py); + let not_ellipsis = 5.to_object(py).into_bound(py); assert!(!not_ellipsis.is_ellipsis()); }); } diff --git a/src/types/dict.rs b/src/types/dict.rs index 64b3adcad44..68cca1cd981 100644 --- a/src/types/dict.rs +++ b/src/types/dict.rs @@ -817,8 +817,6 @@ where #[cfg(test)] mod tests { use super::*; - #[cfg(not(any(PyPy, GraalPy)))] - use crate::exceptions; use crate::types::PyTuple; use std::collections::{BTreeMap, HashMap}; @@ -948,7 +946,7 @@ mod tests { #[test] #[allow(deprecated)] - #[cfg(not(any(PyPy, GraalPy)))] + #[cfg(all(not(any(PyPy, GraalPy)), feature = "gil-refs"))] fn test_get_item_with_error() { Python::with_gil(|py| { let mut v = HashMap::new(); @@ -967,7 +965,7 @@ mod tests { assert!(dict .get_item_with_error(dict) .unwrap_err() - .is_instance_of::(py)); + .is_instance_of::(py)); }); }