Skip to main content

pyo3/
conversion.rs

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