1//! Defines conversions between Rust and Python types.
2use crate::err::{self, PyDowncastError, PyResult};
3#[cfg(feature = "experimental-inspect")]
4use crate::inspect::types::TypeInfo;
5use crate::pyclass::boolean_struct::False;
6use crate::type_object::PyTypeInfo;
7use crate::types::PyTuple;
8use crate::{
9 ffi, gil, Py, PyAny, PyCell, PyClass, PyNativeType, PyObject, PyRef, PyRefMut, Python,
10};
11use std::cell::Cell;
12use std::ptr::NonNull;
13
14/// Returns a borrowed pointer to a Python object.
15///
16/// The returned pointer will be valid for as long as `self` is. It may be null depending on the
17/// implementation.
18///
19/// # Examples
20///
21/// ```rust
22/// use pyo3::prelude::*;
23/// use pyo3::types::PyString;
24/// use pyo3::ffi;
25///
26/// Python::with_gil(|py| {
27/// let s: Py<PyString> = "foo".into_py(py);
28/// let ptr = s.as_ptr();
29///
30/// let is_really_a_pystring = unsafe { ffi::PyUnicode_CheckExact(ptr) };
31/// assert_eq!(is_really_a_pystring, 1);
32/// });
33/// ```
34///
35/// # Safety
36///
37/// For callers, it is your responsibility to make sure that the underlying Python object is not dropped too
38/// early. For example, the following code will cause undefined behavior:
39///
40/// ```rust,no_run
41/// # use pyo3::prelude::*;
42/// # use pyo3::ffi;
43/// #
44/// Python::with_gil(|py| {
45/// let ptr: *mut ffi::PyObject = 0xabad1dea_u32.into_py(py).as_ptr();
46///
47/// let isnt_a_pystring = unsafe {
48/// // `ptr` is dangling, this is UB
49/// ffi::PyUnicode_CheckExact(ptr)
50/// };
51/// # assert_eq!(isnt_a_pystring, 0);
52/// });
53/// ```
54///
55/// This happens because the pointer returned by `as_ptr` does not carry any lifetime information
56/// and the Python object is dropped immediately after the `0xabad1dea_u32.into_py(py).as_ptr()`
57/// expression is evaluated. To fix the problem, bind Python object to a local variable like earlier
58/// to keep the Python object alive until the end of its scope.
59///
60/// Implementors must ensure this returns a valid pointer to a Python object, which borrows a reference count from `&self`.
61pub unsafe trait AsPyPointer {
62 /// Returns the underlying FFI pointer as a borrowed pointer.
63 fn as_ptr(&self) -> *mut ffi::PyObject;
64}
65
66/// Convert `None` into a null pointer.
67unsafe impl<T> AsPyPointer for Option<T>
68where
69 T: AsPyPointer,
70{
71 #[inline]
72 fn as_ptr(&self) -> *mut ffi::PyObject {
73 self.as_ref()
74 .map_or_else(default:std::ptr::null_mut, |t: &T| t.as_ptr())
75 }
76}
77
78/// Conversion trait that allows various objects to be converted into `PyObject`.
79pub trait ToPyObject {
80 /// Converts self into a Python object.
81 fn to_object(&self, py: Python<'_>) -> PyObject;
82}
83
84/// Defines a conversion from a Rust type to a Python object.
85///
86/// It functions similarly to std's [`Into`] trait, but requires a [GIL token](Python)
87/// as an argument. Many functions and traits internal to PyO3 require this trait as a bound,
88/// so a lack of this trait can manifest itself in different error messages.
89///
90/// # Examples
91/// ## With `#[pyclass]`
92/// The easiest way to implement `IntoPy` is by exposing a struct as a native Python object
93/// by annotating it with [`#[pyclass]`](crate::prelude::pyclass).
94///
95/// ```rust
96/// use pyo3::prelude::*;
97///
98/// #[pyclass]
99/// struct Number {
100/// #[pyo3(get, set)]
101/// value: i32,
102/// }
103/// ```
104/// Python code will see this as an instance of the `Number` class with a `value` attribute.
105///
106/// ## Conversion to a Python object
107///
108/// However, it may not be desirable to expose the existence of `Number` to Python code.
109/// `IntoPy` allows us to define a conversion to an appropriate Python object.
110/// ```rust
111/// use pyo3::prelude::*;
112///
113/// struct Number {
114/// value: i32,
115/// }
116///
117/// impl IntoPy<PyObject> for Number {
118/// fn into_py(self, py: Python<'_>) -> PyObject {
119/// // delegates to i32's IntoPy implementation.
120/// self.value.into_py(py)
121/// }
122/// }
123/// ```
124/// Python code will see this as an `int` object.
125///
126/// ## Dynamic conversion into Python objects.
127/// It is also possible to return a different Python object depending on some condition.
128/// This is useful for types like enums that can carry different types.
129///
130/// ```rust
131/// use pyo3::prelude::*;
132///
133/// enum Value {
134/// Integer(i32),
135/// String(String),
136/// None,
137/// }
138///
139/// impl IntoPy<PyObject> for Value {
140/// fn into_py(self, py: Python<'_>) -> PyObject {
141/// match self {
142/// Self::Integer(val) => val.into_py(py),
143/// Self::String(val) => val.into_py(py),
144/// Self::None => py.None(),
145/// }
146/// }
147/// }
148/// # fn main() {
149/// # Python::with_gil(|py| {
150/// # let v = Value::Integer(73).into_py(py);
151/// # let v = v.extract::<i32>(py).unwrap();
152/// #
153/// # let v = Value::String("foo".into()).into_py(py);
154/// # let v = v.extract::<String>(py).unwrap();
155/// #
156/// # let v = Value::None.into_py(py);
157/// # let v = v.extract::<Option<Vec<i32>>>(py).unwrap();
158/// # });
159/// # }
160/// ```
161/// Python code will see this as any of the `int`, `string` or `None` objects.
162#[doc(alias = "IntoPyCallbackOutput")]
163pub trait IntoPy<T>: Sized {
164 /// Performs the conversion.
165 fn into_py(self, py: Python<'_>) -> T;
166
167 /// Extracts the type hint information for this type when it appears as a return value.
168 ///
169 /// For example, `Vec<u32>` would return `List[int]`.
170 /// The default implementation returns `Any`, which is correct for any type.
171 ///
172 /// For most types, the return value for this method will be identical to that of [`FromPyObject::type_input`].
173 /// It may be different for some types, such as `Dict`, to allow duck-typing: functions return `Dict` but take `Mapping` as argument.
174 #[cfg(feature = "experimental-inspect")]
175 fn type_output() -> TypeInfo {
176 TypeInfo::Any
177 }
178}
179
180/// Extract a type from a Python object.
181///
182///
183/// Normal usage is through the `extract` methods on [`Py`] and [`PyAny`], which forward to this trait.
184///
185/// # Examples
186///
187/// ```rust
188/// use pyo3::prelude::*;
189/// use pyo3::types::PyString;
190///
191/// # fn main() -> PyResult<()> {
192/// Python::with_gil(|py| {
193/// let obj: Py<PyString> = PyString::new(py, "blah").into();
194///
195/// // Straight from an owned reference
196/// let s: &str = obj.extract(py)?;
197/// # assert_eq!(s, "blah");
198///
199/// // Or from a borrowed reference
200/// let obj: &PyString = obj.as_ref(py);
201/// let s: &str = obj.extract()?;
202/// # assert_eq!(s, "blah");
203/// # Ok(())
204/// })
205/// # }
206/// ```
207///
208/// Note: depending on the implementation, the lifetime of the extracted result may
209/// depend on the lifetime of the `obj` or the `prepared` variable.
210///
211/// For example, when extracting `&str` from a Python byte string, the resulting string slice will
212/// point to the existing string data (lifetime: `'source`).
213/// On the other hand, when extracting `&str` from a Python Unicode string, the preparation step
214/// will convert the string to UTF-8, and the resulting string slice will have lifetime `'prepared`.
215/// Since which case applies depends on the runtime type of the Python object,
216/// both the `obj` and `prepared` variables must outlive the resulting string slice.
217///
218/// The trait's conversion method takes a `&PyAny` argument but is called
219/// `FromPyObject` for historical reasons.
220pub trait FromPyObject<'source>: Sized {
221 /// Extracts `Self` from the source `PyObject`.
222 fn extract(ob: &'source PyAny) -> PyResult<Self>;
223
224 /// Extracts the type hint information for this type when it appears as an argument.
225 ///
226 /// For example, `Vec<u32>` would return `Sequence[int]`.
227 /// The default implementation returns `Any`, which is correct for any type.
228 ///
229 /// For most types, the return value for this method will be identical to that of [`IntoPy::type_output`].
230 /// It may be different for some types, such as `Dict`, to allow duck-typing: functions return `Dict` but take `Mapping` as argument.
231 #[cfg(feature = "experimental-inspect")]
232 fn type_input() -> TypeInfo {
233 TypeInfo::Any
234 }
235}
236
237/// Identity conversion: allows using existing `PyObject` instances where
238/// `T: ToPyObject` is expected.
239impl<T: ?Sized + ToPyObject> ToPyObject for &'_ T {
240 #[inline]
241 fn to_object(&self, py: Python<'_>) -> PyObject {
242 <T as ToPyObject>::to_object(*self, py)
243 }
244}
245
246/// `Option::Some<T>` is converted like `T`.
247/// `Option::None` is converted to Python `None`.
248impl<T> ToPyObject for Option<T>
249where
250 T: ToPyObject,
251{
252 fn to_object(&self, py: Python<'_>) -> PyObject {
253 self.as_ref()
254 .map_or_else(|| py.None(), |val: &T| val.to_object(py))
255 }
256}
257
258impl<T> IntoPy<PyObject> for Option<T>
259where
260 T: IntoPy<PyObject>,
261{
262 fn into_py(self, py: Python<'_>) -> PyObject {
263 self.map_or_else(|| py.None(), |val: T| val.into_py(py))
264 }
265}
266
267impl IntoPy<PyObject> for &'_ PyAny {
268 #[inline]
269 fn into_py(self, py: Python<'_>) -> PyObject {
270 unsafe { PyObject::from_borrowed_ptr(py, self.as_ptr()) }
271 }
272}
273
274impl<T> IntoPy<PyObject> for &'_ T
275where
276 T: AsRef<PyAny>,
277{
278 #[inline]
279 fn into_py(self, py: Python<'_>) -> PyObject {
280 unsafe { PyObject::from_borrowed_ptr(py, self.as_ref().as_ptr()) }
281 }
282}
283
284impl<T: Copy + ToPyObject> ToPyObject for Cell<T> {
285 fn to_object(&self, py: Python<'_>) -> PyObject {
286 self.get().to_object(py)
287 }
288}
289
290impl<T: Copy + IntoPy<PyObject>> IntoPy<PyObject> for Cell<T> {
291 fn into_py(self, py: Python<'_>) -> PyObject {
292 self.get().into_py(py)
293 }
294}
295
296impl<'a, T: FromPyObject<'a>> FromPyObject<'a> for Cell<T> {
297 fn extract(ob: &'a PyAny) -> PyResult<Self> {
298 T::extract(ob).map(op:Cell::new)
299 }
300}
301
302impl<'a, T> FromPyObject<'a> for &'a PyCell<T>
303where
304 T: PyClass,
305{
306 fn extract(obj: &'a PyAny) -> PyResult<Self> {
307 PyTryFrom::try_from(obj).map_err(op:Into::into)
308 }
309}
310
311impl<'a, T> FromPyObject<'a> for T
312where
313 T: PyClass + Clone,
314{
315 fn extract(obj: &'a PyAny) -> PyResult<Self> {
316 let cell: &PyCell<Self> = PyTryFrom::try_from(obj)?;
317 Ok(unsafe { cell.try_borrow_unguarded()?.clone() })
318 }
319}
320
321impl<'a, T> FromPyObject<'a> for PyRef<'a, T>
322where
323 T: PyClass,
324{
325 fn extract(obj: &'a PyAny) -> PyResult<Self> {
326 let cell: &PyCell<T> = PyTryFrom::try_from(obj)?;
327 cell.try_borrow().map_err(op:Into::into)
328 }
329}
330
331impl<'a, T> FromPyObject<'a> for PyRefMut<'a, T>
332where
333 T: PyClass<Frozen = False>,
334{
335 fn extract(obj: &'a PyAny) -> PyResult<Self> {
336 let cell: &PyCell<T> = PyTryFrom::try_from(obj)?;
337 cell.try_borrow_mut().map_err(op:Into::into)
338 }
339}
340
341impl<'a, T> FromPyObject<'a> for Option<T>
342where
343 T: FromPyObject<'a>,
344{
345 fn extract(obj: &'a PyAny) -> PyResult<Self> {
346 if obj.as_ptr() == unsafe { ffi::Py_None() } {
347 Ok(None)
348 } else {
349 T::extract(obj).map(op:Some)
350 }
351 }
352}
353
354/// Trait implemented by Python object types that allow a checked downcast.
355/// If `T` implements `PyTryFrom`, we can convert `&PyAny` to `&T`.
356///
357/// This trait is similar to `std::convert::TryFrom`
358pub trait PyTryFrom<'v>: Sized + PyNativeType {
359 /// Cast from a concrete Python object type to PyObject.
360 fn try_from<V: Into<&'v PyAny>>(value: V) -> Result<&'v Self, PyDowncastError<'v>>;
361
362 /// Cast from a concrete Python object type to PyObject. With exact type check.
363 fn try_from_exact<V: Into<&'v PyAny>>(value: V) -> Result<&'v Self, PyDowncastError<'v>>;
364
365 /// Cast a PyAny to a specific type of PyObject. The caller must
366 /// have already verified the reference is for this type.
367 ///
368 /// # Safety
369 ///
370 /// Callers must ensure that the type is valid or risk type confusion.
371 unsafe fn try_from_unchecked<V: Into<&'v PyAny>>(value: V) -> &'v Self;
372}
373
374/// Trait implemented by Python object types that allow a checked downcast.
375/// This trait is similar to `std::convert::TryInto`
376pub trait PyTryInto<T>: Sized {
377 /// Cast from PyObject to a concrete Python object type.
378 fn try_into(&self) -> Result<&T, PyDowncastError<'_>>;
379
380 /// Cast from PyObject to a concrete Python object type. With exact type check.
381 fn try_into_exact(&self) -> Result<&T, PyDowncastError<'_>>;
382}
383
384// TryFrom implies TryInto
385impl<U> PyTryInto<U> for PyAny
386where
387 U: for<'v> PyTryFrom<'v>,
388{
389 fn try_into(&self) -> Result<&U, PyDowncastError<'_>> {
390 <U as PyTryFrom<'_>>::try_from(self)
391 }
392 fn try_into_exact(&self) -> Result<&U, PyDowncastError<'_>> {
393 U::try_from_exact(self)
394 }
395}
396
397impl<'v, T> PyTryFrom<'v> for T
398where
399 T: PyTypeInfo + PyNativeType,
400{
401 fn try_from<V: Into<&'v PyAny>>(value: V) -> Result<&'v Self, PyDowncastError<'v>> {
402 let value = value.into();
403 unsafe {
404 if T::is_type_of(value) {
405 Ok(Self::try_from_unchecked(value))
406 } else {
407 Err(PyDowncastError::new(value, T::NAME))
408 }
409 }
410 }
411
412 fn try_from_exact<V: Into<&'v PyAny>>(value: V) -> Result<&'v Self, PyDowncastError<'v>> {
413 let value = value.into();
414 unsafe {
415 if T::is_exact_type_of(value) {
416 Ok(Self::try_from_unchecked(value))
417 } else {
418 Err(PyDowncastError::new(value, T::NAME))
419 }
420 }
421 }
422
423 #[inline]
424 unsafe fn try_from_unchecked<V: Into<&'v PyAny>>(value: V) -> &'v Self {
425 Self::unchecked_downcast(value.into())
426 }
427}
428
429impl<'v, T> PyTryFrom<'v> for PyCell<T>
430where
431 T: 'v + PyClass,
432{
433 fn try_from<V: Into<&'v PyAny>>(value: V) -> Result<&'v Self, PyDowncastError<'v>> {
434 let value = value.into();
435 unsafe {
436 if T::is_type_of(value) {
437 Ok(Self::try_from_unchecked(value))
438 } else {
439 Err(PyDowncastError::new(value, T::NAME))
440 }
441 }
442 }
443 fn try_from_exact<V: Into<&'v PyAny>>(value: V) -> Result<&'v Self, PyDowncastError<'v>> {
444 let value = value.into();
445 unsafe {
446 if T::is_exact_type_of(value) {
447 Ok(Self::try_from_unchecked(value))
448 } else {
449 Err(PyDowncastError::new(value, T::NAME))
450 }
451 }
452 }
453 #[inline]
454 unsafe fn try_from_unchecked<V: Into<&'v PyAny>>(value: V) -> &'v Self {
455 Self::unchecked_downcast(value.into())
456 }
457}
458
459/// Converts `()` to an empty Python tuple.
460impl IntoPy<Py<PyTuple>> for () {
461 fn into_py(self, py: Python<'_>) -> Py<PyTuple> {
462 PyTuple::empty(py).into()
463 }
464}
465
466/// Raw level conversion between `*mut ffi::PyObject` and PyO3 types.
467///
468/// # Safety
469///
470/// See safety notes on individual functions.
471pub unsafe trait FromPyPointer<'p>: Sized {
472 /// Convert from an arbitrary `PyObject`.
473 ///
474 /// # Safety
475 ///
476 /// Implementations must ensure the object does not get freed during `'p`
477 /// and ensure that `ptr` is of the correct type.
478 /// Note that it must be safe to decrement the reference count of `ptr`.
479 unsafe fn from_owned_ptr_or_opt(py: Python<'p>, ptr: *mut ffi::PyObject) -> Option<&'p Self>;
480 /// Convert from an arbitrary `PyObject` or panic.
481 ///
482 /// # Safety
483 ///
484 /// Relies on [`from_owned_ptr_or_opt`](#method.from_owned_ptr_or_opt).
485 unsafe fn from_owned_ptr_or_panic(py: Python<'p>, ptr: *mut ffi::PyObject) -> &'p Self {
486 Self::from_owned_ptr_or_opt(py, ptr).unwrap_or_else(|| err::panic_after_error(py))
487 }
488 /// Convert from an arbitrary `PyObject` or panic.
489 ///
490 /// # Safety
491 ///
492 /// Relies on [`from_owned_ptr_or_opt`](#method.from_owned_ptr_or_opt).
493 unsafe fn from_owned_ptr(py: Python<'p>, ptr: *mut ffi::PyObject) -> &'p Self {
494 Self::from_owned_ptr_or_panic(py, ptr)
495 }
496 /// Convert from an arbitrary `PyObject`.
497 ///
498 /// # Safety
499 ///
500 /// Relies on [`from_owned_ptr_or_opt`](#method.from_owned_ptr_or_opt).
501 unsafe fn from_owned_ptr_or_err(py: Python<'p>, ptr: *mut ffi::PyObject) -> PyResult<&'p Self> {
502 Self::from_owned_ptr_or_opt(py, ptr).ok_or_else(|| err::PyErr::fetch(py))
503 }
504 /// Convert from an arbitrary borrowed `PyObject`.
505 ///
506 /// # Safety
507 ///
508 /// Implementations must ensure the object does not get freed during `'p` and avoid type confusion.
509 unsafe fn from_borrowed_ptr_or_opt(py: Python<'p>, ptr: *mut ffi::PyObject)
510 -> Option<&'p Self>;
511 /// Convert from an arbitrary borrowed `PyObject`.
512 ///
513 /// # Safety
514 ///
515 /// Relies on unsafe fn [`from_borrowed_ptr_or_opt`](#method.from_borrowed_ptr_or_opt).
516 unsafe fn from_borrowed_ptr_or_panic(py: Python<'p>, ptr: *mut ffi::PyObject) -> &'p Self {
517 Self::from_borrowed_ptr_or_opt(py, ptr).unwrap_or_else(|| err::panic_after_error(py))
518 }
519 /// Convert from an arbitrary borrowed `PyObject`.
520 ///
521 /// # Safety
522 ///
523 /// Relies on unsafe fn [`from_borrowed_ptr_or_opt`](#method.from_borrowed_ptr_or_opt).
524 unsafe fn from_borrowed_ptr(py: Python<'p>, ptr: *mut ffi::PyObject) -> &'p Self {
525 Self::from_borrowed_ptr_or_panic(py, ptr)
526 }
527 /// Convert from an arbitrary borrowed `PyObject`.
528 ///
529 /// # Safety
530 ///
531 /// Relies on unsafe fn [`from_borrowed_ptr_or_opt`](#method.from_borrowed_ptr_or_opt).
532 unsafe fn from_borrowed_ptr_or_err(
533 py: Python<'p>,
534 ptr: *mut ffi::PyObject,
535 ) -> PyResult<&'p Self> {
536 Self::from_borrowed_ptr_or_opt(py, ptr).ok_or_else(|| err::PyErr::fetch(py))
537 }
538}
539
540unsafe impl<'p, T> FromPyPointer<'p> for T
541where
542 T: 'p + crate::PyNativeType,
543{
544 unsafe fn from_owned_ptr_or_opt(py: Python<'p>, ptr: *mut ffi::PyObject) -> Option<&'p Self> {
545 gil::register_owned(py, obj:NonNull::new(ptr)?);
546 Some(&*(ptr as *mut Self))
547 }
548 unsafe fn from_borrowed_ptr_or_opt(
549 _py: Python<'p>,
550 ptr: *mut ffi::PyObject,
551 ) -> Option<&'p Self> {
552 NonNull::new(ptr as *mut Self).map(|p: NonNull| &*p.as_ptr())
553 }
554}
555
556/// ```rust,compile_fail
557/// use pyo3::prelude::*;
558///
559/// #[pyclass]
560/// struct TestClass {
561/// num: u32,
562/// }
563///
564/// let t = TestClass { num: 10 };
565///
566/// Python::with_gil(|py| {
567/// let pyvalue = Py::new(py, t).unwrap().to_object(py);
568/// let t: TestClass = pyvalue.extract(py).unwrap();
569/// })
570/// ```
571mod test_no_clone {}
572
573#[cfg(test)]
574mod tests {
575 use crate::types::{IntoPyDict, PyAny, PyDict, PyList};
576 use crate::{PyObject, Python, ToPyObject};
577
578 use super::PyTryFrom;
579
580 #[test]
581 fn test_try_from() {
582 Python::with_gil(|py| {
583 let list: &PyAny = vec![3, 6, 5, 4, 7].to_object(py).into_ref(py);
584 let dict: &PyAny = vec![("reverse", true)].into_py_dict(py).as_ref();
585
586 assert!(<PyList as PyTryFrom<'_>>::try_from(list).is_ok());
587 assert!(<PyDict as PyTryFrom<'_>>::try_from(dict).is_ok());
588
589 assert!(<PyAny as PyTryFrom<'_>>::try_from(list).is_ok());
590 assert!(<PyAny as PyTryFrom<'_>>::try_from(dict).is_ok());
591 });
592 }
593
594 #[test]
595 fn test_try_from_exact() {
596 Python::with_gil(|py| {
597 let list: &PyAny = vec![3, 6, 5, 4, 7].to_object(py).into_ref(py);
598 let dict: &PyAny = vec![("reverse", true)].into_py_dict(py).as_ref();
599
600 assert!(PyList::try_from_exact(list).is_ok());
601 assert!(PyDict::try_from_exact(dict).is_ok());
602
603 assert!(PyAny::try_from_exact(list).is_err());
604 assert!(PyAny::try_from_exact(dict).is_err());
605 });
606 }
607
608 #[test]
609 fn test_try_from_unchecked() {
610 Python::with_gil(|py| {
611 let list = PyList::new(py, [1, 2, 3]);
612 let val = unsafe { <PyList as PyTryFrom>::try_from_unchecked(list.as_ref()) };
613 assert!(list.is(val));
614 });
615 }
616
617 #[test]
618 fn test_option_as_ptr() {
619 Python::with_gil(|py| {
620 use crate::AsPyPointer;
621 let mut option: Option<PyObject> = None;
622 assert_eq!(option.as_ptr(), std::ptr::null_mut());
623
624 let none = py.None();
625 option = Some(none.clone());
626
627 let ref_cnt = none.get_refcnt(py);
628 assert_eq!(option.as_ptr(), none.as_ptr());
629
630 // Ensure ref count not changed by as_ptr call
631 assert_eq!(none.get_refcnt(py), ref_cnt);
632 });
633 }
634}
635