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