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