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