feature gate deprecated APIs for `Py` (#4142)

This commit is contained in:
Icxolu 2024-05-01 12:57:03 +02:00 committed by GitHub
parent 261d27d197
commit dc9a41521a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 88 additions and 91 deletions

View File

@ -177,9 +177,11 @@ What happens to the memory when the last `Py<PyAny>` is dropped and its
reference count reaches zero? It depends whether or not we are holding the GIL. reference count reaches zero? It depends whether or not we are holding the GIL.
```rust ```rust
# #![allow(unused_imports)]
# use pyo3::prelude::*; # use pyo3::prelude::*;
# use pyo3::types::PyString; # use pyo3::types::PyString;
# fn main() -> PyResult<()> { # fn main() -> PyResult<()> {
# #[cfg(feature = "gil-refs")]
Python::with_gil(|py| -> PyResult<()> { Python::with_gil(|py| -> PyResult<()> {
#[allow(deprecated)] // py.eval() is part of the GIL Refs API #[allow(deprecated)] // py.eval() is part of the GIL Refs API
let hello: Py<PyString> = py.eval("\"Hello World!\"", None, None)?.extract()?; let hello: Py<PyString> = 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? we are *not* holding the GIL?
```rust ```rust
# #![allow(unused_imports)]
# use pyo3::prelude::*; # use pyo3::prelude::*;
# use pyo3::types::PyString; # use pyo3::types::PyString;
# fn main() -> PyResult<()> { # fn main() -> PyResult<()> {
# #[cfg(feature = "gil-refs")]
# {
let hello: Py<PyString> = Python::with_gil(|py| { let hello: Py<PyString> = Python::with_gil(|py| {
#[allow(deprecated)] // py.eval() is part of the GIL Refs API #[allow(deprecated)] // py.eval() is part of the GIL Refs API
py.eval("\"Hello World!\"", None, None)?.extract() py.eval("\"Hello World!\"", None, None)?.extract()
@ -224,6 +229,7 @@ Python::with_gil(|py|
// Memory for `hello` is released here. // Memory for `hello` is released here.
# () # ()
); );
# }
# Ok(()) # Ok(())
# } # }
``` ```
@ -237,9 +243,12 @@ We can avoid the delay in releasing memory if we are careful to drop the
`Py<Any>` while the GIL is held. `Py<Any>` while the GIL is held.
```rust ```rust
# #![allow(unused_imports)]
# use pyo3::prelude::*; # use pyo3::prelude::*;
# use pyo3::types::PyString; # use pyo3::types::PyString;
# fn main() -> PyResult<()> { # fn main() -> PyResult<()> {
# #[cfg(feature = "gil-refs")]
# {
#[allow(deprecated)] // py.eval() is part of the GIL Refs API #[allow(deprecated)] // py.eval() is part of the GIL Refs API
let hello: Py<PyString> = let hello: Py<PyString> =
Python::with_gil(|py| py.eval("\"Hello World!\"", None, None)?.extract())?; Python::with_gil(|py| py.eval("\"Hello World!\"", None, None)?.extract())?;
@ -252,6 +261,7 @@ Python::with_gil(|py| {
} }
drop(hello); // Memory released here. drop(hello); // Memory released here.
}); });
# }
# Ok(()) # Ok(())
# } # }
``` ```
@ -263,9 +273,12 @@ that rather than being released immediately, the memory will not be released
until the GIL is dropped. until the GIL is dropped.
```rust ```rust
# #![allow(unused_imports)]
# use pyo3::prelude::*; # use pyo3::prelude::*;
# use pyo3::types::PyString; # use pyo3::types::PyString;
# fn main() -> PyResult<()> { # fn main() -> PyResult<()> {
# #[cfg(feature = "gil-refs")]
# {
#[allow(deprecated)] // py.eval() is part of the GIL Refs API #[allow(deprecated)] // py.eval() is part of the GIL Refs API
let hello: Py<PyString> = let hello: Py<PyString> =
Python::with_gil(|py| py.eval("\"Hello World!\"", None, None)?.extract())?; Python::with_gil(|py| py.eval("\"Hello World!\"", None, None)?.extract())?;
@ -280,6 +293,7 @@ Python::with_gil(|py| {
// Do more stuff... // Do more stuff...
// Memory released here at end of `with_gil()` closure. // Memory released here at end of `with_gil()` closure.
}); });
# }
# Ok(()) # Ok(())
# } # }
``` ```

View File

@ -107,7 +107,7 @@ fn main() -> PyResult<()> {
<div class="warning"> <div class="warning">
During PyO3's [migration from "GIL Refs" to the `Bound<T>` smart pointer](../migration.md#migrating-from-the-gil-refs-api-to-boundt), [`Py<T>::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<T>` smart pointer](../migration.md#migrating-from-the-gil-refs-api-to-boundt), `Py<T>::call` is temporarily named [`Py<T>::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<T>` smart pointer. The methods on the `&PyAny` GIL Ref such as `call` have not been given replacements, and the methods on the `Bound<PyAny>` smart pointer such as [`Bound<PyAny>::call`]({{#PYO3_DOCS_URL}}/pyo3/types/trait.PyAnyMethods.html#tymethod.call) already use follow the newest API conventions.) (This temporary naming is only the case for the `Py<T>` smart pointer. The methods on the `&PyAny` GIL Ref such as `call` have not been given replacements, and the methods on the `Bound<PyAny>` smart pointer such as [`Bound<PyAny>::call`]({{#PYO3_DOCS_URL}}/pyo3/types/trait.PyAnyMethods.html#tymethod.call) already use follow the newest API conventions.)

View File

@ -353,8 +353,10 @@ let _: Py<PyList> = obj.extract()?;
For a `&PyAny` object reference `any` where the underlying object is a `#[pyclass]`: For a `&PyAny` object reference `any` where the underlying object is a `#[pyclass]`:
```rust ```rust
# #![allow(unused_imports)]
# use pyo3::prelude::*; # use pyo3::prelude::*;
# #[pyclass] #[derive(Clone)] struct MyClass { } # #[pyclass] #[derive(Clone)] struct MyClass { }
# #[cfg(feature = "gil-refs")]
# Python::with_gil(|py| -> PyResult<()> { # Python::with_gil(|py| -> PyResult<()> {
#[allow(deprecated)] // into_ref is part of the deprecated GIL Refs API #[allow(deprecated)] // into_ref is part of the deprecated GIL Refs API
let obj: &PyAny = Py::new(py, MyClass {})?.into_ref(py); let obj: &PyAny = Py::new(py, MyClass {})?.into_ref(py);

View File

@ -64,6 +64,7 @@ impl<'a> PyDowncastError<'a> {
/// Compatibility API to convert the Bound variant `DowncastError` into the /// Compatibility API to convert the Bound variant `DowncastError` into the
/// gil-ref variant /// gil-ref variant
#[cfg(feature = "gil-refs")]
pub(crate) fn from_downcast_err(DowncastError { from, to }: DowncastError<'a, 'a>) -> Self { pub(crate) fn from_downcast_err(DowncastError { from, to }: DowncastError<'a, 'a>) -> Self {
#[allow(deprecated)] #[allow(deprecated)]
let from = unsafe { from.py().from_borrowed_ptr(from.as_ptr()) }; let from = unsafe { from.py().from_borrowed_ptr(from.as_ptr()) };

View File

@ -1,4 +1,4 @@
use crate::err::{self, PyDowncastError, PyErr, PyResult}; use crate::err::{self, PyErr, PyResult};
use crate::impl_::pycell::PyClassObject; use crate::impl_::pycell::PyClassObject;
use crate::pycell::{PyBorrowError, PyBorrowMutError}; use crate::pycell::{PyBorrowError, PyBorrowMutError};
use crate::pyclass::boolean_struct::{False, True}; use crate::pyclass::boolean_struct::{False, True};
@ -721,12 +721,12 @@ impl<T> IntoPy<PyObject> for Borrowed<'_, '_, T> {
/// ///
/// This type does not auto-dereference to the inner object because you must prove you hold the GIL to access it. /// 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: /// 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`], /// - [`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`]. /// 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. /// 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 /// These require passing in the [`Python<'py>`](crate::Python) token but are otherwise similar to the corresponding
/// methods on [`PyAny`]. /// methods on [`PyAny`].
/// ///
@ -991,12 +991,10 @@ where
/// assert!(my_class_cell.try_borrow().is_ok()); /// assert!(my_class_cell.try_borrow().is_ok());
/// }); /// });
/// ``` /// ```
#[cfg_attr( #[cfg(feature = "gil-refs")]
not(feature = "gil-refs"), #[deprecated(
deprecated( since = "0.21.0",
since = "0.21.0", note = "use `obj.bind(py)` instead of `obj.as_ref(py)`"
note = "use `obj.bind(py)` instead of `obj.as_ref(py)`"
)
)] )]
pub fn as_ref<'py>(&'py self, _py: Python<'py>) -> &'py T::AsRefTarget { pub fn as_ref<'py>(&'py self, _py: Python<'py>) -> &'py T::AsRefTarget {
let any = self.as_ptr() as *const PyAny; let any = self.as_ptr() as *const PyAny;
@ -1046,12 +1044,10 @@ where
/// obj.into_ref(py) /// obj.into_ref(py)
/// } /// }
/// ``` /// ```
#[cfg_attr( #[cfg(feature = "gil-refs")]
not(feature = "gil-refs"), #[deprecated(
deprecated( since = "0.21.0",
since = "0.21.0", note = "use `obj.into_bound(py)` instead of `obj.into_ref(py)`"
note = "use `obj.into_bound(py)` instead of `obj.into_ref(py)`"
)
)] )]
pub fn into_ref(self, py: Python<'_>) -> &T::AsRefTarget { pub fn into_ref(self, py: Python<'_>) -> &T::AsRefTarget {
#[allow(deprecated)] #[allow(deprecated)]
@ -1464,12 +1460,10 @@ impl<T> Py<T> {
} }
/// Deprecated form of [`call_bound`][Py::call_bound]. /// Deprecated form of [`call_bound`][Py::call_bound].
#[cfg_attr( #[cfg(feature = "gil-refs")]
not(feature = "gil-refs"), #[deprecated(
deprecated( since = "0.21.0",
since = "0.21.0", note = "`call` will be replaced by `call_bound` in a future PyO3 version"
note = "`call` will be replaced by `call_bound` in a future PyO3 version"
)
)] )]
#[inline] #[inline]
pub fn call<A>(&self, py: Python<'_>, args: A, kwargs: Option<&PyDict>) -> PyResult<PyObject> pub fn call<A>(&self, py: Python<'_>, args: A, kwargs: Option<&PyDict>) -> PyResult<PyObject>
@ -1506,12 +1500,10 @@ impl<T> Py<T> {
} }
/// Deprecated form of [`call_method_bound`][Py::call_method_bound]. /// Deprecated form of [`call_method_bound`][Py::call_method_bound].
#[cfg_attr( #[cfg(feature = "gil-refs")]
not(feature = "gil-refs"), #[deprecated(
deprecated( since = "0.21.0",
since = "0.21.0", note = "`call_method` will be replaced by `call_method_bound` in a future PyO3 version"
note = "`call_method` will be replaced by `call_method_bound` in a future PyO3 version"
)
)] )]
#[inline] #[inline]
pub fn call_method<N, A>( pub fn call_method<N, A>(
@ -1779,6 +1771,7 @@ impl<T> std::convert::From<Bound<'_, T>> for Py<T> {
} }
// `&PyCell<T>` can be converted to `Py<T>` // `&PyCell<T>` can be converted to `Py<T>`
#[cfg(feature = "gil-refs")]
#[allow(deprecated)] #[allow(deprecated)]
impl<T> std::convert::From<&crate::PyCell<T>> for Py<T> impl<T> std::convert::From<&crate::PyCell<T>> for Py<T>
where where
@ -1844,10 +1837,7 @@ where
{ {
/// Extracts `Self` from the source `PyObject`. /// Extracts `Self` from the source `PyObject`.
fn extract_bound(ob: &Bound<'py, PyAny>) -> PyResult<Self> { fn extract_bound(ob: &Bound<'py, PyAny>) -> PyResult<Self> {
// TODO update MSRV past 1.59 and use .cloned() to make ob.downcast().cloned().map_err(Into::into)
// clippy happy
#[allow(clippy::map_clone)]
ob.downcast().map(Clone::clone).map_err(Into::into)
} }
} }
@ -1888,21 +1878,22 @@ pub type PyObject = Py<PyAny>;
impl PyObject { impl PyObject {
/// Deprecated form of [`PyObject::downcast_bound`] /// Deprecated form of [`PyObject::downcast_bound`]
#[cfg_attr( #[cfg(feature = "gil-refs")]
not(feature = "gil-refs"), #[deprecated(
deprecated( since = "0.21.0",
since = "0.21.0", note = "`PyObject::downcast` will be replaced by `PyObject::downcast_bound` in a future PyO3 version"
note = "`PyObject::downcast` will be replaced by `PyObject::downcast_bound` in a future PyO3 version"
)
)] )]
#[inline] #[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 where
T: PyTypeCheck<AsRefTarget = T>, T: PyTypeCheck<AsRefTarget = T>,
{ {
self.downcast_bound::<T>(py) self.downcast_bound::<T>(py)
.map(Bound::as_gil_ref) .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. /// Downcast this `PyObject` to a concrete Python type or pyclass.
/// ///
@ -1970,12 +1961,10 @@ impl PyObject {
/// # Safety /// # Safety
/// ///
/// Callers must ensure that the type is valid or risk type confusion. /// Callers must ensure that the type is valid or risk type confusion.
#[cfg_attr( #[cfg(feature = "gil-refs")]
not(feature = "gil-refs"), #[deprecated(
deprecated( since = "0.21.0",
since = "0.21.0", note = "`PyObject::downcast_unchecked` will be replaced by `PyObject::downcast_bound_unchecked` in a future PyO3 version"
note = "`PyObject::downcast_unchecked` will be replaced by `PyObject::downcast_bound_unchecked` in a future PyO3 version"
)
)] )]
#[inline] #[inline]
pub unsafe fn downcast_unchecked<'py, T>(&'py self, py: Python<'py>) -> &T pub unsafe fn downcast_unchecked<'py, T>(&'py self, py: Python<'py>) -> &T
@ -1997,35 +1986,31 @@ impl PyObject {
} }
#[cfg(test)] #[cfg(test)]
#[cfg_attr(not(feature = "gil-refs"), allow(deprecated))]
mod tests { mod tests {
use super::{Bound, Py, PyObject}; use super::{Bound, Py, PyObject};
use crate::types::any::PyAnyMethods; use crate::types::any::PyAnyMethods;
use crate::types::{dict::IntoPyDict, PyDict, PyString}; use crate::types::{dict::IntoPyDict, PyDict, PyString};
use crate::types::{PyCapsule, PyStringMethods}; use crate::types::{PyCapsule, PyStringMethods};
use crate::{ffi, Borrowed, PyAny, PyNativeType, PyResult, Python, ToPyObject}; use crate::{ffi, Borrowed, PyAny, PyResult, Python, ToPyObject};
#[test] #[test]
fn test_call() { fn test_call() {
Python::with_gil(|py| { Python::with_gil(|py| {
let obj = py.get_type::<PyDict>().to_object(py); let obj = py.get_type_bound::<PyDict>().to_object(py);
let assert_repr = |obj: &PyAny, expected: &str| { let assert_repr = |obj: &Bound<'_, PyAny>, expected: &str| {
assert_eq!(obj.repr().unwrap().to_str().unwrap(), expected); assert_eq!(obj.repr().unwrap().to_cow().unwrap(), expected);
}; };
assert_repr(obj.call0(py).unwrap().as_ref(py), "{}"); assert_repr(obj.call0(py).unwrap().bind(py), "{}");
assert_repr(obj.call1(py, ()).unwrap().as_ref(py), "{}"); assert_repr(obj.call1(py, ()).unwrap().bind(py), "{}");
assert_repr(obj.call(py, (), None).unwrap().as_ref(py), "{}"); assert_repr(obj.call_bound(py, (), None).unwrap().bind(py), "{}");
assert_repr( assert_repr(obj.call1(py, ((('x', 1),),)).unwrap().bind(py), "{'x': 1}");
obj.call1(py, ((('x', 1),),)).unwrap().as_ref(py),
"{'x': 1}",
);
assert_repr( assert_repr(
obj.call_bound(py, (), Some(&[('x', 1)].into_py_dict_bound(py))) obj.call_bound(py, (), Some(&[('x', 1)].into_py_dict_bound(py)))
.unwrap() .unwrap()
.as_ref(py), .bind(py),
"{'x': 1}", "{'x': 1}",
); );
}) })
@ -2037,7 +2022,7 @@ mod tests {
let obj: PyObject = PyDict::new_bound(py).into(); let obj: PyObject = PyDict::new_bound(py).into();
assert!(obj.call_method0(py, "asdf").is_err()); assert!(obj.call_method0(py, "asdf").is_err());
assert!(obj assert!(obj
.call_method(py, "nonexistent_method", (1,), None) .call_method_bound(py, "nonexistent_method", (1,), None)
.is_err()); .is_err());
assert!(obj.call_method0(py, "nonexistent_method").is_err()); assert!(obj.call_method0(py, "nonexistent_method").is_err());
assert!(obj.call_method1(py, "nonexistent_method", (1,)).is_err()); assert!(obj.call_method1(py, "nonexistent_method", (1,)).is_err());
@ -2083,7 +2068,7 @@ a = A()
assert!(instance assert!(instance
.getattr(py, "foo")? .getattr(py, "foo")?
.as_ref(py) .bind(py)
.eq(PyString::new_bound(py, "bar"))?); .eq(PyString::new_bound(py, "bar"))?);
instance.getattr(py, "foo")?; instance.getattr(py, "foo")?;
@ -2109,7 +2094,7 @@ a = A()
instance.getattr(py, foo).unwrap_err(); instance.getattr(py, foo).unwrap_err();
instance.setattr(py, foo, bar)?; 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(()) Ok(())
}) })
} }
@ -2117,7 +2102,7 @@ a = A()
#[test] #[test]
fn invalid_attr() -> PyResult<()> { fn invalid_attr() -> PyResult<()> {
Python::with_gil(|py| { Python::with_gil(|py| {
let instance: Py<PyAny> = py.eval("object()", None, None)?.into(); let instance: Py<PyAny> = py.eval_bound("object()", None, None)?.into();
instance.getattr(py, "foo").unwrap_err(); instance.getattr(py, "foo").unwrap_err();
@ -2130,7 +2115,7 @@ a = A()
#[test] #[test]
fn test_py2_from_py_object() { fn test_py2_from_py_object() {
Python::with_gil(|py| { 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 ptr = instance.as_ptr();
let instance: Bound<'_, PyAny> = instance.extract().unwrap(); let instance: Bound<'_, PyAny> = instance.extract().unwrap();
assert_eq!(instance.as_ptr(), ptr); assert_eq!(instance.as_ptr(), ptr);
@ -2141,7 +2126,7 @@ a = A()
fn test_py2_into_py_object() { fn test_py2_into_py_object() {
Python::with_gil(|py| { Python::with_gil(|py| {
let instance = py let instance = py
.eval("object()", None, None) .eval_bound("object()", None, None)
.unwrap() .unwrap()
.as_borrowed() .as_borrowed()
.to_owned(); .to_owned();

View File

@ -116,18 +116,17 @@
//! [`SendWrapper`]: https://docs.rs/send_wrapper/latest/send_wrapper/struct.SendWrapper.html //! [`SendWrapper`]: https://docs.rs/send_wrapper/latest/send_wrapper/struct.SendWrapper.html
//! [`Rc`]: std::rc::Rc //! [`Rc`]: std::rc::Rc
//! [`Py`]: crate::Py //! [`Py`]: crate::Py
use crate::err::{self, PyDowncastError, PyErr, PyResult}; use crate::err::{self, PyErr, PyResult};
use crate::ffi_ptr_ext::FfiPtrExt; use crate::ffi_ptr_ext::FfiPtrExt;
use crate::gil::{GILGuard, SuspendGIL}; use crate::gil::{GILGuard, SuspendGIL};
use crate::impl_::not_send::NotSend; use crate::impl_::not_send::NotSend;
use crate::py_result_ext::PyResultExt; use crate::py_result_ext::PyResultExt;
use crate::type_object::HasPyGilRef;
use crate::types::any::PyAnyMethods; use crate::types::any::PyAnyMethods;
use crate::types::{ use crate::types::{
PyAny, PyDict, PyEllipsis, PyModule, PyNone, PyNotImplemented, PyString, PyType, PyAny, PyDict, PyEllipsis, PyModule, PyNone, PyNotImplemented, PyString, PyType,
}; };
use crate::version::PythonVersionInfo; 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)] #[allow(deprecated)]
use crate::{gil::GILPool, FromPyPointer}; use crate::{gil::GILPool, FromPyPointer};
use std::ffi::{CStr, CString}; 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. /// Registers the object in the release pool, and tries to downcast to specific type.
#[cfg_attr( #[cfg(feature = "gil-refs")]
not(feature = "gil-refs"), #[deprecated(
deprecated( since = "0.21.0",
since = "0.21.0", note = "use `obj.downcast_bound::<T>(py)` instead of `py.checked_cast_as::<T>(obj)`"
note = "use `obj.downcast_bound::<T>(py)` instead of `py.checked_cast_as::<T>(obj)`"
)
)] )]
pub fn checked_cast_as<T>(self, obj: PyObject) -> Result<&'py T, PyDowncastError<'py>> pub fn checked_cast_as<T>(
self,
obj: PyObject,
) -> Result<&'py T, crate::err::PyDowncastError<'py>>
where where
T: PyTypeCheck<AsRefTarget = T>, T: crate::PyTypeCheck<AsRefTarget = T>,
{ {
#[allow(deprecated)] #[allow(deprecated)]
obj.into_ref(self).downcast() obj.into_ref(self).downcast()
@ -860,16 +860,14 @@ impl<'py> Python<'py> {
/// # Safety /// # Safety
/// ///
/// Callers must ensure that ensure that the cast is valid. /// Callers must ensure that ensure that the cast is valid.
#[cfg_attr( #[cfg(feature = "gil-refs")]
not(feature = "gil-refs"), #[deprecated(
deprecated( since = "0.21.0",
since = "0.21.0", note = "use `obj.downcast_bound_unchecked::<T>(py)` instead of `py.cast_as::<T>(obj)`"
note = "use `obj.downcast_bound_unchecked::<T>(py)` instead of `py.cast_as::<T>(obj)`"
)
)] )]
pub unsafe fn cast_as<T>(self, obj: PyObject) -> &'py T pub unsafe fn cast_as<T>(self, obj: PyObject) -> &'py T
where where
T: HasPyGilRef<AsRefTarget = T>, T: crate::type_object::HasPyGilRef<AsRefTarget = T>,
{ {
#[allow(deprecated)] #[allow(deprecated)]
obj.into_ref(self).downcast_unchecked() obj.into_ref(self).downcast_unchecked()

View File

@ -2705,17 +2705,16 @@ class SimpleClass:
} }
#[test] #[test]
#[allow(deprecated)]
fn test_is_ellipsis() { fn test_is_ellipsis() {
Python::with_gil(|py| { Python::with_gil(|py| {
let v = py let v = py
.eval("...", None, None) .eval_bound("...", None, None)
.map_err(|e| e.display(py)) .map_err(|e| e.display(py))
.unwrap(); .unwrap();
assert!(v.is_ellipsis()); 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()); assert!(!not_ellipsis.is_ellipsis());
}); });
} }

View File

@ -817,8 +817,6 @@ where
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
#[cfg(not(any(PyPy, GraalPy)))]
use crate::exceptions;
use crate::types::PyTuple; use crate::types::PyTuple;
use std::collections::{BTreeMap, HashMap}; use std::collections::{BTreeMap, HashMap};
@ -948,7 +946,7 @@ mod tests {
#[test] #[test]
#[allow(deprecated)] #[allow(deprecated)]
#[cfg(not(any(PyPy, GraalPy)))] #[cfg(all(not(any(PyPy, GraalPy)), feature = "gil-refs"))]
fn test_get_item_with_error() { fn test_get_item_with_error() {
Python::with_gil(|py| { Python::with_gil(|py| {
let mut v = HashMap::new(); let mut v = HashMap::new();
@ -967,7 +965,7 @@ mod tests {
assert!(dict assert!(dict
.get_item_with_error(dict) .get_item_with_error(dict)
.unwrap_err() .unwrap_err()
.is_instance_of::<exceptions::PyTypeError>(py)); .is_instance_of::<crate::exceptions::PyTypeError>(py));
}); });
} }