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}