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::{
9 ffi, Borrowed, Bound, BoundObject, Py, PyAny, PyClass, PyErr, PyObject, PyRef, PyRefMut, Python,
10};
11use std::convert::Infallible;
12
13/// Returns a borrowed pointer to a Python object.
14///
15/// The returned pointer will be valid for as long as `self` is. It may be null depending on the
16/// implementation.
17///
18/// # Examples
19///
20/// ```rust
21/// use pyo3::prelude::*;
22/// use pyo3::ffi;
23///
24/// Python::with_gil(|py| {
25/// let s = "foo".into_pyobject(py)?;
26/// let ptr = s.as_ptr();
27///
28/// let is_really_a_pystring = unsafe { ffi::PyUnicode_CheckExact(ptr) };
29/// assert_eq!(is_really_a_pystring, 1);
30/// # Ok::<_, PyErr>(())
31/// })
32/// # .unwrap();
33/// ```
34///
35/// # Safety
36///
37/// For callers, it is your responsibility to make sure that the underlying Python object is not dropped too
38/// early. For example, the following code will cause undefined behavior:
39///
40/// ```rust,no_run
41/// # use pyo3::prelude::*;
42/// # use pyo3::ffi;
43/// #
44/// Python::with_gil(|py| {
45/// // ERROR: calling `.as_ptr()` will throw away the temporary object and leave `ptr` dangling.
46/// let ptr: *mut ffi::PyObject = 0xabad1dea_u32.into_pyobject(py)?.as_ptr();
47///
48/// let isnt_a_pystring = unsafe {
49/// // `ptr` is dangling, this is UB
50/// ffi::PyUnicode_CheckExact(ptr)
51/// };
52/// # assert_eq!(isnt_a_pystring, 0);
53/// # Ok::<_, PyErr>(())
54/// })
55/// # .unwrap();
56/// ```
57///
58/// This happens because the pointer returned by `as_ptr` does not carry any lifetime information
59/// and the Python object is dropped immediately after the `0xabad1dea_u32.into_pyobject(py).as_ptr()`
60/// expression is evaluated. To fix the problem, bind Python object to a local variable like earlier
61/// to keep the Python object alive until the end of its scope.
62///
63/// Implementors must ensure this returns a valid pointer to a Python object, which borrows a reference count from `&self`.
64pub unsafe trait AsPyPointer {
65 /// Returns the underlying FFI pointer as a borrowed pointer.
66 fn as_ptr(&self) -> *mut ffi::PyObject;
67}
68
69/// Conversion trait that allows various objects to be converted into `PyObject`.
70#[deprecated(
71 since = "0.23.0",
72 note = "`ToPyObject` is going to be replaced by `IntoPyObject`. See the migration guide (https://pyo3.rs/v0.23.0/migration) for more information."
73)]
74pub trait ToPyObject {
75 /// Converts self into a Python object.
76 fn to_object(&self, py: Python<'_>) -> PyObject;
77}
78
79/// Defines a conversion from a Rust type to a Python object.
80///
81/// It functions similarly to std's [`Into`] trait, but requires a [GIL token](Python)
82/// as an argument. Many functions and traits internal to PyO3 require this trait as a bound,
83/// so a lack of this trait can manifest itself in different error messages.
84///
85/// # Examples
86/// ## With `#[pyclass]`
87/// The easiest way to implement `IntoPy` is by exposing a struct as a native Python object
88/// by annotating it with [`#[pyclass]`](crate::prelude::pyclass).
89///
90/// ```rust
91/// use pyo3::prelude::*;
92///
93/// # #[allow(dead_code)]
94/// #[pyclass]
95/// struct Number {
96/// #[pyo3(get, set)]
97/// value: i32,
98/// }
99/// ```
100/// Python code will see this as an instance of the `Number` class with a `value` attribute.
101///
102/// ## Conversion to a Python object
103///
104/// However, it may not be desirable to expose the existence of `Number` to Python code.
105/// `IntoPy` allows us to define a conversion to an appropriate Python object.
106/// ```rust
107/// #![allow(deprecated)]
108/// use pyo3::prelude::*;
109///
110/// # #[allow(dead_code)]
111/// struct Number {
112/// value: i32,
113/// }
114///
115/// impl IntoPy<PyObject> for Number {
116/// fn into_py(self, py: Python<'_>) -> PyObject {
117/// // delegates to i32's IntoPy implementation.
118/// self.value.into_py(py)
119/// }
120/// }
121/// ```
122/// Python code will see this as an `int` object.
123///
124/// ## Dynamic conversion into Python objects.
125/// It is also possible to return a different Python object depending on some condition.
126/// This is useful for types like enums that can carry different types.
127///
128/// ```rust
129/// #![allow(deprecated)]
130/// use pyo3::prelude::*;
131///
132/// enum Value {
133/// Integer(i32),
134/// String(String),
135/// None,
136/// }
137///
138/// impl IntoPy<PyObject> for Value {
139/// fn into_py(self, py: Python<'_>) -> PyObject {
140/// match self {
141/// Self::Integer(val) => val.into_py(py),
142/// Self::String(val) => val.into_py(py),
143/// Self::None => py.None(),
144/// }
145/// }
146/// }
147/// # fn main() {
148/// # Python::with_gil(|py| {
149/// # let v = Value::Integer(73).into_py(py);
150/// # let v = v.extract::<i32>(py).unwrap();
151/// #
152/// # let v = Value::String("foo".into()).into_py(py);
153/// # let v = v.extract::<String>(py).unwrap();
154/// #
155/// # let v = Value::None.into_py(py);
156/// # let v = v.extract::<Option<Vec<i32>>>(py).unwrap();
157/// # });
158/// # }
159/// ```
160/// Python code will see this as any of the `int`, `string` or `None` objects.
161#[cfg_attr(
162 diagnostic_namespace,
163 diagnostic::on_unimplemented(
164 message = "`{Self}` cannot be converted to a Python object",
165 note = "`IntoPy` is automatically implemented by the `#[pyclass]` macro",
166 note = "if you do not wish to have a corresponding Python type, implement it manually",
167 note = "if you do not own `{Self}` you can perform a manual conversion to one of the types in `pyo3::types::*`"
168 )
169)]
170#[deprecated(
171 since = "0.23.0",
172 note = "`IntoPy` is going to be replaced by `IntoPyObject`. See the migration guide (https://pyo3.rs/v0.23.0/migration) for more information."
173)]
174pub trait IntoPy<T>: Sized {
175 /// Performs the conversion.
176 fn into_py(self, py: Python<'_>) -> T;
177}
178
179/// Defines a conversion from a Rust type to a Python object, which may fail.
180///
181/// This trait has `#[derive(IntoPyObject)]` to automatically implement it for simple types and
182/// `#[derive(IntoPyObjectRef)]` to implement the same for references.
183///
184/// It functions similarly to std's [`TryInto`] trait, but requires a [GIL token](Python)
185/// as an argument.
186///
187/// The [`into_pyobject`][IntoPyObject::into_pyobject] method is designed for maximum flexibility and efficiency; it
188/// - allows for a concrete Python type to be returned (the [`Target`][IntoPyObject::Target] associated type)
189/// - allows for the smart pointer containing the Python object to be either `Bound<'py, Self::Target>` or `Borrowed<'a, 'py, Self::Target>`
190/// to avoid unnecessary reference counting overhead
191/// - allows for a custom error type to be returned in the event of a conversion error to avoid
192/// unnecessarily creating a Python exception
193///
194/// # See also
195///
196/// - The [`IntoPyObjectExt`] trait, which provides convenience methods for common usages of
197/// `IntoPyObject` which erase type information and convert errors to `PyErr`.
198#[cfg_attr(
199 diagnostic_namespace,
200 diagnostic::on_unimplemented(
201 message = "`{Self}` cannot be converted to a Python object",
202 note = "`IntoPyObject` is automatically implemented by the `#[pyclass]` macro",
203 note = "if you do not wish to have a corresponding Python type, implement it manually",
204 note = "if you do not own `{Self}` you can perform a manual conversion to one of the types in `pyo3::types::*`"
205 )
206)]
207pub trait IntoPyObject<'py>: Sized {
208 /// The Python output type
209 type Target;
210 /// The smart pointer type to use.
211 ///
212 /// This will usually be [`Bound<'py, Target>`], but in special cases [`Borrowed<'a, 'py, Target>`] can be
213 /// used to minimize reference counting overhead.
214 type Output: BoundObject<'py, Self::Target>;
215 /// The type returned in the event of a conversion error.
216 type Error: Into<PyErr>;
217
218 /// Performs the conversion.
219 fn into_pyobject(self, py: Python<'py>) -> Result<Self::Output, Self::Error>;
220
221 /// Extracts the type hint information for this type when it appears as a return value.
222 ///
223 /// For example, `Vec<u32>` would return `List[int]`.
224 /// The default implementation returns `Any`, which is correct for any type.
225 ///
226 /// For most types, the return value for this method will be identical to that of [`FromPyObject::type_input`].
227 /// It may be different for some types, such as `Dict`, to allow duck-typing: functions return `Dict` but take `Mapping` as argument.
228 #[cfg(feature = "experimental-inspect")]
229 fn type_output() -> TypeInfo {
230 TypeInfo::Any
231 }
232
233 /// Converts sequence of Self into a Python object. Used to specialize `Vec<u8>`, `[u8; N]`
234 /// and `SmallVec<[u8; N]>` as a sequence of bytes into a `bytes` object.
235 #[doc(hidden)]
236 fn owned_sequence_into_pyobject<I>(
237 iter: I,
238 py: Python<'py>,
239 _: private::Token,
240 ) -> Result<Bound<'py, PyAny>, PyErr>
241 where
242 I: IntoIterator<Item = Self> + AsRef<[Self]>,
243 I::IntoIter: ExactSizeIterator<Item = Self>,
244 {
245 let mut iter = iter.into_iter().map(|e| e.into_bound_py_any(py));
246 let list = crate::types::list::try_new_from_iter(py, &mut iter);
247 list.map(Bound::into_any)
248 }
249
250 /// Converts sequence of Self into a Python object. Used to specialize `&[u8]` and `Cow<[u8]>`
251 /// as a sequence of bytes into a `bytes` object.
252 #[doc(hidden)]
253 fn borrowed_sequence_into_pyobject<I>(
254 iter: I,
255 py: Python<'py>,
256 _: private::Token,
257 ) -> Result<Bound<'py, PyAny>, PyErr>
258 where
259 Self: private::Reference,
260 I: IntoIterator<Item = Self> + AsRef<[<Self as private::Reference>::BaseType]>,
261 I::IntoIter: ExactSizeIterator<Item = Self>,
262 {
263 let mut iter = iter.into_iter().map(|e| e.into_bound_py_any(py));
264 let list = crate::types::list::try_new_from_iter(py, &mut iter);
265 list.map(Bound::into_any)
266 }
267}
268
269pub(crate) mod private {
270 pub struct Token;
271
272 pub trait Reference {
273 type BaseType;
274 }
275
276 impl<T> Reference for &'_ T {
277 type BaseType = T;
278 }
279}
280
281impl<'py, T> IntoPyObject<'py> for Bound<'py, T> {
282 type Target = T;
283 type Output = Bound<'py, Self::Target>;
284 type Error = Infallible;
285
286 fn into_pyobject(self, _py: Python<'py>) -> Result<Self::Output, Self::Error> {
287 Ok(self)
288 }
289}
290
291impl<'a, 'py, T> IntoPyObject<'py> for &'a Bound<'py, T> {
292 type Target = T;
293 type Output = Borrowed<'a, 'py, Self::Target>;
294 type Error = Infallible;
295
296 fn into_pyobject(self, _py: Python<'py>) -> Result<Self::Output, Self::Error> {
297 Ok(self.as_borrowed())
298 }
299}
300
301impl<'a, 'py, T> IntoPyObject<'py> for Borrowed<'a, 'py, T> {
302 type Target = T;
303 type Output = Borrowed<'a, 'py, Self::Target>;
304 type Error = Infallible;
305
306 fn into_pyobject(self, _py: Python<'py>) -> Result<Self::Output, Self::Error> {
307 Ok(self)
308 }
309}
310
311impl<'a, 'py, T> IntoPyObject<'py> for &Borrowed<'a, 'py, T> {
312 type Target = T;
313 type Output = Borrowed<'a, 'py, Self::Target>;
314 type Error = Infallible;
315
316 fn into_pyobject(self, _py: Python<'py>) -> Result<Self::Output, Self::Error> {
317 Ok(*self)
318 }
319}
320
321impl<'py, T> IntoPyObject<'py> for Py<T> {
322 type Target = T;
323 type Output = Bound<'py, Self::Target>;
324 type Error = Infallible;
325
326 fn into_pyobject(self, py: Python<'py>) -> Result<Self::Output, Self::Error> {
327 Ok(self.into_bound(py))
328 }
329}
330
331impl<'a, 'py, T> IntoPyObject<'py> for &'a Py<T> {
332 type Target = T;
333 type Output = Borrowed<'a, 'py, Self::Target>;
334 type Error = Infallible;
335
336 fn into_pyobject(self, py: Python<'py>) -> Result<Self::Output, Self::Error> {
337 Ok(self.bind_borrowed(py))
338 }
339}
340
341impl<'a, 'py, T> IntoPyObject<'py> for &&'a T
342where
343 &'a T: IntoPyObject<'py>,
344{
345 type Target = <&'a T as IntoPyObject<'py>>::Target;
346 type Output = <&'a T as IntoPyObject<'py>>::Output;
347 type Error = <&'a T as IntoPyObject<'py>>::Error;
348
349 #[inline]
350 fn into_pyobject(self, py: Python<'py>) -> Result<Self::Output, Self::Error> {
351 (*self).into_pyobject(py)
352 }
353}
354
355mod into_pyobject_ext {
356 pub trait Sealed {}
357 impl<'py, T> Sealed for T where T: super::IntoPyObject<'py> {}
358}
359
360/// Convenience methods for common usages of [`IntoPyObject`]. Every type that implements
361/// [`IntoPyObject`] also implements this trait.
362///
363/// These methods:
364/// - Drop type information from the output, returning a `PyAny` object.
365/// - Always convert the `Error` type to `PyErr`, which may incur a performance penalty but it
366/// more convenient in contexts where the `?` operator would produce a `PyErr` anyway.
367pub trait IntoPyObjectExt<'py>: IntoPyObject<'py> + into_pyobject_ext::Sealed {
368 /// Converts `self` into an owned Python object, dropping type information.
369 #[inline]
370 fn into_bound_py_any(self, py: Python<'py>) -> PyResult<Bound<'py, PyAny>> {
371 match self.into_pyobject(py) {
372 Ok(obj) => Ok(obj.into_any().into_bound()),
373 Err(err) => Err(err.into()),
374 }
375 }
376
377 /// Converts `self` into an owned Python object, dropping type information and unbinding it
378 /// from the `'py` lifetime.
379 #[inline]
380 fn into_py_any(self, py: Python<'py>) -> PyResult<Py<PyAny>> {
381 match self.into_pyobject(py) {
382 Ok(obj) => Ok(obj.into_any().unbind()),
383 Err(err) => Err(err.into()),
384 }
385 }
386
387 /// Converts `self` into a Python object.
388 ///
389 /// This is equivalent to calling [`into_pyobject`][IntoPyObject::into_pyobject] followed
390 /// with `.map_err(Into::into)` to convert the error type to [`PyErr`]. This is helpful
391 /// for generic code which wants to make use of the `?` operator.
392 #[inline]
393 fn into_pyobject_or_pyerr(self, py: Python<'py>) -> PyResult<Self::Output> {
394 match self.into_pyobject(py) {
395 Ok(obj) => Ok(obj),
396 Err(err) => Err(err.into()),
397 }
398 }
399}
400
401impl<'py, T> IntoPyObjectExt<'py> for T where T: IntoPyObject<'py> {}
402
403/// Extract a type from a Python object.
404///
405///
406/// Normal usage is through the `extract` methods on [`Bound`] and [`Py`], which forward to this trait.
407///
408/// # Examples
409///
410/// ```rust
411/// use pyo3::prelude::*;
412/// use pyo3::types::PyString;
413///
414/// # fn main() -> PyResult<()> {
415/// Python::with_gil(|py| {
416/// // Calling `.extract()` on a `Bound` smart pointer
417/// let obj: Bound<'_, PyString> = PyString::new(py, "blah");
418/// let s: String = obj.extract()?;
419/// # assert_eq!(s, "blah");
420///
421/// // Calling `.extract(py)` on a `Py` smart pointer
422/// let obj: Py<PyString> = obj.unbind();
423/// let s: String = obj.extract(py)?;
424/// # assert_eq!(s, "blah");
425/// # Ok(())
426/// })
427/// # }
428/// ```
429///
430// /// FIXME: until `FromPyObject` can pick up a second lifetime, the below commentary is no longer
431// /// true. Update and restore this documentation at that time.
432// ///
433// /// Note: depending on the implementation, the lifetime of the extracted result may
434// /// depend on the lifetime of the `obj` or the `prepared` variable.
435// ///
436// /// For example, when extracting `&str` from a Python byte string, the resulting string slice will
437// /// point to the existing string data (lifetime: `'py`).
438// /// On the other hand, when extracting `&str` from a Python Unicode string, the preparation step
439// /// will convert the string to UTF-8, and the resulting string slice will have lifetime `'prepared`.
440// /// Since which case applies depends on the runtime type of the Python object,
441// /// both the `obj` and `prepared` variables must outlive the resulting string slice.
442///
443/// During the migration of PyO3 from the "GIL Refs" API to the `Bound<T>` smart pointer, this trait
444/// has two methods `extract` and `extract_bound` which are defaulted to call each other. To avoid
445/// infinite recursion, implementors must implement at least one of these methods. The recommendation
446/// is to implement `extract_bound` and leave `extract` as the default implementation.
447pub trait FromPyObject<'py>: Sized {
448 /// Extracts `Self` from the bound smart pointer `obj`.
449 ///
450 /// Implementors are encouraged to implement this method and leave `extract` defaulted, as
451 /// this will be most compatible with PyO3's future API.
452 fn extract_bound(ob: &Bound<'py, PyAny>) -> PyResult<Self>;
453
454 /// Extracts the type hint information for this type when it appears as an argument.
455 ///
456 /// For example, `Vec<u32>` would return `Sequence[int]`.
457 /// The default implementation returns `Any`, which is correct for any type.
458 ///
459 /// For most types, the return value for this method will be identical to that of
460 /// [`IntoPyObject::type_output`]. It may be different for some types, such as `Dict`,
461 /// to allow duck-typing: functions return `Dict` but take `Mapping` as argument.
462 #[cfg(feature = "experimental-inspect")]
463 fn type_input() -> TypeInfo {
464 TypeInfo::Any
465 }
466}
467
468mod from_py_object_bound_sealed {
469 /// Private seal for the `FromPyObjectBound` trait.
470 ///
471 /// This prevents downstream types from implementing the trait before
472 /// PyO3 is ready to declare the trait as public API.
473 pub trait Sealed {}
474
475 // This generic implementation is why the seal is separate from
476 // `crate::sealed::Sealed`.
477 impl<'py, T> Sealed for T where T: super::FromPyObject<'py> {}
478 impl Sealed for &'_ str {}
479 impl Sealed for std::borrow::Cow<'_, str> {}
480 impl Sealed for &'_ [u8] {}
481 impl Sealed for std::borrow::Cow<'_, [u8]> {}
482}
483
484/// Expected form of [`FromPyObject`] to be used in a future PyO3 release.
485///
486/// The difference between this and `FromPyObject` is that this trait takes an
487/// additional lifetime `'a`, which is the lifetime of the input `Bound`.
488///
489/// This allows implementations for `&'a str` and `&'a [u8]`, which could not
490/// be expressed by the existing `FromPyObject` trait once the GIL Refs API was
491/// removed.
492///
493/// # Usage
494///
495/// Users are prevented from implementing this trait, instead they should implement
496/// the normal `FromPyObject` trait. This trait has a blanket implementation
497/// for `T: FromPyObject`.
498///
499/// The only case where this trait may have a use case to be implemented is when the
500/// lifetime of the extracted value is tied to the lifetime `'a` of the input `Bound`
501/// instead of the GIL lifetime `py`, as is the case for the `&'a str` implementation.
502///
503/// Please contact the PyO3 maintainers if you believe you have a use case for implementing
504/// this trait before PyO3 is ready to change the main `FromPyObject` trait to take an
505/// additional lifetime.
506///
507/// Similarly, users should typically not call these trait methods and should instead
508/// use this via the `extract` method on `Bound` and `Py`.
509pub trait FromPyObjectBound<'a, 'py>: Sized + from_py_object_bound_sealed::Sealed {
510 /// Extracts `Self` from the bound smart pointer `obj`.
511 ///
512 /// Users are advised against calling this method directly: instead, use this via
513 /// [`Bound<'_, PyAny>::extract`] or [`Py::extract`].
514 fn from_py_object_bound(ob: Borrowed<'a, 'py, PyAny>) -> PyResult<Self>;
515
516 /// Extracts the type hint information for this type when it appears as an argument.
517 ///
518 /// For example, `Vec<u32>` would return `Sequence[int]`.
519 /// The default implementation returns `Any`, which is correct for any type.
520 ///
521 /// For most types, the return value for this method will be identical to that of
522 /// [`IntoPyObject::type_output`]. It may be different for some types, such as `Dict`,
523 /// to allow duck-typing: functions return `Dict` but take `Mapping` as argument.
524 #[cfg(feature = "experimental-inspect")]
525 fn type_input() -> TypeInfo {
526 TypeInfo::Any
527 }
528}
529
530impl<'py, T> FromPyObjectBound<'_, 'py> for T
531where
532 T: FromPyObject<'py>,
533{
534 fn from_py_object_bound(ob: Borrowed<'_, 'py, PyAny>) -> PyResult<Self> {
535 Self::extract_bound(&ob)
536 }
537
538 #[cfg(feature = "experimental-inspect")]
539 fn type_input() -> TypeInfo {
540 <T as FromPyObject>::type_input()
541 }
542}
543
544/// Identity conversion: allows using existing `PyObject` instances where
545/// `T: ToPyObject` is expected.
546#[allow(deprecated)]
547impl<T: ?Sized + ToPyObject> ToPyObject for &'_ T {
548 #[inline]
549 fn to_object(&self, py: Python<'_>) -> PyObject {
550 <T as ToPyObject>::to_object(*self, py)
551 }
552}
553
554impl<T> FromPyObject<'_> for T
555where
556 T: PyClass + Clone,
557{
558 fn extract_bound(obj: &Bound<'_, PyAny>) -> PyResult<Self> {
559 let bound = obj.downcast::<Self>()?;
560 Ok(bound.try_borrow()?.clone())
561 }
562}
563
564impl<'py, T> FromPyObject<'py> for PyRef<'py, T>
565where
566 T: PyClass,
567{
568 fn extract_bound(obj: &Bound<'py, PyAny>) -> PyResult<Self> {
569 obj.downcast::<T>()?.try_borrow().map_err(Into::into)
570 }
571}
572
573impl<'py, T> FromPyObject<'py> for PyRefMut<'py, T>
574where
575 T: PyClass<Frozen = False>,
576{
577 fn extract_bound(obj: &Bound<'py, PyAny>) -> PyResult<Self> {
578 obj.downcast::<T>()?.try_borrow_mut().map_err(Into::into)
579 }
580}
581
582/// Converts `()` to an empty Python tuple.
583#[allow(deprecated)]
584impl IntoPy<Py<PyTuple>> for () {
585 fn into_py(self, py: Python<'_>) -> Py<PyTuple> {
586 PyTuple::empty(py).unbind()
587 }
588}
589
590impl<'py> IntoPyObject<'py> for () {
591 type Target = PyTuple;
592 type Output = Bound<'py, Self::Target>;
593 type Error = Infallible;
594
595 fn into_pyobject(self, py: Python<'py>) -> Result<Self::Output, Self::Error> {
596 Ok(PyTuple::empty(py))
597 }
598}
599
600/// ```rust,compile_fail
601/// use pyo3::prelude::*;
602///
603/// #[pyclass]
604/// struct TestClass {
605/// num: u32,
606/// }
607///
608/// let t = TestClass { num: 10 };
609///
610/// Python::with_gil(|py| {
611/// let pyvalue = Py::new(py, t).unwrap().to_object(py);
612/// let t: TestClass = pyvalue.extract(py).unwrap();
613/// })
614/// ```
615mod test_no_clone {}