Skip to main content

pyo3/
conversion.rs

1//! Defines conversions between Rust and Python types.
2use crate::err::PyResult;
3use crate::impl_::pyclass::ExtractPyClassWithClone;
4#[cfg(feature = "experimental-inspect")]
5use crate::inspect::{type_hint_identifier, type_hint_subscript, PyStaticExpr};
6use crate::pyclass::boolean_struct::False;
7use crate::pyclass::{PyClassGuardError, PyClassGuardMutError};
8use crate::types::PyList;
9use crate::types::PyTuple;
10use crate::{
11    Borrowed, Bound, BoundObject, Py, PyAny, PyClass, PyClassGuard, PyErr, PyRef, PyRefMut,
12    PyTypeCheck, Python,
13};
14use std::convert::Infallible;
15use std::marker::PhantomData;
16
17/// Defines a conversion from a Rust type to a Python object, which may fail.
18///
19/// This trait has `#[derive(IntoPyObject)]` to automatically implement it for simple types and
20/// `#[derive(IntoPyObjectRef)]` to implement the same for references.
21///
22/// It functions similarly to std's [`TryInto`] trait, but requires a [`Python<'py>`] token
23/// as an argument.
24///
25/// The [`into_pyobject`][IntoPyObject::into_pyobject] method is designed for maximum flexibility and efficiency; it
26///  - allows for a concrete Python type to be returned (the [`Target`][IntoPyObject::Target] associated type)
27///  - allows for the smart pointer containing the Python object to be either `Bound<'py, Self::Target>` or `Borrowed<'a, 'py, Self::Target>`
28///    to avoid unnecessary reference counting overhead
29///  - allows for a custom error type to be returned in the event of a conversion error to avoid
30///    unnecessarily creating a Python exception
31///
32/// # See also
33///
34/// - The [`IntoPyObjectExt`] trait, which provides convenience methods for common usages of
35///   `IntoPyObject` which erase type information and convert errors to `PyErr`.
36#[diagnostic::on_unimplemented(
37    message = "`{Self}` cannot be converted to a Python object",
38    note = "`IntoPyObject` is automatically implemented by the `#[pyclass]` macro",
39    note = "if you do not wish to have a corresponding Python type, implement it manually",
40    note = "if you do not own `{Self}` you can perform a manual conversion to one of the types in `pyo3::types::*`"
41)]
42pub trait IntoPyObject<'py>: Sized {
43    /// The Python output type
44    type Target;
45    /// The smart pointer type to use.
46    ///
47    /// This will usually be [`Bound<'py, Target>`], but in special cases [`Borrowed<'a, 'py, Target>`] can be
48    /// used to minimize reference counting overhead.
49    type Output: BoundObject<'py, Self::Target>;
50    /// The type returned in the event of a conversion error.
51    type Error: Into<PyErr>;
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::INPUT_TYPE`].
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    const OUTPUT_TYPE: PyStaticExpr = type_hint_identifier!("_typeshed", "Incomplete");
62
63    /// Performs the conversion.
64    fn into_pyobject(self, py: Python<'py>) -> Result<Self::Output, Self::Error>;
65
66    /// Converts sequence of Self into a Python object. Used to specialize `Vec<u8>`, `[u8; N]`
67    /// and `SmallVec<[u8; N]>` as a sequence of bytes into a `bytes` object.
68    #[doc(hidden)]
69    fn owned_sequence_into_pyobject<I>(
70        iter: I,
71        py: Python<'py>,
72        _: private::Token,
73    ) -> Result<Bound<'py, PyAny>, PyErr>
74    where
75        I: IntoIterator<Item = Self> + AsRef<[Self]>,
76        I::IntoIter: ExactSizeIterator<Item = Self>,
77    {
78        Ok(PyList::new(py, iter)?.into_any())
79    }
80
81    /// Converts sequence of Self into a Python object. Used to specialize `&[u8]` and `Cow<[u8]>`
82    /// as a sequence of bytes into a `bytes` object.
83    #[doc(hidden)]
84    fn borrowed_sequence_into_pyobject<I>(
85        iter: I,
86        py: Python<'py>,
87        _: private::Token,
88    ) -> Result<Bound<'py, PyAny>, PyErr>
89    where
90        Self: private::Reference,
91        I: IntoIterator<Item = Self> + AsRef<[<Self as private::Reference>::BaseType]>,
92        I::IntoIter: ExactSizeIterator<Item = Self>,
93    {
94        Ok(PyList::new(py, iter)?.into_any())
95    }
96
97    /// The output type of [`IntoPyObject::owned_sequence_into_pyobject`] and [`IntoPyObject::borrowed_sequence_into_pyobject`]
98    #[cfg(feature = "experimental-inspect")]
99    #[doc(hidden)]
100    const SEQUENCE_OUTPUT_TYPE: PyStaticExpr =
101        type_hint_subscript!(PyList::TYPE_HINT, Self::OUTPUT_TYPE);
102}
103
104pub(crate) mod private {
105    pub struct Token;
106
107    pub trait Reference {
108        type BaseType;
109    }
110
111    impl<T> Reference for &'_ T {
112        type BaseType = T;
113    }
114}
115
116impl<'py, T: PyTypeCheck> IntoPyObject<'py> for Bound<'py, T> {
117    type Target = T;
118    type Output = Bound<'py, Self::Target>;
119    type Error = Infallible;
120
121    #[cfg(feature = "experimental-inspect")]
122    const OUTPUT_TYPE: PyStaticExpr = T::TYPE_HINT;
123
124    fn into_pyobject(self, _py: Python<'py>) -> Result<Self::Output, Self::Error> {
125        Ok(self)
126    }
127}
128
129impl<'a, 'py, T: PyTypeCheck> IntoPyObject<'py> for &'a Bound<'py, T> {
130    type Target = T;
131    type Output = Borrowed<'a, 'py, Self::Target>;
132    type Error = Infallible;
133
134    #[cfg(feature = "experimental-inspect")]
135    const OUTPUT_TYPE: PyStaticExpr = T::TYPE_HINT;
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: PyTypeCheck> 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    #[cfg(feature = "experimental-inspect")]
148    const OUTPUT_TYPE: PyStaticExpr = T::TYPE_HINT;
149
150    fn into_pyobject(self, _py: Python<'py>) -> Result<Self::Output, Self::Error> {
151        Ok(self)
152    }
153}
154
155impl<'a, 'py, T: PyTypeCheck> IntoPyObject<'py> for &Borrowed<'a, 'py, T> {
156    type Target = T;
157    type Output = Borrowed<'a, 'py, Self::Target>;
158    type Error = Infallible;
159
160    #[cfg(feature = "experimental-inspect")]
161    const OUTPUT_TYPE: PyStaticExpr = T::TYPE_HINT;
162
163    fn into_pyobject(self, _py: Python<'py>) -> Result<Self::Output, Self::Error> {
164        Ok(*self)
165    }
166}
167
168impl<'py, T: PyTypeCheck> IntoPyObject<'py> for Py<T> {
169    type Target = T;
170    type Output = Bound<'py, Self::Target>;
171    type Error = Infallible;
172
173    #[cfg(feature = "experimental-inspect")]
174    const OUTPUT_TYPE: PyStaticExpr = T::TYPE_HINT;
175
176    fn into_pyobject(self, py: Python<'py>) -> Result<Self::Output, Self::Error> {
177        Ok(self.into_bound(py))
178    }
179}
180
181impl<'a, 'py, T: PyTypeCheck> IntoPyObject<'py> for &'a Py<T> {
182    type Target = T;
183    type Output = Borrowed<'a, 'py, Self::Target>;
184    type Error = Infallible;
185
186    #[cfg(feature = "experimental-inspect")]
187    const OUTPUT_TYPE: PyStaticExpr = T::TYPE_HINT;
188
189    fn into_pyobject(self, py: Python<'py>) -> Result<Self::Output, Self::Error> {
190        Ok(self.bind_borrowed(py))
191    }
192}
193
194impl<'a, 'py, T> IntoPyObject<'py> for &&'a T
195where
196    &'a T: IntoPyObject<'py>,
197{
198    type Target = <&'a T as IntoPyObject<'py>>::Target;
199    type Output = <&'a T as IntoPyObject<'py>>::Output;
200    type Error = <&'a T as IntoPyObject<'py>>::Error;
201
202    #[cfg(feature = "experimental-inspect")]
203    const OUTPUT_TYPE: PyStaticExpr = <&'a T as IntoPyObject<'py>>::OUTPUT_TYPE;
204
205    #[inline]
206    fn into_pyobject(self, py: Python<'py>) -> Result<Self::Output, Self::Error> {
207        (*self).into_pyobject(py)
208    }
209}
210
211mod into_pyobject_ext {
212    pub trait Sealed {}
213    impl<'py, T> Sealed for T where T: super::IntoPyObject<'py> {}
214}
215
216/// Convenience methods for common usages of [`IntoPyObject`]. Every type that implements
217/// [`IntoPyObject`] also implements this trait.
218///
219/// These methods:
220///   - Drop type information from the output, returning a `PyAny` object.
221///   - Always convert the `Error` type to `PyErr`, which may incur a performance penalty but it
222///     more convenient in contexts where the `?` operator would produce a `PyErr` anyway.
223pub trait IntoPyObjectExt<'py>: IntoPyObject<'py> + into_pyobject_ext::Sealed {
224    /// Converts `self` into an owned Python object, dropping type information.
225    #[inline]
226    fn into_bound_py_any(self, py: Python<'py>) -> PyResult<Bound<'py, PyAny>> {
227        match self.into_pyobject(py) {
228            Ok(obj) => Ok(obj.into_any().into_bound()),
229            Err(err) => Err(err.into()),
230        }
231    }
232
233    /// Converts `self` into an owned Python object, dropping type information and unbinding it
234    /// from the `'py` lifetime.
235    #[inline]
236    fn into_py_any(self, py: Python<'py>) -> PyResult<Py<PyAny>> {
237        match self.into_pyobject(py) {
238            Ok(obj) => Ok(obj.into_any().unbind()),
239            Err(err) => Err(err.into()),
240        }
241    }
242
243    /// Converts `self` into a Python object.
244    ///
245    /// This is equivalent to calling [`into_pyobject`][IntoPyObject::into_pyobject] followed
246    /// with `.map_err(Into::into)` to convert the error type to [`PyErr`]. This is helpful
247    /// for generic code which wants to make use of the `?` operator.
248    #[inline]
249    fn into_pyobject_or_pyerr(self, py: Python<'py>) -> PyResult<Self::Output> {
250        match self.into_pyobject(py) {
251            Ok(obj) => Ok(obj),
252            Err(err) => Err(err.into()),
253        }
254    }
255}
256
257impl<'py, T> IntoPyObjectExt<'py> for T where T: IntoPyObject<'py> {}
258
259/// Extract a type from a Python object.
260///
261///
262/// Normal usage is through the `extract` methods on [`Bound`], [`Borrowed`] and [`Py`], which
263/// forward to this trait.
264///
265/// # Examples
266///
267/// ```rust
268/// use pyo3::prelude::*;
269/// use pyo3::types::PyString;
270///
271/// # fn main() -> PyResult<()> {
272/// Python::attach(|py| {
273///     // Calling `.extract()` on a `Bound` smart pointer
274///     let obj: Bound<'_, PyString> = PyString::new(py, "blah");
275///     let s: String = obj.extract()?;
276/// #   assert_eq!(s, "blah");
277///
278///     // Calling `.extract(py)` on a `Py` smart pointer
279///     let obj: Py<PyString> = obj.unbind();
280///     let s: String = obj.extract(py)?;
281/// #   assert_eq!(s, "blah");
282/// #   Ok(())
283/// })
284/// # }
285/// ```
286///
287/// Note: Depending on the Python version and implementation, some [`FromPyObject`] implementations
288/// may produce a result that borrows into the Python type. This is described by the input lifetime
289/// `'a` of `obj`.
290///
291/// Types that must not borrow from the input can use [`FromPyObjectOwned`] as a restriction. This
292/// is most often the case for collection types. See its documentation for more details.
293///
294/// # How to implement [`FromPyObject`]?
295/// ## `#[derive(FromPyObject)]`
296/// The simplest way to implement [`FromPyObject`] for a custom type is to make use of our derive
297/// macro.
298/// ```rust,no_run
299/// # #![allow(dead_code)]
300/// use pyo3::prelude::*;
301///
302/// #[derive(FromPyObject)]
303/// struct MyObject {
304///     msg: String,
305///     list: Vec<u32>
306/// }
307/// # fn main() {}
308/// ```
309/// By default this will try to extract each field from the Python object by attribute access, but
310/// this can be customized. For more information about the derive macro, its configuration as well
311/// as its working principle for other types, take a look at the [guide].
312///
313/// In case the derive macro is not sufficient or can not be used for some other reason,
314/// [`FromPyObject`] can be implemented manually. In the following types without lifetime parameters
315/// are handled first, because they are a little bit simpler. Types with lifetime parameters are
316/// explained below.
317///
318/// ## Manual implementation for types without lifetime
319/// Types that do not contain lifetime parameters are unable to borrow from the Python object, so
320/// the lifetimes of [`FromPyObject`] can be elided:
321/// ```rust,no_run
322/// # #![allow(dead_code)]
323/// use pyo3::prelude::*;
324///
325/// struct MyObject {
326///     msg: String,
327///     list: Vec<u32>
328/// }
329///
330/// impl FromPyObject<'_, '_> for MyObject {
331///     type Error = PyErr;
332///
333///     fn extract(obj: Borrowed<'_, '_, PyAny>) -> Result<Self, Self::Error> {
334///         Ok(MyObject {
335///             msg: obj.getattr("msg")?.extract()?,
336///             list: obj.getattr("list")?.extract()?,
337///         })
338///     }
339/// }
340///
341/// # fn main() {}
342/// ```
343/// This is basically what the derive macro above expands to.
344///
345/// ## Manual implementation for types with lifetime parameters
346/// For types that contain lifetimes, these lifetimes need to be bound to the corresponding
347/// [`FromPyObject`] lifetime. This is roughly how the extraction of a typed [`Bound`] is
348/// implemented within PyO3.
349///
350/// ```rust,no_run
351/// # #![allow(dead_code)]
352/// use pyo3::prelude::*;
353/// use pyo3::types::PyString;
354///
355/// struct MyObject<'py>(Bound<'py, PyString>);
356///
357/// impl<'py> FromPyObject<'_, 'py> for MyObject<'py> {
358///     type Error = PyErr;
359///
360///     fn extract(obj: Borrowed<'_, 'py, PyAny>) -> Result<Self, Self::Error> {
361///         Ok(MyObject(obj.cast()?.to_owned()))
362///     }
363/// }
364///
365/// # fn main() {}
366/// ```
367///
368/// # Details
369/// [`Cow<'a, str>`] is an example of an output type that may or may not borrow from the input
370/// lifetime `'a`. Which variant will be produced depends on the runtime type of the Python object.
371/// For a Python byte string, the existing string data can be borrowed for `'a` into a
372/// [`Cow::Borrowed`]. For a Python Unicode string, the data may have to be reencoded to UTF-8, and
373/// copied into a [`Cow::Owned`]. It does _not_ depend on the Python lifetime `'py`.
374///
375/// The output type may also depend on the Python lifetime `'py`. This allows the output type to
376/// keep interacting with the Python interpreter. See also [`Bound<'py, T>`].
377///
378/// [`Cow<'a, str>`]: std::borrow::Cow
379/// [`Cow::Borrowed`]: std::borrow::Cow::Borrowed
380/// [`Cow::Owned`]: std::borrow::Cow::Owned
381/// [guide]: https://pyo3.rs/latest/conversions/traits.html#deriving-frompyobject
382pub trait FromPyObject<'a, 'py>: Sized {
383    /// The type returned in the event of a conversion error.
384    ///
385    /// For most use cases defaulting to [PyErr] here is perfectly acceptable. Using a custom error
386    /// type can be used to avoid having to create a Python exception object in the case where that
387    /// exception never reaches Python. This may lead to slightly better performance under certain
388    /// conditions.
389    ///
390    /// # Note
391    /// Unfortunately `Try` and thus `?` is based on [`From`], not [`Into`], so implementations may
392    /// need to use `.map_err(Into::into)` sometimes to convert a generic `Error` into a [`PyErr`].
393    type Error: Into<PyErr>;
394
395    /// Provides the type hint information for this type when it appears as an argument.
396    ///
397    /// For example, `Vec<u32>` would be `collections.abc.Sequence[int]`.
398    /// The default value is `typing.Any`, which is correct for any type.
399    #[cfg(feature = "experimental-inspect")]
400    const INPUT_TYPE: PyStaticExpr = type_hint_identifier!("_typeshed", "Incomplete");
401
402    /// Extracts `Self` from the bound smart pointer `obj`.
403    ///
404    /// Users are advised against calling this method directly: instead, use this via
405    /// [`Bound<'_, PyAny>::extract`](crate::types::any::PyAnyMethods::extract) or [`Py::extract`].
406    fn extract(obj: Borrowed<'a, 'py, PyAny>) -> Result<Self, Self::Error>;
407
408    /// Specialization hook for extracting sequences for types like `Vec<u8>` and `[u8; N]`,
409    /// where the bytes can be directly copied from some python objects without going through
410    /// iteration.
411    #[doc(hidden)]
412    #[inline(always)]
413    fn sequence_extractor(
414        _obj: Borrowed<'_, 'py, PyAny>,
415        _: private::Token,
416    ) -> Option<impl FromPyObjectSequence<Target = Self>> {
417        struct NeverASequence<T>(PhantomData<T>);
418
419        impl<T> FromPyObjectSequence for NeverASequence<T> {
420            type Target = T;
421
422            fn to_vec(&self) -> Vec<Self::Target> {
423                unreachable!()
424            }
425
426            fn to_array<const N: usize>(&self) -> PyResult<[Self::Target; N]> {
427                unreachable!()
428            }
429        }
430
431        Option::<NeverASequence<Self>>::None
432    }
433
434    /// Helper used to make a specialized path in extracting `DateTime<Tz>` where `Tz` is
435    /// `chrono::Local`, which will accept "naive" datetime objects as being in the local timezone.
436    #[cfg(feature = "chrono-local")]
437    #[inline]
438    fn as_local_tz(_: private::Token) -> Option<Self> {
439        None
440    }
441}
442
443mod from_py_object_sequence {
444    use crate::PyResult;
445
446    /// Private trait for implementing specialized sequence extraction for `Vec<u8>` and `[u8; N]`
447    #[doc(hidden)]
448    pub trait FromPyObjectSequence {
449        type Target;
450
451        fn to_vec(&self) -> Vec<Self::Target>;
452
453        fn to_array<const N: usize>(&self) -> PyResult<[Self::Target; N]>;
454    }
455}
456
457// Only reachable / implementable inside PyO3 itself.
458pub(crate) use from_py_object_sequence::FromPyObjectSequence;
459
460/// A data structure that can be extracted without borrowing any data from the input.
461///
462/// This is primarily useful for trait bounds. For example a [`FromPyObject`] implementation of a
463/// wrapper type may be able to borrow data from the input, but a [`FromPyObject`] implementation of
464/// a collection type may only extract owned data.
465///
466/// For example [`PyList`] will not hand out references tied to its own lifetime, but "owned"
467/// references independent of it. (Similar to [`Vec<Arc<T>>`] where you clone the [`Arc<T>`] out).
468/// This makes it impossible to collect borrowed types in a collection, since they would not borrow
469/// from the original [`PyList`], but the much shorter lived element reference. See the example
470/// below.
471///
472/// ```,no_run
473/// # use pyo3::prelude::*;
474/// # #[allow(dead_code)]
475/// pub struct MyWrapper<T>(T);
476///
477/// impl<'a, 'py, T> FromPyObject<'a, 'py> for MyWrapper<T>
478/// where
479///     T: FromPyObject<'a, 'py>
480/// {
481///     type Error = T::Error;
482///
483///     fn extract(obj: Borrowed<'a, 'py, PyAny>) -> Result<Self, Self::Error> {
484///         obj.extract().map(MyWrapper)
485///     }
486/// }
487///
488/// # #[allow(dead_code)]
489/// pub struct MyVec<T>(Vec<T>);
490///
491/// impl<'py, T> FromPyObject<'_, 'py> for MyVec<T>
492/// where
493///     T: FromPyObjectOwned<'py> // 👈 can only extract owned values, because each `item` below
494///                               //    is a temporary short lived owned reference
495/// {
496///     type Error = PyErr;
497///
498///     fn extract(obj: Borrowed<'_, 'py, PyAny>) -> Result<Self, Self::Error> {
499///         let mut v = MyVec(Vec::new());
500///         for item in obj.try_iter()? {
501///             v.0.push(item?.extract::<T>().map_err(Into::into)?);
502///         }
503///         Ok(v)
504///     }
505/// }
506/// ```
507///
508/// [`PyList`]: crate::types::PyList
509/// [`Arc<T>`]: std::sync::Arc
510pub trait FromPyObjectOwned<'py>: for<'a> FromPyObject<'a, 'py> {}
511impl<'py, T> FromPyObjectOwned<'py> for T where T: for<'a> FromPyObject<'a, 'py> {}
512
513impl<'a, 'py, T> FromPyObject<'a, 'py> for T
514where
515    T: PyClass + Clone + ExtractPyClassWithClone,
516{
517    type Error = PyClassGuardError<'a, 'py>;
518
519    #[cfg(feature = "experimental-inspect")]
520    const INPUT_TYPE: PyStaticExpr = <T as crate::PyTypeInfo>::TYPE_HINT;
521
522    fn extract(obj: Borrowed<'a, 'py, PyAny>) -> Result<Self, Self::Error> {
523        Ok(obj.extract::<PyClassGuard<'_, T>>()?.clone())
524    }
525}
526
527impl<'a, 'py, T> FromPyObject<'a, 'py> for PyRef<'py, T>
528where
529    T: PyClass,
530{
531    type Error = PyClassGuardError<'a, 'py>;
532
533    #[cfg(feature = "experimental-inspect")]
534    const INPUT_TYPE: PyStaticExpr = <T as crate::PyTypeInfo>::TYPE_HINT;
535
536    fn extract(obj: Borrowed<'a, 'py, PyAny>) -> Result<Self, Self::Error> {
537        obj.cast::<T>()
538            .map_err(|e| PyClassGuardError(Some(e)))?
539            .try_borrow()
540            .map_err(|_| PyClassGuardError(None))
541    }
542}
543
544impl<'a, 'py, T> FromPyObject<'a, 'py> for PyRefMut<'py, T>
545where
546    T: PyClass<Frozen = False>,
547{
548    type Error = PyClassGuardMutError<'a, 'py>;
549
550    #[cfg(feature = "experimental-inspect")]
551    const INPUT_TYPE: PyStaticExpr = <T as crate::PyTypeInfo>::TYPE_HINT;
552
553    fn extract(obj: Borrowed<'a, 'py, PyAny>) -> Result<Self, Self::Error> {
554        obj.cast::<T>()
555            .map_err(|e| PyClassGuardMutError(Some(e)))?
556            .try_borrow_mut()
557            .map_err(|_| PyClassGuardMutError(None))
558    }
559}
560
561impl<'py> IntoPyObject<'py> for () {
562    type Target = PyTuple;
563    type Output = Bound<'py, Self::Target>;
564    type Error = Infallible;
565
566    #[cfg(feature = "experimental-inspect")]
567    const OUTPUT_TYPE: PyStaticExpr =
568        type_hint_subscript!(PyTuple::TYPE_HINT, PyStaticExpr::Tuple { elts: &[] });
569
570    fn into_pyobject(self, py: Python<'py>) -> Result<Self::Output, Self::Error> {
571        Ok(PyTuple::empty(py))
572    }
573}
574
575/// ```rust,compile_fail
576/// use pyo3::prelude::*;
577///
578/// #[pyclass]
579/// struct TestClass {
580///     num: u32,
581/// }
582///
583/// let t = TestClass { num: 10 };
584///
585/// Python::attach(|py| {
586///     let pyvalue = Py::new(py, t).unwrap().to_object(py);
587///     let t: TestClass = pyvalue.extract(py).unwrap();
588/// })
589/// ```
590mod test_no_clone {}
591
592#[cfg(test)]
593mod tests {
594    #[test]
595    #[cfg(feature = "macros")]
596    fn test_pyclass_skip_from_py_object() {
597        use crate::{types::PyAnyMethods, FromPyObject, IntoPyObject, PyErr, Python};
598
599        #[crate::pyclass(crate = "crate", skip_from_py_object)]
600        #[derive(Clone)]
601        struct Foo(i32);
602
603        impl<'py> FromPyObject<'_, 'py> for Foo {
604            type Error = PyErr;
605
606            fn extract(obj: crate::Borrowed<'_, 'py, crate::PyAny>) -> Result<Self, Self::Error> {
607                if let Ok(obj) = obj.cast::<Self>() {
608                    Ok(obj.borrow().clone())
609                } else {
610                    obj.extract::<i32>().map(Self)
611                }
612            }
613        }
614        Python::attach(|py| {
615            let foo1 = 42i32.into_pyobject(py)?;
616            assert_eq!(foo1.extract::<Foo>()?.0, 42);
617
618            let foo2 = Foo(0).into_pyobject(py)?;
619            assert_eq!(foo2.extract::<Foo>()?.0, 0);
620
621            Ok::<_, PyErr>(())
622        })
623        .unwrap();
624    }
625
626    #[test]
627    #[cfg(feature = "macros")]
628    fn test_pyclass_from_py_object() {
629        use crate::{types::PyAnyMethods, IntoPyObject, PyErr, Python};
630
631        #[crate::pyclass(crate = "crate", from_py_object)]
632        #[derive(Clone)]
633        struct Foo(i32);
634
635        Python::attach(|py| {
636            let foo1 = 42i32.into_pyobject(py)?;
637            assert!(foo1.extract::<Foo>().is_err());
638
639            let foo2 = Foo(0).into_pyobject(py)?;
640            assert_eq!(foo2.extract::<Foo>()?.0, 0);
641
642            Ok::<_, PyErr>(())
643        })
644        .unwrap();
645    }
646}