Merge pull request #3601 from davidhewitt/deprecate-pytryfrom

deprecate `PyTryFrom` and `PyTryInto`
This commit is contained in:
David Hewitt 2023-12-20 11:55:35 +00:00 committed by GitHub
commit a3c92fa319
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 75 additions and 37 deletions

View file

@ -16,6 +16,7 @@ To migrate, switch all type casts to use `obj.downcast()` instead of `try_from(o
Before: Before:
```rust ```rust
# #![allow(deprecated)]
# use pyo3::prelude::*; # use pyo3::prelude::*;
# use pyo3::types::{PyInt, PyList}; # use pyo3::types::{PyInt, PyList};
# fn main() -> PyResult<()> { # fn main() -> PyResult<()> {

View file

@ -0,0 +1 @@
Deprecate `PyTryFrom` and `PyTryInto` traits in favor of `any.downcast()` via the `PyTypeCheck` and `PyTypeInfo` traits.

View file

@ -355,11 +355,20 @@ where
/// If `T` implements `PyTryFrom`, we can convert `&PyAny` to `&T`. /// If `T` implements `PyTryFrom`, we can convert `&PyAny` to `&T`.
/// ///
/// This trait is similar to `std::convert::TryFrom` /// This trait is similar to `std::convert::TryFrom`
#[deprecated(since = "0.21.0")]
pub trait PyTryFrom<'v>: Sized + PyNativeType { pub trait PyTryFrom<'v>: Sized + PyNativeType {
/// Cast from a concrete Python object type to PyObject. /// Cast from a concrete Python object type to PyObject.
#[deprecated(
since = "0.21.0",
note = "use `value.downcast::<T>()` instead of `T::try_from(value)`"
)]
fn try_from<V: Into<&'v PyAny>>(value: V) -> Result<&'v Self, PyDowncastError<'v>>; fn try_from<V: Into<&'v PyAny>>(value: V) -> Result<&'v Self, PyDowncastError<'v>>;
/// Cast from a concrete Python object type to PyObject. With exact type check. /// Cast from a concrete Python object type to PyObject. With exact type check.
#[deprecated(
since = "0.21.0",
note = "use `value.downcast_exact::<T>()` instead of `T::try_from_exact(value)`"
)]
fn try_from_exact<V: Into<&'v PyAny>>(value: V) -> Result<&'v Self, PyDowncastError<'v>>; fn try_from_exact<V: Into<&'v PyAny>>(value: V) -> Result<&'v Self, PyDowncastError<'v>>;
/// Cast a PyAny to a specific type of PyObject. The caller must /// Cast a PyAny to a specific type of PyObject. The caller must
@ -368,19 +377,33 @@ pub trait PyTryFrom<'v>: Sized + PyNativeType {
/// # 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.
#[deprecated(
since = "0.21.0",
note = "use `value.downcast_unchecked::<T>()` instead of `T::try_from_unchecked(value)`"
)]
unsafe fn try_from_unchecked<V: Into<&'v PyAny>>(value: V) -> &'v Self; unsafe fn try_from_unchecked<V: Into<&'v PyAny>>(value: V) -> &'v Self;
} }
/// Trait implemented by Python object types that allow a checked downcast. /// Trait implemented by Python object types that allow a checked downcast.
/// This trait is similar to `std::convert::TryInto` /// This trait is similar to `std::convert::TryInto`
#[deprecated(since = "0.21.0")]
pub trait PyTryInto<T>: Sized { pub trait PyTryInto<T>: Sized {
/// Cast from PyObject to a concrete Python object type. /// Cast from PyObject to a concrete Python object type.
#[deprecated(
since = "0.21.0",
note = "use `value.downcast()` instead of `value.try_into()`"
)]
fn try_into(&self) -> Result<&T, PyDowncastError<'_>>; fn try_into(&self) -> Result<&T, PyDowncastError<'_>>;
/// Cast from PyObject to a concrete Python object type. With exact type check. /// Cast from PyObject to a concrete Python object type. With exact type check.
#[deprecated(
since = "0.21.0",
note = "use `value.downcast()` instead of `value.try_into_exact()`"
)]
fn try_into_exact(&self) -> Result<&T, PyDowncastError<'_>>; fn try_into_exact(&self) -> Result<&T, PyDowncastError<'_>>;
} }
#[allow(deprecated)]
mod implementations { mod implementations {
use super::*; use super::*;
@ -555,47 +578,50 @@ mod test_no_clone {}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::PyObject; use crate::{PyObject, Python};
use super::super::PyTryFrom; #[allow(deprecated)]
use crate::types::{IntoPyDict, PyAny, PyDict, PyList}; mod deprecated {
use crate::{Python, ToPyObject}; use super::super::PyTryFrom;
use crate::types::{IntoPyDict, PyAny, PyDict, PyList};
use crate::{Python, ToPyObject};
#[test] #[test]
fn test_try_from() { fn test_try_from() {
Python::with_gil(|py| { Python::with_gil(|py| {
let list: &PyAny = vec![3, 6, 5, 4, 7].to_object(py).into_ref(py); let list: &PyAny = vec![3, 6, 5, 4, 7].to_object(py).into_ref(py);
let dict: &PyAny = vec![("reverse", true)].into_py_dict(py).as_ref(); let dict: &PyAny = vec![("reverse", true)].into_py_dict(py).as_ref();
assert!(<PyList as PyTryFrom<'_>>::try_from(list).is_ok()); assert!(<PyList as PyTryFrom<'_>>::try_from(list).is_ok());
assert!(<PyDict as PyTryFrom<'_>>::try_from(dict).is_ok()); assert!(<PyDict as PyTryFrom<'_>>::try_from(dict).is_ok());
assert!(<PyAny as PyTryFrom<'_>>::try_from(list).is_ok()); assert!(<PyAny as PyTryFrom<'_>>::try_from(list).is_ok());
assert!(<PyAny as PyTryFrom<'_>>::try_from(dict).is_ok()); assert!(<PyAny as PyTryFrom<'_>>::try_from(dict).is_ok());
}); });
} }
#[test] #[test]
fn test_try_from_exact() { fn test_try_from_exact() {
Python::with_gil(|py| { Python::with_gil(|py| {
let list: &PyAny = vec![3, 6, 5, 4, 7].to_object(py).into_ref(py); let list: &PyAny = vec![3, 6, 5, 4, 7].to_object(py).into_ref(py);
let dict: &PyAny = vec![("reverse", true)].into_py_dict(py).as_ref(); let dict: &PyAny = vec![("reverse", true)].into_py_dict(py).as_ref();
assert!(PyList::try_from_exact(list).is_ok()); assert!(PyList::try_from_exact(list).is_ok());
assert!(PyDict::try_from_exact(dict).is_ok()); assert!(PyDict::try_from_exact(dict).is_ok());
assert!(PyAny::try_from_exact(list).is_err()); assert!(PyAny::try_from_exact(list).is_err());
assert!(PyAny::try_from_exact(dict).is_err()); assert!(PyAny::try_from_exact(dict).is_err());
}); });
} }
#[test] #[test]
fn test_try_from_unchecked() { fn test_try_from_unchecked() {
Python::with_gil(|py| { Python::with_gil(|py| {
let list = PyList::new(py, [1, 2, 3]); let list = PyList::new(py, [1, 2, 3]);
let val = unsafe { <PyList as PyTryFrom>::try_from_unchecked(list.as_ref()) }; let val = unsafe { <PyList as PyTryFrom>::try_from_unchecked(list.as_ref()) };
assert!(list.is(val)); assert!(list.is(val));
}); });
}
} }
#[test] #[test]

View file

@ -1614,7 +1614,7 @@ a = A()
#[cfg(feature = "macros")] #[cfg(feature = "macros")]
mod using_macros { mod using_macros {
use crate::{PyCell, PyTryInto}; use crate::PyCell;
use super::*; use super::*;
@ -1642,7 +1642,9 @@ a = A()
} }
#[test] #[test]
#[allow(deprecated)]
fn cell_tryfrom() { fn cell_tryfrom() {
use crate::PyTryInto;
// More detailed tests of the underlying semantics in pycell.rs // More detailed tests of the underlying semantics in pycell.rs
Python::with_gil(|py| { Python::with_gil(|py| {
let instance: &PyAny = Py::new(py, SomeClass(0)).unwrap().into_ref(py); let instance: &PyAny = Py::new(py, SomeClass(0)).unwrap().into_ref(py);

View file

@ -295,6 +295,7 @@
//! [`Ungil`]: crate::marker::Ungil //! [`Ungil`]: crate::marker::Ungil
pub use crate::class::*; pub use crate::class::*;
pub use crate::conversion::{AsPyPointer, FromPyObject, FromPyPointer, IntoPy, ToPyObject}; pub use crate::conversion::{AsPyPointer, FromPyObject, FromPyPointer, IntoPy, ToPyObject};
#[allow(deprecated)]
pub use crate::conversion::{PyTryFrom, PyTryInto}; pub use crate::conversion::{PyTryFrom, PyTryInto};
pub use crate::err::{PyDowncastError, PyErr, PyErrArguments, PyResult}; pub use crate::err::{PyDowncastError, PyErr, PyErrArguments, PyResult};
pub use crate::gil::GILPool; pub use crate::gil::GILPool;

View file

@ -9,6 +9,7 @@
//! ``` //! ```
pub use crate::conversion::{FromPyObject, IntoPy, ToPyObject}; pub use crate::conversion::{FromPyObject, IntoPy, ToPyObject};
#[allow(deprecated)]
pub use crate::conversion::{PyTryFrom, PyTryInto}; pub use crate::conversion::{PyTryFrom, PyTryInto};
pub use crate::err::{PyErr, PyResult}; pub use crate::err::{PyErr, PyResult};
pub use crate::instance::{Py, PyObject}; pub use crate::instance::{Py, PyObject};

View file

@ -23,7 +23,6 @@ pub trait PySizedLayout<T>: PyLayout<T> + Sized {}
/// ///
/// This is expected to be deprecated in the near future, see <https://github.com/PyO3/pyo3/issues/3382> /// This is expected to be deprecated in the near future, see <https://github.com/PyO3/pyo3/issues/3382>
/// ///
///
/// # Safety /// # Safety
/// ///
/// - `Py<Self>::as_ref` will hand out references to `Self::AsRefTarget`. /// - `Py<Self>::as_ref` will hand out references to `Self::AsRefTarget`.

View file

@ -79,6 +79,7 @@ impl PyTypeCheck for PyIterator {
} }
} }
#[allow(deprecated)]
impl<'v> crate::PyTryFrom<'v> for PyIterator { impl<'v> crate::PyTryFrom<'v> for PyIterator {
fn try_from<V: Into<&'v PyAny>>(value: V) -> Result<&'v PyIterator, PyDowncastError<'v>> { fn try_from<V: Into<&'v PyAny>>(value: V) -> Result<&'v PyIterator, PyDowncastError<'v>> {
let value = value.into(); let value = value.into();

View file

@ -135,6 +135,7 @@ impl PyTypeCheck for PyMapping {
} }
} }
#[allow(deprecated)]
impl<'v> crate::PyTryFrom<'v> for PyMapping { impl<'v> crate::PyTryFrom<'v> for PyMapping {
/// Downcasting to `PyMapping` requires the concrete class to be a subclass (or registered /// Downcasting to `PyMapping` requires the concrete class to be a subclass (or registered
/// subclass) of `collections.abc.Mapping` (from the Python standard library) - i.e. /// subclass) of `collections.abc.Mapping` (from the Python standard library) - i.e.
@ -168,7 +169,7 @@ mod tests {
use crate::{ use crate::{
exceptions::PyKeyError, exceptions::PyKeyError,
types::{PyDict, PyTuple}, types::{PyDict, PyTuple},
PyTryFrom, Python, Python,
}; };
use super::*; use super::*;
@ -318,7 +319,9 @@ mod tests {
} }
#[test] #[test]
#[allow(deprecated)]
fn test_mapping_try_from() { fn test_mapping_try_from() {
use crate::PyTryFrom;
Python::with_gil(|py| { Python::with_gil(|py| {
let dict = PyDict::new(py); let dict = PyDict::new(py);
let _ = <PyMapping as PyTryFrom>::try_from(dict).unwrap(); let _ = <PyMapping as PyTryFrom>::try_from(dict).unwrap();

View file

@ -549,6 +549,7 @@ impl PyTypeCheck for PySequence {
} }
} }
#[allow(deprecated)]
impl<'v> crate::PyTryFrom<'v> for PySequence { impl<'v> crate::PyTryFrom<'v> for PySequence {
/// Downcasting to `PySequence` requires the concrete class to be a subclass (or registered /// Downcasting to `PySequence` requires the concrete class to be a subclass (or registered
/// subclass) of `collections.abc.Sequence` (from the Python standard library) - i.e. /// subclass) of `collections.abc.Sequence` (from the Python standard library) - i.e.
@ -577,7 +578,7 @@ impl<'v> crate::PyTryFrom<'v> for PySequence {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::types::{PyList, PySequence, PyTuple}; use crate::types::{PyList, PySequence, PyTuple};
use crate::{PyObject, PyTryFrom, Python, ToPyObject}; use crate::{PyObject, Python, ToPyObject};
fn get_object() -> PyObject { fn get_object() -> PyObject {
// Convenience function for getting a single unique object // Convenience function for getting a single unique object
@ -1078,7 +1079,9 @@ mod tests {
} }
#[test] #[test]
#[allow(deprecated)]
fn test_seq_try_from() { fn test_seq_try_from() {
use crate::PyTryFrom;
Python::with_gil(|py| { Python::with_gil(|py| {
let list = PyList::empty(py); let list = PyList::empty(py);
let _ = <PySequence as PyTryFrom>::try_from(list).unwrap(); let _ = <PySequence as PyTryFrom>::try_from(list).unwrap();