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}