From 34881fc9529d72d68791ad5007ac407c2ee70568 Mon Sep 17 00:00:00 2001 From: David Hewitt <1939362+davidhewitt@users.noreply.github.com> Date: Fri, 28 Jul 2023 15:11:56 +0100 Subject: [PATCH] add PyAny::downcast_exact --- newsfragments/3346.added.md | 1 + src/types/any.rs | 38 +++++++++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+) create mode 100644 newsfragments/3346.added.md diff --git a/newsfragments/3346.added.md b/newsfragments/3346.added.md new file mode 100644 index 00000000000..7e7085cb6d5 --- /dev/null +++ b/newsfragments/3346.added.md @@ -0,0 +1 @@ +Add `PyAny::downcast_exact`. diff --git a/src/types/any.rs b/src/types/any.rs index a9ae30b6ff0..d4678fd8d4f 100644 --- a/src/types/any.rs +++ b/src/types/any.rs @@ -894,6 +894,44 @@ impl PyAny { ::try_from(self) } + /// Downcast this `PyAny` to a concrete Python type or pyclass (but not a subclass of it). + /// + /// It is almost always better to use [`PyAny::downcast`] because it accounts for Python + /// subtyping. Use this method only when you do not want to allow subtypes. + /// + /// The advantage of this method over [`PyAny::downcast`] is that it is faster. The implementation + /// of `downcast_exact` uses the equivalent of the Python expression `type(self) is T`, whereas + /// `downcast` uses `isinstance(self, T)`. + /// + /// For extracting a Rust-only type, see [`PyAny::extract`](struct.PyAny.html#method.extract). + /// + /// # Example: Downcasting to a specific Python object but not a subtype + /// + /// ```rust + /// use pyo3::prelude::*; + /// use pyo3::types::{PyBool, PyLong}; + /// + /// Python::with_gil(|py| { + /// let b = PyBool::new(py, true); + /// assert!(b.is_instance_of::()); + /// let any: &PyAny = b.as_ref(); + /// + /// // `bool` is a subtype of `int`, so `downcast` will accept a `bool` as an `int` + /// // but `downcast_exact` will not. + /// assert!(any.downcast::().is_ok()); + /// assert!(any.downcast_exact::().is_err()); + /// + /// assert!(any.downcast_exact::().is_ok()); + /// }); + /// ``` + #[inline] + pub fn downcast_exact<'p, T>(&'p self) -> Result<&'p T, PyDowncastError<'_>> + where + T: PyTryFrom<'p>, + { + ::try_from_exact(self) + } + /// Converts this `PyAny` to a concrete Python type without checking validity. /// /// # Safety