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