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