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 {}