From 3c65132da57f1282bdc38b868c2919ea97394fc5 Mon Sep 17 00:00:00 2001 From: David Hewitt Date: Wed, 10 Jul 2024 14:38:30 +0100 Subject: [PATCH] remove all functionality deprecated in PyO3 0.21 (#4323) * remove all functionality deprecated in PyO3 0.21 * further adjustments after removing deprecated APIs --- guide/src/migration.md | 3 +- newsfragments/4323.removed.md | 1 + src/conversion.rs | 168 +--------------------------------- src/instance.rs | 21 ----- src/lib.rs | 27 ------ src/marker.rs | 40 +------- src/prelude.rs | 3 - src/pyclass.rs | 110 +--------------------- src/types/any.rs | 8 -- src/types/iterator.rs | 39 +------- src/types/mapping.rs | 42 +-------- src/types/sequence.rs | 41 +-------- 12 files changed, 9 insertions(+), 494 deletions(-) create mode 100644 newsfragments/4323.removed.md diff --git a/guide/src/migration.md b/guide/src/migration.md index 8ac3ff16c47..626458b46d1 100644 --- a/guide/src/migration.md +++ b/guide/src/migration.md @@ -235,8 +235,7 @@ The `__next__` and `__anext__` magic methods can now return any type convertible Starting with an implementation of a Python iterator using `IterNextOutput`, e.g. -```rust -#![allow(deprecated)] +```rust,ignore use pyo3::prelude::*; use pyo3::iter::IterNextOutput; diff --git a/newsfragments/4323.removed.md b/newsfragments/4323.removed.md new file mode 100644 index 00000000000..c9d46f6a886 --- /dev/null +++ b/newsfragments/4323.removed.md @@ -0,0 +1 @@ +Remove all functionality deprecated in PyO3 0.21. diff --git a/src/conversion.rs b/src/conversion.rs index 6a089e186bc..451d0df4abf 100644 --- a/src/conversion.rs +++ b/src/conversion.rs @@ -8,10 +8,7 @@ use crate::types::PyTuple; use crate::{ffi, Borrowed, Bound, Py, PyAny, PyClass, PyObject, PyRef, PyRefMut, Python}; #[cfg(feature = "gil-refs")] use { - crate::{ - err::{self, PyDowncastError}, - gil, PyNativeType, - }, + crate::{err, gil, PyNativeType}, std::ptr::NonNull, }; @@ -395,121 +392,6 @@ where } } -/// Trait implemented by Python object types that allow a checked downcast. -/// If `T` implements `PyTryFrom`, we can convert `&PyAny` to `&T`. -/// -/// This trait is similar to `std::convert::TryFrom` -#[cfg(feature = "gil-refs")] -#[deprecated(since = "0.21.0")] -pub trait PyTryFrom<'v>: Sized + PyNativeType { - /// Cast from a concrete Python object type to PyObject. - #[deprecated( - since = "0.21.0", - note = "use `value.downcast::()` instead of `T::try_from(value)`" - )] - fn try_from>(value: V) -> Result<&'v Self, PyDowncastError<'v>>; - - /// Cast from a concrete Python object type to PyObject. With exact type check. - #[deprecated( - since = "0.21.0", - note = "use `value.downcast_exact::()` instead of `T::try_from_exact(value)`" - )] - fn try_from_exact>(value: V) -> Result<&'v Self, PyDowncastError<'v>>; - - /// Cast a PyAny to a specific type of PyObject. The caller must - /// have already verified the reference is for this type. - /// - /// # Safety - /// - /// Callers must ensure that the type is valid or risk type confusion. - #[deprecated( - since = "0.21.0", - note = "use `value.downcast_unchecked::()` instead of `T::try_from_unchecked(value)`" - )] - unsafe fn try_from_unchecked>(value: V) -> &'v Self; -} - -/// Trait implemented by Python object types that allow a checked downcast. -/// This trait is similar to `std::convert::TryInto` -#[cfg(feature = "gil-refs")] -#[deprecated(since = "0.21.0")] -pub trait PyTryInto: Sized { - /// 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<'_>>; - - /// 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<'_>>; -} - -#[cfg(feature = "gil-refs")] -#[allow(deprecated)] -mod implementations { - use super::*; - use crate::type_object::PyTypeInfo; - - // TryFrom implies TryInto - impl PyTryInto for PyAny - where - U: for<'v> PyTryFrom<'v>, - { - fn try_into(&self) -> Result<&U, PyDowncastError<'_>> { - >::try_from(self) - } - fn try_into_exact(&self) -> Result<&U, PyDowncastError<'_>> { - U::try_from_exact(self) - } - } - - impl<'v, T> PyTryFrom<'v> for T - where - T: PyTypeInfo + PyNativeType, - { - fn try_from>(value: V) -> Result<&'v Self, PyDowncastError<'v>> { - value.into().downcast() - } - - fn try_from_exact>(value: V) -> Result<&'v Self, PyDowncastError<'v>> { - value.into().downcast_exact() - } - - #[inline] - unsafe fn try_from_unchecked>(value: V) -> &'v Self { - value.into().downcast_unchecked() - } - } - - impl<'v, T> PyTryFrom<'v> for crate::PyCell - where - T: 'v + PyClass, - { - fn try_from>(value: V) -> Result<&'v Self, PyDowncastError<'v>> { - value.into().downcast() - } - fn try_from_exact>(value: V) -> Result<&'v Self, PyDowncastError<'v>> { - let value = value.into(); - unsafe { - if T::is_exact_type_of(value) { - Ok(Self::try_from_unchecked(value)) - } else { - Err(PyDowncastError::new(value, T::NAME)) - } - } - } - #[inline] - unsafe fn try_from_unchecked>(value: V) -> &'v Self { - value.into().downcast_unchecked() - } - } -} - /// Converts `()` to an empty Python tuple. impl IntoPy> for () { fn into_py(self, py: Python<'_>) -> Py { @@ -665,51 +547,3 @@ where /// }) /// ``` mod test_no_clone {} - -#[cfg(test)] -mod tests { - #[cfg(feature = "gil-refs")] - #[allow(deprecated)] - mod deprecated { - use super::super::PyTryFrom; - use crate::types::{IntoPyDict, PyAny, PyDict, PyList}; - use crate::{Python, ToPyObject}; - - #[test] - fn test_try_from() { - Python::with_gil(|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(); - - assert!(>::try_from(list).is_ok()); - assert!(>::try_from(dict).is_ok()); - - assert!(>::try_from(list).is_ok()); - assert!(>::try_from(dict).is_ok()); - }); - } - - #[test] - fn test_try_from_exact() { - Python::with_gil(|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(); - - assert!(PyList::try_from_exact(list).is_ok()); - assert!(PyDict::try_from_exact(dict).is_ok()); - - assert!(PyAny::try_from_exact(list).is_err()); - assert!(PyAny::try_from_exact(dict).is_err()); - }); - } - - #[test] - fn test_try_from_unchecked() { - Python::with_gil(|py| { - let list = PyList::new(py, [1, 2, 3]); - let val = unsafe { ::try_from_unchecked(list.as_ref()) }; - assert!(list.is(val)); - }); - } - } -} diff --git a/src/instance.rs b/src/instance.rs index fad0c55bc3d..d80072afa98 100644 --- a/src/instance.rs +++ b/src/instance.rs @@ -1385,14 +1385,6 @@ impl Py { unsafe { ffi::Py_None() == self.as_ptr() } } - /// Returns whether the object is considered to be true. - /// - /// This is equivalent to the Python expression `bool(self)`. - #[deprecated(since = "0.21.0", note = "use `.is_truthy()` instead")] - pub fn is_true(&self, py: Python<'_>) -> PyResult { - self.is_truthy(py) - } - /// Returns whether the object is considered to be true. /// /// This applies truth value testing equivalent to the Python expression `bool(self)`. @@ -2365,18 +2357,5 @@ a = A() } }) } - - #[test] - #[cfg(feature = "gil-refs")] - #[allow(deprecated)] - fn cell_tryfrom() { - use crate::{PyCell, PyTryInto}; - // More detailed tests of the underlying semantics in pycell.rs - Python::with_gil(|py| { - let instance: &PyAny = Py::new(py, SomeClass(0)).unwrap().into_ref(py); - let _: &PyCell = PyTryInto::try_into(instance).unwrap(); - let _: &PyCell = PyTryInto::try_into_exact(instance).unwrap(); - }) - } } } diff --git a/src/lib.rs b/src/lib.rs index 0ff48dbb460..5792a63e9b5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -318,9 +318,6 @@ pub use crate::class::*; pub use crate::conversion::{AsPyPointer, FromPyObject, IntoPy, ToPyObject}; #[cfg(feature = "gil-refs")] -#[allow(deprecated)] -pub use crate::conversion::{FromPyPointer, PyTryFrom, PyTryInto}; -#[cfg(feature = "gil-refs")] pub use crate::err::PyDowncastError; pub use crate::err::{DowncastError, DowncastIntoError, PyErr, PyErrArguments, PyResult, ToPyErr}; #[cfg(feature = "gil-refs")] @@ -382,30 +379,6 @@ pub mod class { pub use crate::pyclass::CompareOp; } - /// Old module which contained some implementation details of the `#[pyproto]` module. - /// - /// Prefer using the same content from `pyo3::pyclass`, e.g. `use pyo3::pyclass::IterANextOutput` instead - /// of `use pyo3::class::pyasync::IterANextOutput`. - /// - /// For compatibility reasons this has not yet been removed, however will be done so - /// once is resolved. - pub mod pyasync { - #[allow(deprecated)] - pub use crate::pyclass::{IterANextOutput, PyIterANextOutput}; - } - - /// Old module which contained some implementation details of the `#[pyproto]` module. - /// - /// Prefer using the same content from `pyo3::pyclass`, e.g. `use pyo3::pyclass::IterNextOutput` instead - /// of `use pyo3::class::pyasync::IterNextOutput`. - /// - /// For compatibility reasons this has not yet been removed, however will be done so - /// once is resolved. - pub mod iter { - #[allow(deprecated)] - pub use crate::pyclass::{IterNextOutput, PyIterNextOutput}; - } - /// Old module which contained some implementation details of the `#[pyproto]` module. /// /// Prefer using the same content from `pyo3::pyclass`, e.g. `use pyo3::pyclass::PyTraverseError` instead diff --git a/src/marker.rs b/src/marker.rs index 065adc7dda9..689f58db311 100644 --- a/src/marker.rs +++ b/src/marker.rs @@ -126,10 +126,10 @@ use crate::types::{ PyAny, PyDict, PyEllipsis, PyModule, PyNone, PyNotImplemented, PyString, PyType, }; use crate::version::PythonVersionInfo; -use crate::{ffi, Bound, IntoPy, Py, PyObject, PyTypeInfo}; #[allow(deprecated)] #[cfg(feature = "gil-refs")] -use crate::{gil::GILPool, FromPyPointer, PyNativeType}; +use crate::{conversion::FromPyPointer, gil::GILPool, PyNativeType}; +use crate::{ffi, Bound, IntoPy, Py, PyObject, PyTypeInfo}; use std::ffi::{CStr, CString}; use std::marker::PhantomData; use std::os::raw::c_int; @@ -801,42 +801,6 @@ impl<'py> Python<'py> { PythonVersionInfo::from_str(version_number_str).unwrap() } - /// Registers the object in the release pool, and tries to downcast to specific type. - #[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, crate::err::PyDowncastError<'py>> - where - T: crate::PyTypeCheck, - { - #[allow(deprecated)] - obj.into_ref(self).downcast() - } - - /// Registers the object in the release pool, and does an unchecked downcast - /// to the specific type. - /// - /// # Safety - /// - /// Callers must ensure that ensure that the cast is valid. - #[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: crate::type_object::HasPyGilRef, - { - #[allow(deprecated)] - obj.into_ref(self).downcast_unchecked() - } - /// Registers the object pointer in the release pool, /// and does an unchecked downcast to the specific type. /// diff --git a/src/prelude.rs b/src/prelude.rs index 6a0657c8a98..3f45cb52cf0 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -9,9 +9,6 @@ //! ``` pub use crate::conversion::{FromPyObject, IntoPy, ToPyObject}; -#[cfg(feature = "gil-refs")] -#[allow(deprecated)] -pub use crate::conversion::{PyTryFrom, PyTryInto}; pub use crate::err::{PyErr, PyResult}; pub use crate::instance::{Borrowed, Bound, Py, PyObject}; pub use crate::marker::Python; diff --git a/src/pyclass.rs b/src/pyclass.rs index 29cd1251974..91510e11151 100644 --- a/src/pyclass.rs +++ b/src/pyclass.rs @@ -1,8 +1,5 @@ //! `PyClass` and related traits. -use crate::{ - callback::IntoPyCallbackOutput, ffi, impl_::pyclass::PyClassImpl, IntoPy, PyObject, PyResult, - PyTypeInfo, Python, -}; +use crate::{ffi, impl_::pyclass::PyClassImpl, PyTypeInfo}; use std::{cmp::Ordering, os::raw::c_int}; mod create_type_object; @@ -99,111 +96,6 @@ impl CompareOp { } } -/// Output of `__next__` which can either `yield` the next value in the iteration, or -/// `return` a value to raise `StopIteration` in Python. -/// -/// Usage example: -/// -/// ```rust -/// # #![allow(deprecated)] -/// use pyo3::prelude::*; -/// use pyo3::iter::IterNextOutput; -/// -/// #[pyclass] -/// struct PyClassIter { -/// count: usize, -/// } -/// -/// #[pymethods] -/// impl PyClassIter { -/// #[new] -/// pub fn new() -> Self { -/// PyClassIter { count: 0 } -/// } -/// -/// fn __next__(&mut self) -> IterNextOutput { -/// if self.count < 5 { -/// self.count += 1; -/// // Given an instance `counter`, First five `next(counter)` calls yield 1, 2, 3, 4, 5. -/// IterNextOutput::Yield(self.count) -/// } else { -/// // At the sixth time, we get a `StopIteration` with `'Ended'`. -/// // try: -/// // next(counter) -/// // except StopIteration as e: -/// // assert e.value == 'Ended' -/// IterNextOutput::Return("Ended") -/// } -/// } -/// } -/// ``` -#[deprecated(since = "0.21.0", note = "Use `Option` or `PyStopIteration` instead.")] -pub enum IterNextOutput { - /// The value yielded by the iterator. - Yield(T), - /// The `StopIteration` object. - Return(U), -} - -/// Alias of `IterNextOutput` with `PyObject` yield & return values. -#[deprecated(since = "0.21.0", note = "Use `Option` or `PyStopIteration` instead.")] -#[allow(deprecated)] -pub type PyIterNextOutput = IterNextOutput; - -#[allow(deprecated)] -impl IntoPyCallbackOutput<*mut ffi::PyObject> for IterNextOutput -where - T: IntoPy, - U: IntoPy, -{ - fn convert(self, py: Python<'_>) -> PyResult<*mut ffi::PyObject> { - match self { - IterNextOutput::Yield(o) => Ok(o.into_py(py).into_ptr()), - IterNextOutput::Return(o) => { - Err(crate::exceptions::PyStopIteration::new_err(o.into_py(py))) - } - } - } -} - -/// Output of `__anext__`. -/// -/// -#[deprecated( - since = "0.21.0", - note = "Use `Option` or `PyStopAsyncIteration` instead." -)] -pub enum IterANextOutput { - /// An expression which the generator yielded. - Yield(T), - /// A `StopAsyncIteration` object. - Return(U), -} - -/// An [IterANextOutput] of Python objects. -#[deprecated( - since = "0.21.0", - note = "Use `Option` or `PyStopAsyncIteration` instead." -)] -#[allow(deprecated)] -pub type PyIterANextOutput = IterANextOutput; - -#[allow(deprecated)] -impl IntoPyCallbackOutput<*mut ffi::PyObject> for IterANextOutput -where - T: IntoPy, - U: IntoPy, -{ - fn convert(self, py: Python<'_>) -> PyResult<*mut ffi::PyObject> { - match self { - IterANextOutput::Yield(o) => Ok(o.into_py(py).into_ptr()), - IterANextOutput::Return(o) => Err(crate::exceptions::PyStopAsyncIteration::new_err( - o.into_py(py), - )), - } - } -} - /// A workaround for [associated const equality](https://github.com/rust-lang/rust/issues/92827). /// /// This serves to have True / False values in the [`PyClass`] trait's `Frozen` type. diff --git a/src/types/any.rs b/src/types/any.rs index c991b69b4a4..0b45dab2c92 100644 --- a/src/types/any.rs +++ b/src/types/any.rs @@ -581,14 +581,6 @@ impl PyAny { .map(Bound::into_gil_ref) } - /// Returns whether the object is considered to be true. - /// - /// This is equivalent to the Python expression `bool(self)`. - #[deprecated(since = "0.21.0", note = "use `.is_truthy()` instead")] - pub fn is_true(&self) -> PyResult { - self.is_truthy() - } - /// Returns whether the object is considered to be true. /// /// This applies truth value testing equivalent to the Python expression `bool(self)`. diff --git a/src/types/iterator.rs b/src/types/iterator.rs index 38f3131be90..1ae9f9f471a 100644 --- a/src/types/iterator.rs +++ b/src/types/iterator.rs @@ -3,7 +3,7 @@ use crate::instance::Borrowed; use crate::py_result_ext::PyResultExt; use crate::{ffi, Bound, PyAny, PyErr, PyResult, PyTypeCheck}; #[cfg(feature = "gil-refs")] -use crate::{AsPyPointer, PyDowncastError, PyNativeType}; +use crate::{AsPyPointer, PyNativeType}; /// A Python iterator object. /// @@ -130,31 +130,6 @@ impl PyTypeCheck for PyIterator { } } -#[cfg(feature = "gil-refs")] -#[allow(deprecated)] -impl<'v> crate::PyTryFrom<'v> for PyIterator { - fn try_from>(value: V) -> Result<&'v PyIterator, PyDowncastError<'v>> { - let value = value.into(); - unsafe { - if ffi::PyIter_Check(value.as_ptr()) != 0 { - Ok(value.downcast_unchecked()) - } else { - Err(PyDowncastError::new(value, "Iterator")) - } - } - } - - fn try_from_exact>(value: V) -> Result<&'v PyIterator, PyDowncastError<'v>> { - value.into().downcast() - } - - #[inline] - unsafe fn try_from_unchecked>(value: V) -> &'v PyIterator { - let ptr = value.into() as *const _ as *const PyIterator; - &*ptr - } -} - #[cfg(test)] mod tests { use super::PyIterator; @@ -298,18 +273,6 @@ def fibonacci(target): }); } - #[test] - #[cfg(feature = "gil-refs")] - #[allow(deprecated)] - fn iterator_try_from() { - Python::with_gil(|py| { - let obj: crate::Py = - vec![10, 20].to_object(py).as_ref(py).iter().unwrap().into(); - let iter = ::try_from(obj.as_ref(py)).unwrap(); - assert!(obj.is(iter)); - }); - } - #[test] #[cfg(feature = "macros")] fn python_class_not_iterator() { diff --git a/src/types/mapping.rs b/src/types/mapping.rs index 82e6b326810..9ff0ad85762 100644 --- a/src/types/mapping.rs +++ b/src/types/mapping.rs @@ -7,7 +7,7 @@ use crate::type_object::PyTypeInfo; use crate::types::any::PyAnyMethods; use crate::types::{PyAny, PyDict, PySequence, PyType}; #[cfg(feature = "gil-refs")] -use crate::{err::PyDowncastError, PyNativeType}; +use crate::PyNativeType; use crate::{ffi, Py, PyTypeCheck, Python, ToPyObject}; /// Represents a reference to a Python object supporting the mapping protocol. @@ -266,34 +266,6 @@ impl PyTypeCheck for PyMapping { } } -#[cfg(feature = "gil-refs")] -#[allow(deprecated)] -impl<'v> crate::PyTryFrom<'v> for PyMapping { - /// 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. - /// `isinstance(, collections.abc.Mapping) == True`. - fn try_from>(value: V) -> Result<&'v PyMapping, PyDowncastError<'v>> { - let value = value.into(); - - if PyMapping::type_check(&value.as_borrowed()) { - unsafe { return Ok(value.downcast_unchecked()) } - } - - Err(PyDowncastError::new(value, "Mapping")) - } - - #[inline] - fn try_from_exact>(value: V) -> Result<&'v PyMapping, PyDowncastError<'v>> { - value.into().downcast() - } - - #[inline] - unsafe fn try_from_unchecked>(value: V) -> &'v PyMapping { - let ptr = value.into() as *const _ as *const PyMapping; - &*ptr - } -} - #[cfg(test)] mod tests { use std::collections::HashMap; @@ -445,16 +417,4 @@ mod tests { assert_eq!(32 + 42 + 123, values_sum); }); } - - #[test] - #[cfg(feature = "gil-refs")] - #[allow(deprecated)] - fn test_mapping_try_from() { - use crate::PyTryFrom; - Python::with_gil(|py| { - let dict = PyDict::new(py); - let _ = ::try_from(dict).unwrap(); - let _ = PyMapping::try_from_exact(dict).unwrap(); - }); - } } diff --git a/src/types/sequence.rs b/src/types/sequence.rs index 39de9efb272..faf371160dd 100644 --- a/src/types/sequence.rs +++ b/src/types/sequence.rs @@ -10,7 +10,7 @@ use crate::sync::GILOnceCell; use crate::type_object::PyTypeInfo; use crate::types::{any::PyAnyMethods, PyAny, PyList, PyString, PyTuple, PyType}; #[cfg(feature = "gil-refs")] -use crate::{err::PyDowncastError, PyNativeType}; +use crate::PyNativeType; use crate::{ffi, FromPyObject, Py, PyTypeCheck, Python, ToPyObject}; /// Represents a reference to a Python object supporting the sequence protocol. @@ -553,33 +553,6 @@ impl PyTypeCheck for PySequence { } } -#[cfg(feature = "gil-refs")] -#[allow(deprecated)] -impl<'v> crate::PyTryFrom<'v> for PySequence { - /// 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. - /// `isinstance(, collections.abc.Sequence) == True`. - fn try_from>(value: V) -> Result<&'v PySequence, PyDowncastError<'v>> { - let value = value.into(); - - if PySequence::type_check(&value.as_borrowed()) { - unsafe { return Ok(value.downcast_unchecked::()) } - } - - Err(PyDowncastError::new(value, "Sequence")) - } - - fn try_from_exact>(value: V) -> Result<&'v PySequence, PyDowncastError<'v>> { - value.into().downcast() - } - - #[inline] - unsafe fn try_from_unchecked>(value: V) -> &'v PySequence { - let ptr = value.into() as *const _ as *const PySequence; - &*ptr - } -} - #[cfg(test)] mod tests { use crate::types::{PyAnyMethods, PyList, PySequence, PySequenceMethods, PyTuple}; @@ -1107,16 +1080,4 @@ mod tests { assert!(seq_from.to_list().is_ok()); }); } - - #[test] - #[cfg(feature = "gil-refs")] - #[allow(deprecated)] - fn test_seq_try_from() { - use crate::PyTryFrom; - Python::with_gil(|py| { - let list = PyList::empty(py); - let _ = ::try_from(list).unwrap(); - let _ = PySequence::try_from_exact(list).unwrap(); - }); - } }