diff --git a/newsfragments/5472.changed.md b/newsfragments/5472.changed.md new file mode 100644 index 00000000000..4634c5afea2 --- /dev/null +++ b/newsfragments/5472.changed.md @@ -0,0 +1 @@ +Deprecate `PyAnyMethods::downcast` functions in favour of `Bound::cast` functions diff --git a/src/conversions/std/vec.rs b/src/conversions/std/vec.rs index abe752dc5a7..74c796732ea 100644 --- a/src/conversions/std/vec.rs +++ b/src/conversions/std/vec.rs @@ -89,7 +89,7 @@ where // to support this function and if not, we will only fail extraction safely. let seq = unsafe { if ffi::PySequence_Check(obj.as_ptr()) != 0 { - obj.downcast_unchecked::() + obj.cast_unchecked::() } else { return Err(DowncastError::new_from_type( obj, diff --git a/src/err/mod.rs b/src/err/mod.rs index 6575263aeeb..a560d651f66 100644 --- a/src/err/mod.rs +++ b/src/err/mod.rs @@ -857,12 +857,12 @@ impl std::fmt::Display for TypeNameOrValue<'_> { match self { Self::Name(name) => name.fmt(f), Self::Value(t) => { - if let Ok(t) = t.downcast::() { + if let Ok(t) = t.cast::() { t.qualname() .map_err(|_| std::fmt::Error)? .to_string_lossy() .fmt(f) - } else if let Ok(t) = t.downcast::() { + } else if let Ok(t) = t.cast::() { for (i, t) in t.iter().enumerate() { if i > 0 { f.write_str(" | ")?; diff --git a/src/impl_/extract_argument.rs b/src/impl_/extract_argument.rs index 424b3ef998f..39023d021a2 100644 --- a/src/impl_/extract_argument.rs +++ b/src/impl_/extract_argument.rs @@ -188,7 +188,7 @@ pub fn extract_pyclass_ref<'a, 'holder, T: PyClass>( obj: &'a Bound<'_, PyAny>, holder: &'holder mut Option>, ) -> PyResult<&'holder T> { - Ok(&*holder.insert(PyClassGuard::try_borrow(obj.downcast()?.as_unbound())?)) + Ok(&*holder.insert(PyClassGuard::try_borrow(obj.cast()?.as_unbound())?)) } #[inline] @@ -196,9 +196,7 @@ pub fn extract_pyclass_ref_mut<'a, 'holder, T: PyClass>( obj: &'a Bound<'_, PyAny>, holder: &'holder mut Option>, ) -> PyResult<&'holder mut T> { - Ok(&mut *holder.insert(PyClassGuardMut::try_borrow_mut( - obj.downcast()?.as_unbound(), - )?)) + Ok(&mut *holder.insert(PyClassGuardMut::try_borrow_mut(obj.cast()?.as_unbound())?)) } /// The standard implementation of how PyO3 extracts a `#[pyfunction]` or `#[pymethod]` function argument. diff --git a/src/instance.rs b/src/instance.rs index f25b44fe0df..cf27b1064b0 100644 --- a/src/instance.rs +++ b/src/instance.rs @@ -2244,7 +2244,7 @@ impl Py { /// }) /// # } /// ``` - // FIXME(icxolu) deprecate in favor of `Py::cast_bound` + #[deprecated(since = "0.27.0", note = "use `Py::cast_bound` instead")] #[inline] pub fn downcast_bound<'py, T>( &self, @@ -2253,7 +2253,8 @@ impl Py { where T: PyTypeCheck, { - self.cast_bound(py) + #[allow(deprecated)] + self.bind(py).downcast() } /// Casts the `Py` to a concrete Python object type without checking validity. @@ -2261,10 +2262,13 @@ impl Py { /// # Safety /// /// Callers must ensure that the type is valid or risk type confusion. - // FIXME(icxolu) deprecate in favor of `Py::cast_bound_unchecked` + #[deprecated(since = "0.27.0", note = "use `Py::cast_bound_unchecked` instead")] #[inline] pub unsafe fn downcast_bound_unchecked<'py, T>(&self, py: Python<'py>) -> &Bound<'py, T> { - unsafe { self.cast_bound_unchecked(py) } + #[allow(deprecated)] + unsafe { + self.bind(py).downcast_unchecked() + } } } diff --git a/src/sync/once_lock.rs b/src/sync/once_lock.rs index fd608215049..5612b556e38 100644 --- a/src/sync/once_lock.rs +++ b/src/sync/once_lock.rs @@ -162,10 +162,7 @@ where attr_name: &str, ) -> PyResult<&Bound<'py, T>> { self.get_or_try_init(py, || { - let type_object = py - .import(module_name)? - .getattr(attr_name)? - .downcast_into()?; + let type_object = py.import(module_name)?.getattr(attr_name)?.cast_into()?; Ok(type_object.unbind()) }) .map(|ty| ty.bind(py)) diff --git a/src/types/any.rs b/src/types/any.rs index 4970340a8e5..a20f0bebb99 100644 --- a/src/types/any.rs +++ b/src/types/any.rs @@ -772,7 +772,7 @@ pub trait PyAnyMethods<'py>: crate::sealed::Sealed { /// }) /// # } /// ``` - // FIXME(icxolu) deprecate in favor of `Bound::cast` + #[deprecated(since = "0.27.0", note = "use `Bound::cast` instead")] fn downcast(&self) -> Result<&Bound<'py, T>, DowncastError<'_, 'py>> where T: PyTypeCheck; @@ -800,7 +800,7 @@ pub trait PyAnyMethods<'py>: crate::sealed::Sealed { /// assert!(obj.downcast_into::().is_ok()); /// }) /// ``` - // FIXME(icxolu) deprecate in favor of `Bound::cast_into` + #[deprecated(since = "0.27.0", note = "use `Bound::cast_into` instead")] fn downcast_into(self) -> Result, DowncastIntoError<'py>> where T: PyTypeCheck; @@ -836,13 +836,13 @@ pub trait PyAnyMethods<'py>: crate::sealed::Sealed { /// assert!(any.downcast_exact::().is_ok()); /// }); /// ``` - // FIXME(icxolu) deprecate in favor of `Bound::cast_exact` + #[deprecated(since = "0.27.0", note = "use `Bound::cast_exact` instead")] fn downcast_exact(&self) -> Result<&Bound<'py, T>, DowncastError<'_, 'py>> where T: PyTypeInfo; /// Like `downcast_exact` but takes ownership of `self`. - // FIXME(icxolu) deprecate in favor of `Bound::cast_into_exact` + #[deprecated(since = "0.27.0", note = "use `Bound::cast_into_exact` instead")] fn downcast_into_exact(self) -> Result, DowncastIntoError<'py>> where T: PyTypeInfo; @@ -852,7 +852,7 @@ pub trait PyAnyMethods<'py>: crate::sealed::Sealed { /// # Safety /// /// Callers must ensure that the type is valid or risk type confusion. - // FIXME(icxolu) deprecate in favor of `Bound::cast_unchecked` + #[deprecated(since = "0.27.0", note = "use `Bound::cast_unchecked` instead")] unsafe fn downcast_unchecked(&self) -> &Bound<'py, T>; /// Like `downcast_unchecked` but takes ownership of `self`. @@ -860,7 +860,7 @@ pub trait PyAnyMethods<'py>: crate::sealed::Sealed { /// # Safety /// /// Callers must ensure that the type is valid or risk type confusion. - // FIXME(icxolu) deprecate in favor of `Bound::cast_into_unchecked` + #[deprecated(since = "0.27.0", note = "use `Bound::cast_into_unchecked` instead")] unsafe fn downcast_into_unchecked(self) -> Bound<'py, T>; /// Extracts some type from the Python object. @@ -1449,7 +1449,13 @@ impl<'py> PyAnyMethods<'py> for Bound<'py, PyAny> { where T: PyTypeCheck, { - self.cast() + if T::type_check(self) { + // Safety: type_check is responsible for ensuring that the type is correct + Ok(unsafe { self.cast_unchecked() }) + } else { + #[allow(deprecated)] + Err(DowncastError::new(self, T::NAME)) + } } #[inline] @@ -1457,7 +1463,13 @@ impl<'py> PyAnyMethods<'py> for Bound<'py, PyAny> { where T: PyTypeCheck, { - self.cast_into() + if T::type_check(&self) { + // Safety: type_check is responsible for ensuring that the type is correct + Ok(unsafe { self.cast_into_unchecked() }) + } else { + #[allow(deprecated)] + Err(DowncastIntoError::new(self, T::NAME)) + } } #[inline] @@ -1465,7 +1477,13 @@ impl<'py> PyAnyMethods<'py> for Bound<'py, PyAny> { where T: PyTypeInfo, { - self.cast_exact() + if T::is_exact_type_of(self) { + // Safety: is_exact_type_of is responsible for ensuring that the type is correct + Ok(unsafe { self.cast_unchecked() }) + } else { + #[allow(deprecated)] + Err(DowncastError::new(self, T::NAME)) + } } #[inline] @@ -1473,7 +1491,13 @@ impl<'py> PyAnyMethods<'py> for Bound<'py, PyAny> { where T: PyTypeInfo, { - self.cast_into_exact() + if T::is_exact_type_of(&self) { + // Safety: is_exact_type_of is responsible for ensuring that the type is correct + Ok(unsafe { self.cast_into_unchecked() }) + } else { + #[allow(deprecated)] + Err(DowncastIntoError::new(self, T::NAME)) + } } #[inline]