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