pyo3/
conversion.rs

1//! Defines conversions between Rust and Python types.
2use crate::err::PyResult;
3#[cfg(feature = "experimental-inspect")]
4use crate::inspect::types::TypeInfo;
5use crate::pyclass::boolean_struct::False;
6use crate::types::any::PyAnyMethods;
7use crate::types::PyTuple;
8use crate::{Borrowed, Bound, BoundObject, Py, PyAny, PyClass, PyErr, PyRef, PyRefMut, Python};
9use std::convert::Infallible;
10
11/// Defines a conversion from a Rust type to a Python object, which may fail.
12///
13/// This trait has `#[derive(IntoPyObject)]` to automatically implement it for simple types and
14/// `#[derive(IntoPyObjectRef)]` to implement the same for references.
15///
16/// It functions similarly to std's [`TryInto`] trait, but requires a [GIL token](Python)
17/// as an argument.
18///
19/// The [`into_pyobject`][IntoPyObject::into_pyobject] method is designed for maximum flexibility and efficiency; it
20///  - allows for a concrete Python type to be returned (the [`Target`][IntoPyObject::Target] associated type)
21///  - allows for the smart pointer containing the Python object to be either `Bound<'py, Self::Target>` or `Borrowed<'a, 'py, Self::Target>`
22///    to avoid unnecessary reference counting overhead
23///  - allows for a custom error type to be returned in the event of a conversion error to avoid
24///    unnecessarily creating a Python exception
25///
26/// # See also
27///
28/// - The [`IntoPyObjectExt`] trait, which provides convenience methods for common usages of
29///   `IntoPyObject` which erase type information and convert errors to `PyErr`.
30#[cfg_attr(
31    diagnostic_namespace,
32    diagnostic::on_unimplemented(
33        message = "`{Self}` cannot be converted to a Python object",
34        note = "`IntoPyObject` is automatically implemented by the `#[pyclass]` macro",
35        note = "if you do not wish to have a corresponding Python type, implement it manually",
36        note = "if you do not own `{Self}` you can perform a manual conversion to one of the types in `pyo3::types::*`"
37    )
38)]
39pub trait IntoPyObject<'py>: Sized {
40    /// The Python output type
41    type Target;
42    /// The smart pointer type to use.
43    ///
44    /// This will usually be [`Bound<'py, Target>`], but in special cases [`Borrowed<'a, 'py, Target>`] can be
45    /// used to minimize reference counting overhead.
46    type Output: BoundObject<'py, Self::Target>;
47    /// The type returned in the event of a conversion error.
48    type Error: Into<PyErr>;
49
50    /// Performs the conversion.
51    fn into_pyobject(self, py: Python<'py>) -> Result<Self::Output, Self::Error>;
52
53    /// Extracts the type hint information for this type when it appears as a return value.
54    ///
55    /// For example, `Vec<u32>` would return `List[int]`.
56    /// The default implementation returns `Any`, which is correct for any type.
57    ///
58    /// For most types, the return value for this method will be identical to that of [`FromPyObject::type_input`].
59    /// It may be different for some types, such as `Dict`, to allow duck-typing: functions return `Dict` but take `Mapping` as argument.
60    #[cfg(feature = "experimental-inspect")]
61    fn type_output() -> TypeInfo {
62        TypeInfo::Any
63    }
64
65    /// Converts sequence of Self into a Python object. Used to specialize `Vec<u8>`, `[u8; N]`
66    /// and `SmallVec<[u8; N]>` as a sequence of bytes into a `bytes` object.
67    #[doc(hidden)]
68    fn owned_sequence_into_pyobject<I>(
69        iter: I,
70        py: Python<'py>,
71        _: private::Token,
72    ) -> Result<Bound<'py, PyAny>, PyErr>
73    where
74        I: IntoIterator<Item = Self> + AsRef<[Self]>,
75        I::IntoIter: ExactSizeIterator<Item = Self>,
76    {
77        let mut iter = iter.into_iter().map(|e| e.into_bound_py_any(py));
78        let list = crate::types::list::try_new_from_iter(py, &mut iter);
79        list.map(Bound::into_any)
80    }
81
82    /// Converts sequence of Self into a Python object. Used to specialize `&[u8]` and `Cow<[u8]>`
83    /// as a sequence of bytes into a `bytes` object.
84    #[doc(hidden)]
85    fn borrowed_sequence_into_pyobject<I>(
86        iter: I,
87        py: Python<'py>,
88        _: private::Token,
89    ) -> Result<Bound<'py, PyAny>, PyErr>
90    where
91        Self: private::Reference,
92        I: IntoIterator<Item = Self> + AsRef<[<Self as private::Reference>::BaseType]>,
93        I::IntoIter: ExactSizeIterator<Item = Self>,
94    {
95        let mut iter = iter.into_iter().map(|e| e.into_bound_py_any(py));
96        let list = crate::types::list::try_new_from_iter(py, &mut iter);
97        list.map(Bound::into_any)
98    }
99}
100
101pub(crate) mod private {
102    pub struct Token;
103
104    pub trait Reference {
105        type BaseType;
106    }
107
108    impl<T> Reference for &'_ T {
109        type BaseType = T;
110    }
111}
112
113impl<'py, T> IntoPyObject<'py> for Bound<'py, T> {
114    type Target = T;
115    type Output = Bound<'py, Self::Target>;
116    type Error = Infallible;
117
118    fn into_pyobject(self, _py: Python<'py>) -> Result<Self::Output, Self::Error> {
119        Ok(self)
120    }
121}
122
123impl<'a, 'py, T> IntoPyObject<'py> for &'a Bound<'py, T> {
124    type Target = T;
125    type Output = Borrowed<'a, 'py, Self::Target>;
126    type Error = Infallible;
127
128    fn into_pyobject(self, _py: Python<'py>) -> Result<Self::Output, Self::Error> {
129        Ok(self.as_borrowed())
130    }
131}
132
133impl<'a, 'py, T> IntoPyObject<'py> for Borrowed<'a, 'py, T> {
134    type Target = T;
135    type Output = Borrowed<'a, 'py, Self::Target>;
136    type Error = Infallible;
137
138    fn into_pyobject(self, _py: Python<'py>) -> Result<Self::Output, Self::Error> {
139        Ok(self)
140    }
141}
142
143impl<'a, 'py, T> IntoPyObject<'py> for &Borrowed<'a, 'py, T> {
144    type Target = T;
145    type Output = Borrowed<'a, 'py, Self::Target>;
146    type Error = Infallible;
147
148    fn into_pyobject(self, _py: Python<'py>) -> Result<Self::Output, Self::Error> {
149        Ok(*self)
150    }
151}
152
153impl<'py, T> IntoPyObject<'py> for Py<T> {
154    type Target = T;
155    type Output = Bound<'py, Self::Target>;
156    type Error = Infallible;
157
158    fn into_pyobject(self, py: Python<'py>) -> Result<Self::Output, Self::Error> {
159        Ok(self.into_bound(py))
160    }
161}
162
163impl<'a, 'py, T> IntoPyObject<'py> for &'a Py<T> {
164    type Target = T;
165    type Output = Borrowed<'a, 'py, Self::Target>;
166    type Error = Infallible;
167
168    fn into_pyobject(self, py: Python<'py>) -> Result<Self::Output, Self::Error> {
169        Ok(self.bind_borrowed(py))
170    }
171}
172
173impl<'a, 'py, T> IntoPyObject<'py> for &&'a T
174where
175    &'a T: IntoPyObject<'py>,
176{
177    type Target = <&'a T as IntoPyObject<'py>>::Target;
178    type Output = <&'a T as IntoPyObject<'py>>::Output;
179    type Error = <&'a T as IntoPyObject<'py>>::Error;
180
181    #[inline]
182    fn into_pyobject(self, py: Python<'py>) -> Result<Self::Output, Self::Error> {
183        (*self).into_pyobject(py)
184    }
185}
186
187mod into_pyobject_ext {
188    pub trait Sealed {}
189    impl<'py, T> Sealed for T where T: super::IntoPyObject<'py> {}
190}
191
192/// Convenience methods for common usages of [`IntoPyObject`]. Every type that implements
193/// [`IntoPyObject`] also implements this trait.
194///
195/// These methods:
196///   - Drop type information from the output, returning a `PyAny` object.
197///   - Always convert the `Error` type to `PyErr`, which may incur a performance penalty but it
198///     more convenient in contexts where the `?` operator would produce a `PyErr` anyway.
199pub trait IntoPyObjectExt<'py>: IntoPyObject<'py> + into_pyobject_ext::Sealed {
200    /// Converts `self` into an owned Python object, dropping type information.
201    #[inline]
202    fn into_bound_py_any(self, py: Python<'py>) -> PyResult<Bound<'py, PyAny>> {
203        match self.into_pyobject(py) {
204            Ok(obj) => Ok(obj.into_any().into_bound()),
205            Err(err) => Err(err.into()),
206        }
207    }
208
209    /// Converts `self` into an owned Python object, dropping type information and unbinding it
210    /// from the `'py` lifetime.
211    #[inline]
212    fn into_py_any(self, py: Python<'py>) -> PyResult<Py<PyAny>> {
213        match self.into_pyobject(py) {
214            Ok(obj) => Ok(obj.into_any().unbind()),
215            Err(err) => Err(err.into()),
216        }
217    }
218
219    /// Converts `self` into a Python object.
220    ///
221    /// This is equivalent to calling [`into_pyobject`][IntoPyObject::into_pyobject] followed
222    /// with `.map_err(Into::into)` to convert the error type to [`PyErr`]. This is helpful
223    /// for generic code which wants to make use of the `?` operator.
224    #[inline]
225    fn into_pyobject_or_pyerr(self, py: Python<'py>) -> PyResult<Self::Output> {
226        match self.into_pyobject(py) {
227            Ok(obj) => Ok(obj),
228            Err(err) => Err(err.into()),
229        }
230    }
231}
232
233impl<'py, T> IntoPyObjectExt<'py> for T where T: IntoPyObject<'py> {}
234
235/// Extract a type from a Python object.
236///
237///
238/// Normal usage is through the `extract` methods on [`Bound`] and [`Py`], which forward to this trait.
239///
240/// # Examples
241///
242/// ```rust
243/// use pyo3::prelude::*;
244/// use pyo3::types::PyString;
245///
246/// # fn main() -> PyResult<()> {
247/// Python::with_gil(|py| {
248///     // Calling `.extract()` on a `Bound` smart pointer
249///     let obj: Bound<'_, PyString> = PyString::new(py, "blah");
250///     let s: String = obj.extract()?;
251/// #   assert_eq!(s, "blah");
252///
253///     // Calling `.extract(py)` on a `Py` smart pointer
254///     let obj: Py<PyString> = obj.unbind();
255///     let s: String = obj.extract(py)?;
256/// #   assert_eq!(s, "blah");
257/// #   Ok(())
258/// })
259/// # }
260/// ```
261///
262// /// FIXME: until `FromPyObject` can pick up a second lifetime, the below commentary is no longer
263// /// true. Update and restore this documentation at that time.
264// ///
265// /// Note: depending on the implementation, the lifetime of the extracted result may
266// /// depend on the lifetime of the `obj` or the `prepared` variable.
267// ///
268// /// For example, when extracting `&str` from a Python byte string, the resulting string slice will
269// /// point to the existing string data (lifetime: `'py`).
270// /// On the other hand, when extracting `&str` from a Python Unicode string, the preparation step
271// /// will convert the string to UTF-8, and the resulting string slice will have lifetime `'prepared`.
272// /// Since which case applies depends on the runtime type of the Python object,
273// /// both the `obj` and `prepared` variables must outlive the resulting string slice.
274///
275/// During the migration of PyO3 from the "GIL Refs" API to the `Bound<T>` smart pointer, this trait
276/// has two methods `extract` and `extract_bound` which are defaulted to call each other. To avoid
277/// infinite recursion, implementors must implement at least one of these methods. The recommendation
278/// is to implement `extract_bound` and leave `extract` as the default implementation.
279pub trait FromPyObject<'py>: Sized {
280    /// Extracts `Self` from the bound smart pointer `obj`.
281    ///
282    /// Implementors are encouraged to implement this method and leave `extract` defaulted, as
283    /// this will be most compatible with PyO3's future API.
284    fn extract_bound(ob: &Bound<'py, PyAny>) -> PyResult<Self>;
285
286    /// Extracts the type hint information for this type when it appears as an argument.
287    ///
288    /// For example, `Vec<u32>` would return `Sequence[int]`.
289    /// The default implementation returns `Any`, which is correct for any type.
290    ///
291    /// For most types, the return value for this method will be identical to that of
292    /// [`IntoPyObject::type_output`]. It may be different for some types, such as `Dict`,
293    /// to allow duck-typing: functions return `Dict` but take `Mapping` as argument.
294    #[cfg(feature = "experimental-inspect")]
295    fn type_input() -> TypeInfo {
296        TypeInfo::Any
297    }
298}
299
300mod from_py_object_bound_sealed {
301    /// Private seal for the `FromPyObjectBound` trait.
302    ///
303    /// This prevents downstream types from implementing the trait before
304    /// PyO3 is ready to declare the trait as public API.
305    pub trait Sealed {}
306
307    // This generic implementation is why the seal is separate from
308    // `crate::sealed::Sealed`.
309    impl<'py, T> Sealed for T where T: super::FromPyObject<'py> {}
310    impl Sealed for &'_ str {}
311    impl Sealed for std::borrow::Cow<'_, str> {}
312    impl Sealed for &'_ [u8] {}
313    impl Sealed for std::borrow::Cow<'_, [u8]> {}
314}
315
316/// Expected form of [`FromPyObject`] to be used in a future PyO3 release.
317///
318/// The difference between this and `FromPyObject` is that this trait takes an
319/// additional lifetime `'a`, which is the lifetime of the input `Bound`.
320///
321/// This allows implementations for `&'a str` and `&'a [u8]`, which could not
322/// be expressed by the existing `FromPyObject` trait once the GIL Refs API was
323/// removed.
324///
325/// # Usage
326///
327/// Users are prevented from implementing this trait, instead they should implement
328/// the normal `FromPyObject` trait. This trait has a blanket implementation
329/// for `T: FromPyObject`.
330///
331/// The only case where this trait may have a use case to be implemented is when the
332/// lifetime of the extracted value is tied to the lifetime `'a` of the input `Bound`
333/// instead of the GIL lifetime `py`, as is the case for the `&'a str` implementation.
334///
335/// Please contact the PyO3 maintainers if you believe you have a use case for implementing
336/// this trait before PyO3 is ready to change the main `FromPyObject` trait to take an
337/// additional lifetime.
338///
339/// Similarly, users should typically not call these trait methods and should instead
340/// use this via the `extract` method on `Bound` and `Py`.
341pub trait FromPyObjectBound<'a, 'py>: Sized + from_py_object_bound_sealed::Sealed {
342    /// Extracts `Self` from the bound smart pointer `obj`.
343    ///
344    /// Users are advised against calling this method directly: instead, use this via
345    /// [`Bound<'_, PyAny>::extract`] or [`Py::extract`].
346    fn from_py_object_bound(ob: Borrowed<'a, 'py, PyAny>) -> PyResult<Self>;
347
348    /// Extracts the type hint information for this type when it appears as an argument.
349    ///
350    /// For example, `Vec<u32>` would return `Sequence[int]`.
351    /// The default implementation returns `Any`, which is correct for any type.
352    ///
353    /// For most types, the return value for this method will be identical to that of
354    /// [`IntoPyObject::type_output`]. It may be different for some types, such as `Dict`,
355    /// to allow duck-typing: functions return `Dict` but take `Mapping` as argument.
356    #[cfg(feature = "experimental-inspect")]
357    fn type_input() -> TypeInfo {
358        TypeInfo::Any
359    }
360}
361
362impl<'py, T> FromPyObjectBound<'_, 'py> for T
363where
364    T: FromPyObject<'py>,
365{
366    fn from_py_object_bound(ob: Borrowed<'_, 'py, PyAny>) -> PyResult<Self> {
367        Self::extract_bound(&ob)
368    }
369
370    #[cfg(feature = "experimental-inspect")]
371    fn type_input() -> TypeInfo {
372        <T as FromPyObject>::type_input()
373    }
374}
375
376impl<T> FromPyObject<'_> for T
377where
378    T: PyClass + Clone,
379{
380    fn extract_bound(obj: &Bound<'_, PyAny>) -> PyResult<Self> {
381        let bound = obj.downcast::<Self>()?;
382        Ok(bound.try_borrow()?.clone())
383    }
384}
385
386impl<'py, T> FromPyObject<'py> for PyRef<'py, T>
387where
388    T: PyClass,
389{
390    fn extract_bound(obj: &Bound<'py, PyAny>) -> PyResult<Self> {
391        obj.downcast::<T>()?.try_borrow().map_err(Into::into)
392    }
393}
394
395impl<'py, T> FromPyObject<'py> for PyRefMut<'py, T>
396where
397    T: PyClass<Frozen = False>,
398{
399    fn extract_bound(obj: &Bound<'py, PyAny>) -> PyResult<Self> {
400        obj.downcast::<T>()?.try_borrow_mut().map_err(Into::into)
401    }
402}
403
404impl<'py> IntoPyObject<'py> for () {
405    type Target = PyTuple;
406    type Output = Bound<'py, Self::Target>;
407    type Error = Infallible;
408
409    fn into_pyobject(self, py: Python<'py>) -> Result<Self::Output, Self::Error> {
410        Ok(PyTuple::empty(py))
411    }
412}
413
414/// ```rust,compile_fail
415/// use pyo3::prelude::*;
416///
417/// #[pyclass]
418/// struct TestClass {
419///     num: u32,
420/// }
421///
422/// let t = TestClass { num: 10 };
423///
424/// Python::with_gil(|py| {
425///     let pyvalue = Py::new(py, t).unwrap().to_object(py);
426///     let t: TestClass = pyvalue.extract(py).unwrap();
427/// })
428/// ```
429mod test_no_clone {}
⚠️ Internal Docs ⚠️ Not Public API 👉 Official Docs Here