diff --git a/src/err/mod.rs b/src/err/mod.rs index 12827d7d..31385f4c 100644 --- a/src/err/mod.rs +++ b/src/err/mod.rs @@ -97,6 +97,14 @@ impl<'py> DowncastIntoError<'py> { to: to.into(), } } + + /// Consumes this `DowncastIntoError` and returns the original object, allowing continued + /// use of it after a failed conversion. + /// + /// See [`downcast_into`][PyAnyMethods::downcast_into] for an example. + pub fn into_inner(self) -> Bound<'py, PyAny> { + self.from + } } impl PyErr { diff --git a/src/types/any.rs b/src/types/any.rs index 73582bbc..90c7f216 100644 --- a/src/types/any.rs +++ b/src/types/any.rs @@ -1561,6 +1561,27 @@ pub trait PyAnyMethods<'py> { T: PyTypeCheck; /// Like `downcast` but takes ownership of `self`. + /// + /// In case of an error, it is possible to retrieve `self` again via [`DowncastIntoError::into_inner`]. + /// + /// # Example + /// + /// ```rust + /// use pyo3::prelude::*; + /// use pyo3::types::{PyDict, PyList}; + /// + /// Python::with_gil(|py| { + /// let obj: Bound<'_, PyAny> = PyDict::new_bound(py).into_any(); + /// + /// let obj: Bound<'_, PyAny> = match obj.downcast_into::() { + /// Ok(_) => panic!("obj should not be a list"), + /// Err(err) => err.into_inner(), + /// }; + /// + /// // obj is a dictionary + /// assert!(obj.downcast_into::().is_ok()); + /// }) + /// ``` fn downcast_into(self) -> Result, DowncastIntoError<'py>> where T: PyTypeCheck;