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