2021-09-13 20:58:15 +00:00
|
|
|
//! Defines conversions between Rust and Python types.
|
2019-03-29 09:57:05 +00:00
|
|
|
use crate::err::{self, PyDowncastError, PyResult};
|
2023-01-15 12:41:23 +00:00
|
|
|
#[cfg(feature = "experimental-inspect")]
|
2022-07-01 11:05:39 +00:00
|
|
|
use crate::inspect::types::TypeInfo;
|
2022-06-11 11:20:43 +00:00
|
|
|
use crate::pyclass::boolean_struct::False;
|
2020-05-01 16:09:10 +00:00
|
|
|
use crate::type_object::PyTypeInfo;
|
2019-02-23 17:01:22 +00:00
|
|
|
use crate::types::PyTuple;
|
2020-08-06 21:29:05 +00:00
|
|
|
use crate::{
|
2022-06-11 11:20:43 +00:00
|
|
|
ffi, gil, Py, PyAny, PyCell, PyClass, PyNativeType, PyObject, PyRef, PyRefMut, Python,
|
2020-08-06 21:29:05 +00:00
|
|
|
};
|
2023-03-05 18:44:45 +00:00
|
|
|
use std::cell::Cell;
|
2019-03-29 09:57:05 +00:00
|
|
|
use std::ptr::NonNull;
|
2019-02-23 17:01:22 +00:00
|
|
|
|
2022-05-02 22:46:53 +00:00
|
|
|
/// Returns a borrowed pointer to a Python object.
|
2019-02-23 17:01:22 +00:00
|
|
|
///
|
2022-05-02 22:46:53 +00:00
|
|
|
/// The returned pointer will be valid for as long as `self` is. It may be null depending on the
|
|
|
|
/// implementation.
|
2019-02-24 07:17:44 +00:00
|
|
|
///
|
2021-03-20 07:45:56 +00:00
|
|
|
/// # Examples
|
2019-02-24 07:17:44 +00:00
|
|
|
///
|
2022-05-02 22:46:53 +00:00
|
|
|
/// ```rust
|
|
|
|
/// use pyo3::prelude::*;
|
|
|
|
/// use pyo3::types::PyString;
|
|
|
|
/// use pyo3::ffi;
|
|
|
|
///
|
|
|
|
/// Python::with_gil(|py| {
|
|
|
|
/// let s: Py<PyString> = "foo".into_py(py);
|
|
|
|
/// let ptr = s.as_ptr();
|
|
|
|
///
|
|
|
|
/// let is_really_a_pystring = unsafe { ffi::PyUnicode_CheckExact(ptr) };
|
|
|
|
/// assert_eq!(is_really_a_pystring, 1);
|
|
|
|
/// });
|
2019-02-24 07:17:44 +00:00
|
|
|
/// ```
|
2022-05-02 22:46:53 +00:00
|
|
|
///
|
|
|
|
/// # Safety
|
|
|
|
///
|
|
|
|
/// It is your responsibility to make sure that the underlying Python object is not dropped too
|
|
|
|
/// early. For example, the following code will cause undefined behavior:
|
|
|
|
///
|
|
|
|
/// ```rust,no_run
|
|
|
|
/// # use pyo3::prelude::*;
|
|
|
|
/// # use pyo3::ffi;
|
|
|
|
/// #
|
2021-03-20 07:44:28 +00:00
|
|
|
/// Python::with_gil(|py| {
|
2022-05-02 22:46:53 +00:00
|
|
|
/// let ptr: *mut ffi::PyObject = 0xabad1dea_u32.into_py(py).as_ptr();
|
|
|
|
///
|
|
|
|
/// let isnt_a_pystring = unsafe {
|
|
|
|
/// // `ptr` is dangling, this is UB
|
|
|
|
/// ffi::PyUnicode_CheckExact(ptr)
|
|
|
|
/// };
|
|
|
|
/// # assert_eq!(isnt_a_pystring, 0);
|
2021-03-20 07:44:28 +00:00
|
|
|
/// });
|
2019-02-24 07:17:44 +00:00
|
|
|
/// ```
|
2022-05-02 22:46:53 +00:00
|
|
|
///
|
|
|
|
/// This happens because the pointer returned by `as_ptr` does not carry any lifetime information
|
|
|
|
/// and the Python object is dropped immediately after the `0xabad1dea_u32.into_py(py).as_ptr()`
|
|
|
|
/// expression is evaluated. To fix the problem, bind Python object to a local variable like earlier
|
|
|
|
/// to keep the Python object alive until the end of its scope.
|
2019-02-24 07:17:44 +00:00
|
|
|
pub trait AsPyPointer {
|
2022-05-02 22:46:53 +00:00
|
|
|
/// Returns the underlying FFI pointer as a borrowed pointer.
|
2019-02-23 17:01:22 +00:00
|
|
|
fn as_ptr(&self) -> *mut ffi::PyObject;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Convert `None` into a null pointer.
|
2019-02-24 07:17:44 +00:00
|
|
|
impl<T> AsPyPointer for Option<T>
|
2019-02-23 17:01:22 +00:00
|
|
|
where
|
2019-02-24 07:17:44 +00:00
|
|
|
T: AsPyPointer,
|
2019-02-23 17:01:22 +00:00
|
|
|
{
|
|
|
|
#[inline]
|
|
|
|
fn as_ptr(&self) -> *mut ffi::PyObject {
|
2020-07-19 11:26:59 +00:00
|
|
|
self.as_ref()
|
2022-02-11 22:17:00 +00:00
|
|
|
.map_or_else(std::ptr::null_mut, |t| t.as_ptr())
|
2019-02-23 17:01:22 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-17 14:16:15 +00:00
|
|
|
/// Conversion trait that allows various objects to be converted into `PyObject`.
|
2015-10-25 16:55:29 +00:00
|
|
|
pub trait ToPyObject {
|
2015-06-27 20:45:35 +00:00
|
|
|
/// Converts self into a Python object.
|
2022-03-23 07:07:28 +00:00
|
|
|
fn to_object(&self, py: Python<'_>) -> PyObject;
|
2017-07-26 08:11:00 +00:00
|
|
|
}
|
|
|
|
|
2021-04-27 13:56:49 +00:00
|
|
|
/// Defines a conversion from a Rust type to a Python object.
|
2020-08-06 21:29:05 +00:00
|
|
|
///
|
2021-04-27 13:56:49 +00:00
|
|
|
/// It functions similarly to std's [`Into`](std::convert::Into) trait,
|
|
|
|
/// but requires a [GIL token](Python) as an argument.
|
|
|
|
/// Many functions and traits internal to PyO3 require this trait as a bound,
|
|
|
|
/// so a lack of this trait can manifest itself in different error messages.
|
|
|
|
///
|
|
|
|
/// # Examples
|
|
|
|
/// ## With `#[pyclass]`
|
|
|
|
/// The easiest way to implement `IntoPy` is by exposing a struct as a native Python object
|
|
|
|
/// by annotating it with [`#[pyclass]`](crate::prelude::pyclass).
|
|
|
|
///
|
|
|
|
/// ```rust
|
|
|
|
/// use pyo3::prelude::*;
|
|
|
|
///
|
|
|
|
/// #[pyclass]
|
|
|
|
/// struct Number {
|
2021-10-14 21:15:25 +00:00
|
|
|
/// #[pyo3(get, set)]
|
|
|
|
/// value: i32,
|
2021-04-27 13:56:49 +00:00
|
|
|
/// }
|
|
|
|
/// ```
|
|
|
|
/// Python code will see this as an instance of the `Number` class with a `value` attribute.
|
|
|
|
///
|
|
|
|
/// ## Conversion to a Python object
|
|
|
|
///
|
|
|
|
/// However, it may not be desirable to expose the existence of `Number` to Python code.
|
|
|
|
/// `IntoPy` allows us to define a conversion to an appropriate Python object.
|
|
|
|
/// ```rust
|
|
|
|
/// use pyo3::prelude::*;
|
|
|
|
///
|
|
|
|
/// struct Number {
|
2021-10-14 21:15:25 +00:00
|
|
|
/// value: i32,
|
2021-04-27 13:56:49 +00:00
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// impl IntoPy<PyObject> for Number {
|
2022-03-23 07:07:28 +00:00
|
|
|
/// fn into_py(self, py: Python<'_>) -> PyObject {
|
2021-04-27 13:56:49 +00:00
|
|
|
/// // delegates to i32's IntoPy implementation.
|
|
|
|
/// self.value.into_py(py)
|
2021-10-14 21:15:25 +00:00
|
|
|
/// }
|
2021-04-27 13:56:49 +00:00
|
|
|
/// }
|
|
|
|
/// ```
|
|
|
|
/// Python code will see this as an `int` object.
|
|
|
|
///
|
2021-04-27 19:16:39 +00:00
|
|
|
/// ## Dynamic conversion into Python objects.
|
2021-04-27 13:56:49 +00:00
|
|
|
/// It is also possible to return a different Python object depending on some condition.
|
|
|
|
/// This is useful for types like enums that can carry different types.
|
|
|
|
///
|
|
|
|
/// ```rust
|
|
|
|
/// use pyo3::prelude::*;
|
|
|
|
///
|
|
|
|
/// enum Value {
|
|
|
|
/// Integer(i32),
|
|
|
|
/// String(String),
|
2021-10-14 21:15:25 +00:00
|
|
|
/// None,
|
2021-04-27 13:56:49 +00:00
|
|
|
/// }
|
2021-04-27 19:16:39 +00:00
|
|
|
///
|
2021-04-27 13:56:49 +00:00
|
|
|
/// impl IntoPy<PyObject> for Value {
|
2022-03-23 07:07:28 +00:00
|
|
|
/// fn into_py(self, py: Python<'_>) -> PyObject {
|
2021-04-27 13:56:49 +00:00
|
|
|
/// match self {
|
|
|
|
/// Self::Integer(val) => val.into_py(py),
|
|
|
|
/// Self::String(val) => val.into_py(py),
|
2021-10-14 21:15:25 +00:00
|
|
|
/// Self::None => py.None(),
|
2021-04-27 13:56:49 +00:00
|
|
|
/// }
|
2021-10-14 21:15:25 +00:00
|
|
|
/// }
|
2021-04-27 13:56:49 +00:00
|
|
|
/// }
|
2021-10-14 21:15:25 +00:00
|
|
|
/// # fn main() {
|
|
|
|
/// # Python::with_gil(|py| {
|
|
|
|
/// # let v = Value::Integer(73).into_py(py);
|
|
|
|
/// # let v = v.extract::<i32>(py).unwrap();
|
|
|
|
/// #
|
|
|
|
/// # let v = Value::String("foo".into()).into_py(py);
|
|
|
|
/// # let v = v.extract::<String>(py).unwrap();
|
|
|
|
/// #
|
|
|
|
/// # let v = Value::None.into_py(py);
|
|
|
|
/// # let v = v.extract::<Option<Vec<i32>>>(py).unwrap();
|
|
|
|
/// # });
|
|
|
|
/// # }
|
2021-04-27 13:56:49 +00:00
|
|
|
/// ```
|
|
|
|
/// Python code will see this as any of the `int`, `string` or `None` objects.
|
2023-06-08 20:04:49 +00:00
|
|
|
#[doc(alias = "IntoPyCallbackOutput")]
|
2019-02-07 17:48:29 +00:00
|
|
|
pub trait IntoPy<T>: Sized {
|
2019-02-23 17:01:22 +00:00
|
|
|
/// Performs the conversion.
|
2022-03-23 07:07:28 +00:00
|
|
|
fn into_py(self, py: Python<'_>) -> T;
|
2022-07-01 11:05:39 +00:00
|
|
|
|
|
|
|
/// Extracts the type hint information for this type when it appears as a return value.
|
|
|
|
///
|
|
|
|
/// For example, `Vec<u32>` would return `List[int]`.
|
|
|
|
/// The default implementation returns `Any`, which is correct for any type.
|
|
|
|
///
|
|
|
|
/// For most types, the return value for this method will be identical to that of [`FromPyObject::type_input`].
|
|
|
|
/// It may be different for some types, such as `Dict`, to allow duck-typing: functions return `Dict` but take `Mapping` as argument.
|
2023-01-15 12:41:23 +00:00
|
|
|
#[cfg(feature = "experimental-inspect")]
|
2022-07-01 11:05:39 +00:00
|
|
|
fn type_output() -> TypeInfo {
|
|
|
|
TypeInfo::Any
|
|
|
|
}
|
2019-02-07 17:48:29 +00:00
|
|
|
}
|
|
|
|
|
2022-05-02 22:46:53 +00:00
|
|
|
/// Extract a type from a Python object.
|
2015-07-18 20:39:55 +00:00
|
|
|
///
|
2020-03-17 14:16:15 +00:00
|
|
|
///
|
2022-05-02 22:46:53 +00:00
|
|
|
/// Normal usage is through the `extract` methods on [`Py`] and [`PyAny`], which forward to this trait.
|
2020-03-17 14:16:15 +00:00
|
|
|
///
|
2022-05-02 22:46:53 +00:00
|
|
|
/// # Examples
|
|
|
|
///
|
|
|
|
/// ```rust
|
|
|
|
/// use pyo3::prelude::*;
|
|
|
|
/// use pyo3::types::PyString;
|
|
|
|
///
|
|
|
|
/// # fn main() -> PyResult<()> {
|
|
|
|
/// Python::with_gil(|py| {
|
|
|
|
/// let obj: Py<PyString> = PyString::new(py, "blah").into();
|
|
|
|
///
|
|
|
|
/// // Straight from an owned reference
|
|
|
|
/// let s: &str = obj.extract(py)?;
|
|
|
|
/// # assert_eq!(s, "blah");
|
|
|
|
///
|
|
|
|
/// // Or from a borrowed reference
|
|
|
|
/// let obj: &PyString = obj.as_ref(py);
|
|
|
|
/// let s: &str = obj.extract()?;
|
|
|
|
/// # assert_eq!(s, "blah");
|
|
|
|
/// # Ok(())
|
|
|
|
/// })
|
|
|
|
/// # }
|
2016-05-08 19:25:09 +00:00
|
|
|
/// ```
|
|
|
|
///
|
2015-07-18 20:39:55 +00:00
|
|
|
/// Note: depending on the implementation, the lifetime of the extracted result may
|
|
|
|
/// depend on the lifetime of the `obj` or the `prepared` variable.
|
|
|
|
///
|
2020-03-17 14:16:15 +00:00
|
|
|
/// For example, when extracting `&str` from a Python byte string, the resulting string slice will
|
2015-07-18 20:39:55 +00:00
|
|
|
/// point to the existing string data (lifetime: `'source`).
|
2020-03-17 14:16:15 +00:00
|
|
|
/// On the other hand, when extracting `&str` from a Python Unicode string, the preparation step
|
2015-07-18 20:39:55 +00:00
|
|
|
/// will convert the string to UTF-8, and the resulting string slice will have lifetime `'prepared`.
|
2020-03-17 14:16:15 +00:00
|
|
|
/// Since which case applies depends on the runtime type of the Python object,
|
2015-07-18 20:39:55 +00:00
|
|
|
/// both the `obj` and `prepared` variables must outlive the resulting string slice.
|
|
|
|
///
|
2020-03-17 14:16:15 +00:00
|
|
|
/// The trait's conversion method takes a `&PyAny` argument but is called
|
|
|
|
/// `FromPyObject` for historical reasons.
|
2018-07-30 21:01:46 +00:00
|
|
|
pub trait FromPyObject<'source>: Sized {
|
2016-05-08 19:25:09 +00:00
|
|
|
/// Extracts `Self` from the source `PyObject`.
|
2019-03-04 04:50:43 +00:00
|
|
|
fn extract(ob: &'source PyAny) -> PyResult<Self>;
|
2022-07-01 11:05:39 +00:00
|
|
|
|
|
|
|
/// Extracts the type hint information for this type when it appears as an argument.
|
|
|
|
///
|
|
|
|
/// For example, `Vec<u32>` would return `Sequence[int]`.
|
|
|
|
/// The default implementation returns `Any`, which is correct for any type.
|
|
|
|
///
|
|
|
|
/// For most types, the return value for this method will be identical to that of [`IntoPy::type_output`].
|
|
|
|
/// It may be different for some types, such as `Dict`, to allow duck-typing: functions return `Dict` but take `Mapping` as argument.
|
2023-01-15 12:41:23 +00:00
|
|
|
#[cfg(feature = "experimental-inspect")]
|
2022-07-01 11:05:39 +00:00
|
|
|
fn type_input() -> TypeInfo {
|
|
|
|
TypeInfo::Any
|
|
|
|
}
|
2016-05-08 19:25:09 +00:00
|
|
|
}
|
|
|
|
|
2017-05-19 04:35:08 +00:00
|
|
|
/// Identity conversion: allows using existing `PyObject` instances where
|
|
|
|
/// `T: ToPyObject` is expected.
|
2020-11-20 05:55:24 +00:00
|
|
|
impl<T: ?Sized + ToPyObject> ToPyObject for &'_ T {
|
2015-01-04 19:11:18 +00:00
|
|
|
#[inline]
|
2022-03-23 07:07:28 +00:00
|
|
|
fn to_object(&self, py: Python<'_>) -> PyObject {
|
2017-05-25 03:31:51 +00:00
|
|
|
<T as ToPyObject>::to_object(*self, py)
|
2015-01-04 19:11:18 +00:00
|
|
|
}
|
2017-07-26 08:11:00 +00:00
|
|
|
}
|
|
|
|
|
2016-05-08 15:51:16 +00:00
|
|
|
/// `Option::Some<T>` is converted like `T`.
|
|
|
|
/// `Option::None` is converted to Python `None`.
|
2018-07-30 21:01:46 +00:00
|
|
|
impl<T> ToPyObject for Option<T>
|
|
|
|
where
|
|
|
|
T: ToPyObject,
|
|
|
|
{
|
2022-03-23 07:07:28 +00:00
|
|
|
fn to_object(&self, py: Python<'_>) -> PyObject {
|
2020-07-19 11:26:59 +00:00
|
|
|
self.as_ref()
|
|
|
|
.map_or_else(|| py.None(), |val| val.to_object(py))
|
2016-05-08 15:51:16 +00:00
|
|
|
}
|
2017-05-25 05:43:07 +00:00
|
|
|
}
|
2018-01-19 17:04:42 +00:00
|
|
|
|
2019-08-24 17:21:45 +00:00
|
|
|
impl<T> IntoPy<PyObject> for Option<T>
|
2018-07-30 21:01:46 +00:00
|
|
|
where
|
2019-08-24 17:21:45 +00:00
|
|
|
T: IntoPy<PyObject>,
|
2018-07-30 21:01:46 +00:00
|
|
|
{
|
2022-03-23 07:07:28 +00:00
|
|
|
fn into_py(self, py: Python<'_>) -> PyObject {
|
2020-07-19 11:26:59 +00:00
|
|
|
self.map_or_else(|| py.None(), |val| val.into_py(py))
|
2016-05-08 15:51:16 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-05-05 16:30:58 +00:00
|
|
|
/// `()` is converted to Python `None`.
|
|
|
|
impl ToPyObject for () {
|
2022-03-23 07:07:28 +00:00
|
|
|
fn to_object(&self, py: Python<'_>) -> PyObject {
|
2017-05-31 22:52:13 +00:00
|
|
|
py.None()
|
2017-05-05 16:30:58 +00:00
|
|
|
}
|
|
|
|
}
|
2017-08-03 22:01:52 +00:00
|
|
|
|
2020-07-21 23:02:11 +00:00
|
|
|
impl IntoPy<PyObject> for () {
|
2022-03-23 07:07:28 +00:00
|
|
|
fn into_py(self, py: Python<'_>) -> PyObject {
|
2017-06-06 03:25:00 +00:00
|
|
|
py.None()
|
|
|
|
}
|
|
|
|
}
|
2017-08-03 22:01:52 +00:00
|
|
|
|
2020-07-21 23:02:11 +00:00
|
|
|
impl<T> IntoPy<PyObject> for &'_ T
|
2018-07-30 21:01:46 +00:00
|
|
|
where
|
2019-02-24 07:17:44 +00:00
|
|
|
T: AsPyPointer,
|
2018-07-30 21:01:46 +00:00
|
|
|
{
|
2017-07-29 06:19:00 +00:00
|
|
|
#[inline]
|
2022-03-23 07:07:28 +00:00
|
|
|
fn into_py(self, py: Python<'_>) -> PyObject {
|
2020-07-21 23:02:11 +00:00
|
|
|
unsafe { PyObject::from_borrowed_ptr(py, self.as_ptr()) }
|
2017-07-29 06:19:00 +00:00
|
|
|
}
|
|
|
|
}
|
2017-05-05 16:30:58 +00:00
|
|
|
|
2023-03-05 18:44:45 +00:00
|
|
|
impl<T: Copy + ToPyObject> ToPyObject for Cell<T> {
|
|
|
|
fn to_object(&self, py: Python<'_>) -> PyObject {
|
|
|
|
self.get().to_object(py)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<T: Copy + IntoPy<PyObject>> IntoPy<PyObject> for Cell<T> {
|
|
|
|
fn into_py(self, py: Python<'_>) -> PyObject {
|
|
|
|
self.get().into_py(py)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a, T: FromPyObject<'a>> FromPyObject<'a> for Cell<T> {
|
|
|
|
fn extract(ob: &'a PyAny) -> PyResult<Self> {
|
|
|
|
T::extract(ob).map(Cell::new)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-15 04:42:25 +00:00
|
|
|
impl<'a, T> FromPyObject<'a> for &'a PyCell<T>
|
|
|
|
where
|
|
|
|
T: PyClass,
|
|
|
|
{
|
|
|
|
fn extract(obj: &'a PyAny) -> PyResult<Self> {
|
|
|
|
PyTryFrom::try_from(obj).map_err(Into::into)
|
2020-01-13 22:56:16 +00:00
|
|
|
}
|
2020-02-15 04:42:25 +00:00
|
|
|
}
|
2020-01-13 22:56:16 +00:00
|
|
|
|
2020-02-15 04:42:25 +00:00
|
|
|
impl<'a, T> FromPyObject<'a> for T
|
|
|
|
where
|
|
|
|
T: PyClass + Clone,
|
|
|
|
{
|
|
|
|
fn extract(obj: &'a PyAny) -> PyResult<Self> {
|
|
|
|
let cell: &PyCell<Self> = PyTryFrom::try_from(obj)?;
|
2020-02-22 11:26:11 +00:00
|
|
|
Ok(unsafe { cell.try_borrow_unguarded()?.clone() })
|
2020-01-13 22:56:16 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-15 04:42:25 +00:00
|
|
|
impl<'a, T> FromPyObject<'a> for PyRef<'a, T>
|
|
|
|
where
|
|
|
|
T: PyClass,
|
|
|
|
{
|
|
|
|
fn extract(obj: &'a PyAny) -> PyResult<Self> {
|
|
|
|
let cell: &PyCell<T> = PyTryFrom::try_from(obj)?;
|
|
|
|
cell.try_borrow().map_err(Into::into)
|
|
|
|
}
|
2017-05-31 01:57:36 +00:00
|
|
|
}
|
2017-05-05 16:30:58 +00:00
|
|
|
|
2020-02-15 04:42:25 +00:00
|
|
|
impl<'a, T> FromPyObject<'a> for PyRefMut<'a, T>
|
2018-07-30 21:01:46 +00:00
|
|
|
where
|
2022-06-11 11:20:43 +00:00
|
|
|
T: PyClass<Frozen = False>,
|
2017-06-07 02:26:59 +00:00
|
|
|
{
|
2020-02-15 04:42:25 +00:00
|
|
|
fn extract(obj: &'a PyAny) -> PyResult<Self> {
|
|
|
|
let cell: &PyCell<T> = PyTryFrom::try_from(obj)?;
|
|
|
|
cell.try_borrow_mut().map_err(Into::into)
|
2018-01-19 17:04:42 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-30 21:01:46 +00:00
|
|
|
impl<'a, T> FromPyObject<'a> for Option<T>
|
|
|
|
where
|
|
|
|
T: FromPyObject<'a>,
|
2018-01-19 17:04:42 +00:00
|
|
|
{
|
2019-03-04 04:50:43 +00:00
|
|
|
fn extract(obj: &'a PyAny) -> PyResult<Self> {
|
2016-05-08 19:25:09 +00:00
|
|
|
if obj.as_ptr() == unsafe { ffi::Py_None() } {
|
|
|
|
Ok(None)
|
|
|
|
} else {
|
2020-07-19 11:26:59 +00:00
|
|
|
T::extract(obj).map(Some)
|
2016-05-08 19:25:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2017-07-29 06:19:00 +00:00
|
|
|
|
|
|
|
/// Trait implemented by Python object types that allow a checked downcast.
|
2020-02-25 10:56:58 +00:00
|
|
|
/// If `T` implements `PyTryFrom`, we can convert `&PyAny` to `&T`.
|
|
|
|
///
|
2017-07-29 06:19:00 +00:00
|
|
|
/// This trait is similar to `std::convert::TryFrom`
|
2020-05-01 16:09:10 +00:00
|
|
|
pub trait PyTryFrom<'v>: Sized + PyNativeType {
|
2017-07-29 06:19:00 +00:00
|
|
|
/// Cast from a concrete Python object type to PyObject.
|
2020-07-19 10:23:07 +00:00
|
|
|
fn try_from<V: Into<&'v PyAny>>(value: V) -> Result<&'v Self, PyDowncastError<'v>>;
|
2017-07-29 06:19:00 +00:00
|
|
|
|
|
|
|
/// Cast from a concrete Python object type to PyObject. With exact type check.
|
2020-07-19 10:23:07 +00:00
|
|
|
fn try_from_exact<V: Into<&'v PyAny>>(value: V) -> Result<&'v Self, PyDowncastError<'v>>;
|
2017-07-29 06:19:00 +00:00
|
|
|
|
2019-03-04 04:50:43 +00:00
|
|
|
/// Cast a PyAny to a specific type of PyObject. The caller must
|
2018-12-01 15:12:27 +00:00
|
|
|
/// have already verified the reference is for this type.
|
2021-01-15 14:31:40 +00:00
|
|
|
///
|
|
|
|
/// # Safety
|
|
|
|
///
|
|
|
|
/// Callers must ensure that the type is valid or risk type confusion.
|
2019-03-04 04:50:43 +00:00
|
|
|
unsafe fn try_from_unchecked<V: Into<&'v PyAny>>(value: V) -> &'v Self;
|
2017-07-29 06:19:00 +00:00
|
|
|
}
|
|
|
|
|
2020-02-15 04:42:25 +00:00
|
|
|
/// Trait implemented by Python object types that allow a checked downcast.
|
|
|
|
/// This trait is similar to `std::convert::TryInto`
|
|
|
|
pub trait PyTryInto<T>: Sized {
|
|
|
|
/// Cast from PyObject to a concrete Python object type.
|
2022-03-23 07:07:28 +00:00
|
|
|
fn try_into(&self) -> Result<&T, PyDowncastError<'_>>;
|
2020-02-09 07:35:52 +00:00
|
|
|
|
2020-02-15 04:42:25 +00:00
|
|
|
/// Cast from PyObject to a concrete Python object type. With exact type check.
|
2022-03-23 07:07:28 +00:00
|
|
|
fn try_into_exact(&self) -> Result<&T, PyDowncastError<'_>>;
|
2020-02-15 04:42:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// TryFrom implies TryInto
|
|
|
|
impl<U> PyTryInto<U> for PyAny
|
|
|
|
where
|
|
|
|
U: for<'v> PyTryFrom<'v>,
|
|
|
|
{
|
2022-03-23 07:07:28 +00:00
|
|
|
fn try_into(&self) -> Result<&U, PyDowncastError<'_>> {
|
|
|
|
<U as PyTryFrom<'_>>::try_from(self)
|
2020-02-15 04:42:25 +00:00
|
|
|
}
|
2022-03-23 07:07:28 +00:00
|
|
|
fn try_into_exact(&self) -> Result<&U, PyDowncastError<'_>> {
|
2020-02-15 04:42:25 +00:00
|
|
|
U::try_from_exact(self)
|
|
|
|
}
|
|
|
|
}
|
2017-07-29 06:19:00 +00:00
|
|
|
|
2019-02-07 05:27:13 +00:00
|
|
|
impl<'v, T> PyTryFrom<'v> for T
|
2018-07-30 21:01:46 +00:00
|
|
|
where
|
2020-05-01 16:09:10 +00:00
|
|
|
T: PyTypeInfo + PyNativeType,
|
2018-07-30 21:01:46 +00:00
|
|
|
{
|
2020-07-19 10:23:07 +00:00
|
|
|
fn try_from<V: Into<&'v PyAny>>(value: V) -> Result<&'v Self, PyDowncastError<'v>> {
|
2019-02-07 05:27:13 +00:00
|
|
|
let value = value.into();
|
2017-07-29 06:19:00 +00:00
|
|
|
unsafe {
|
2020-11-15 15:10:56 +00:00
|
|
|
if T::is_type_of(value) {
|
2020-02-09 07:35:52 +00:00
|
|
|
Ok(Self::try_from_unchecked(value))
|
2017-07-29 06:19:00 +00:00
|
|
|
} else {
|
2020-07-19 08:44:25 +00:00
|
|
|
Err(PyDowncastError::new(value, T::NAME))
|
2017-07-29 06:19:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-19 10:23:07 +00:00
|
|
|
fn try_from_exact<V: Into<&'v PyAny>>(value: V) -> Result<&'v Self, PyDowncastError<'v>> {
|
2019-02-07 05:27:13 +00:00
|
|
|
let value = value.into();
|
2017-07-29 06:19:00 +00:00
|
|
|
unsafe {
|
2020-11-15 15:10:56 +00:00
|
|
|
if T::is_exact_type_of(value) {
|
2020-02-09 07:35:52 +00:00
|
|
|
Ok(Self::try_from_unchecked(value))
|
2017-07-29 06:19:00 +00:00
|
|
|
} else {
|
2020-07-19 08:44:25 +00:00
|
|
|
Err(PyDowncastError::new(value, T::NAME))
|
2017-07-29 06:19:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2018-12-01 15:12:27 +00:00
|
|
|
|
|
|
|
#[inline]
|
2020-02-09 07:35:52 +00:00
|
|
|
unsafe fn try_from_unchecked<V: Into<&'v PyAny>>(value: V) -> &'v Self {
|
|
|
|
Self::unchecked_downcast(value.into())
|
2018-12-01 15:27:48 +00:00
|
|
|
}
|
2017-07-29 06:19:00 +00:00
|
|
|
}
|
2018-04-06 15:19:32 +00:00
|
|
|
|
2020-02-15 04:42:25 +00:00
|
|
|
impl<'v, T> PyTryFrom<'v> for PyCell<T>
|
|
|
|
where
|
|
|
|
T: 'v + PyClass,
|
|
|
|
{
|
2020-07-19 10:23:07 +00:00
|
|
|
fn try_from<V: Into<&'v PyAny>>(value: V) -> Result<&'v Self, PyDowncastError<'v>> {
|
2020-02-15 04:42:25 +00:00
|
|
|
let value = value.into();
|
|
|
|
unsafe {
|
2020-11-15 15:10:56 +00:00
|
|
|
if T::is_type_of(value) {
|
2020-02-15 04:42:25 +00:00
|
|
|
Ok(Self::try_from_unchecked(value))
|
|
|
|
} else {
|
2020-07-19 08:44:25 +00:00
|
|
|
Err(PyDowncastError::new(value, T::NAME))
|
2020-02-15 04:42:25 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-07-19 10:23:07 +00:00
|
|
|
fn try_from_exact<V: Into<&'v PyAny>>(value: V) -> Result<&'v Self, PyDowncastError<'v>> {
|
2020-02-15 04:42:25 +00:00
|
|
|
let value = value.into();
|
|
|
|
unsafe {
|
2020-11-15 15:10:56 +00:00
|
|
|
if T::is_exact_type_of(value) {
|
2020-02-15 04:42:25 +00:00
|
|
|
Ok(Self::try_from_unchecked(value))
|
|
|
|
} else {
|
2020-07-19 08:44:25 +00:00
|
|
|
Err(PyDowncastError::new(value, T::NAME))
|
2020-02-15 04:42:25 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#[inline]
|
|
|
|
unsafe fn try_from_unchecked<V: Into<&'v PyAny>>(value: V) -> &'v Self {
|
|
|
|
Self::unchecked_downcast(value.into())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-23 17:01:22 +00:00
|
|
|
/// Converts `()` to an empty Python tuple.
|
2020-07-21 23:02:11 +00:00
|
|
|
impl IntoPy<Py<PyTuple>> for () {
|
2022-03-23 07:07:28 +00:00
|
|
|
fn into_py(self, py: Python<'_>) -> Py<PyTuple> {
|
2020-07-21 23:40:31 +00:00
|
|
|
PyTuple::empty(py).into()
|
2018-04-06 15:19:32 +00:00
|
|
|
}
|
2018-07-30 21:01:46 +00:00
|
|
|
}
|
2018-12-01 15:12:27 +00:00
|
|
|
|
2019-04-03 08:14:03 +00:00
|
|
|
/// Raw level conversion between `*mut ffi::PyObject` and PyO3 types.
|
2021-12-03 23:29:02 +00:00
|
|
|
///
|
|
|
|
/// # Safety
|
|
|
|
///
|
|
|
|
/// See safety notes on individual functions.
|
2019-03-29 09:57:05 +00:00
|
|
|
pub unsafe trait FromPyPointer<'p>: Sized {
|
2021-01-15 14:31:40 +00:00
|
|
|
/// Convert from an arbitrary `PyObject`.
|
|
|
|
///
|
|
|
|
/// # Safety
|
|
|
|
///
|
2021-01-16 13:31:16 +00:00
|
|
|
/// Implementations must ensure the object does not get freed during `'p`
|
|
|
|
/// and ensure that `ptr` is of the correct type.
|
|
|
|
/// Note that it must be safe to decrement the reference count of `ptr`.
|
2020-02-09 07:35:52 +00:00
|
|
|
unsafe fn from_owned_ptr_or_opt(py: Python<'p>, ptr: *mut ffi::PyObject) -> Option<&'p Self>;
|
2021-01-15 14:31:40 +00:00
|
|
|
/// Convert from an arbitrary `PyObject` or panic.
|
|
|
|
///
|
|
|
|
/// # Safety
|
|
|
|
///
|
2021-01-16 13:16:14 +00:00
|
|
|
/// Relies on [`from_owned_ptr_or_opt`](#method.from_owned_ptr_or_opt).
|
2020-02-09 07:35:52 +00:00
|
|
|
unsafe fn from_owned_ptr_or_panic(py: Python<'p>, ptr: *mut ffi::PyObject) -> &'p Self {
|
2020-07-19 11:26:59 +00:00
|
|
|
Self::from_owned_ptr_or_opt(py, ptr).unwrap_or_else(|| err::panic_after_error(py))
|
2019-03-29 09:57:05 +00:00
|
|
|
}
|
2021-01-15 14:31:40 +00:00
|
|
|
/// Convert from an arbitrary `PyObject` or panic.
|
|
|
|
///
|
|
|
|
/// # Safety
|
|
|
|
///
|
2021-01-16 14:11:11 +00:00
|
|
|
/// Relies on [`from_owned_ptr_or_opt`](#method.from_owned_ptr_or_opt).
|
2020-02-09 07:35:52 +00:00
|
|
|
unsafe fn from_owned_ptr(py: Python<'p>, ptr: *mut ffi::PyObject) -> &'p Self {
|
2019-03-29 09:57:05 +00:00
|
|
|
Self::from_owned_ptr_or_panic(py, ptr)
|
|
|
|
}
|
2021-01-15 14:31:40 +00:00
|
|
|
/// Convert from an arbitrary `PyObject`.
|
|
|
|
///
|
|
|
|
/// # Safety
|
|
|
|
///
|
2021-01-16 14:11:11 +00:00
|
|
|
/// Relies on [`from_owned_ptr_or_opt`](#method.from_owned_ptr_or_opt).
|
2020-02-09 07:35:52 +00:00
|
|
|
unsafe fn from_owned_ptr_or_err(py: Python<'p>, ptr: *mut ffi::PyObject) -> PyResult<&'p Self> {
|
2021-10-30 09:51:02 +00:00
|
|
|
Self::from_owned_ptr_or_opt(py, ptr).ok_or_else(|| err::PyErr::fetch(py))
|
2019-03-29 09:57:05 +00:00
|
|
|
}
|
2021-01-15 14:31:40 +00:00
|
|
|
/// Convert from an arbitrary borrowed `PyObject`.
|
|
|
|
///
|
|
|
|
/// # Safety
|
|
|
|
///
|
|
|
|
/// Implementations must ensure the object does not get freed during `'p` and avoid type confusion.
|
2020-02-09 07:35:52 +00:00
|
|
|
unsafe fn from_borrowed_ptr_or_opt(py: Python<'p>, ptr: *mut ffi::PyObject)
|
|
|
|
-> Option<&'p Self>;
|
2021-01-15 14:31:40 +00:00
|
|
|
/// Convert from an arbitrary borrowed `PyObject`.
|
|
|
|
///
|
|
|
|
/// # Safety
|
|
|
|
///
|
2021-01-16 14:11:11 +00:00
|
|
|
/// Relies on unsafe fn [`from_borrowed_ptr_or_opt`](#method.from_borrowed_ptr_or_opt).
|
2020-02-09 07:35:52 +00:00
|
|
|
unsafe fn from_borrowed_ptr_or_panic(py: Python<'p>, ptr: *mut ffi::PyObject) -> &'p Self {
|
2020-07-19 11:26:59 +00:00
|
|
|
Self::from_borrowed_ptr_or_opt(py, ptr).unwrap_or_else(|| err::panic_after_error(py))
|
2019-03-29 09:57:05 +00:00
|
|
|
}
|
2021-01-15 14:31:40 +00:00
|
|
|
/// Convert from an arbitrary borrowed `PyObject`.
|
|
|
|
///
|
|
|
|
/// # Safety
|
|
|
|
///
|
2021-01-16 14:11:11 +00:00
|
|
|
/// Relies on unsafe fn [`from_borrowed_ptr_or_opt`](#method.from_borrowed_ptr_or_opt).
|
2020-02-09 07:35:52 +00:00
|
|
|
unsafe fn from_borrowed_ptr(py: Python<'p>, ptr: *mut ffi::PyObject) -> &'p Self {
|
2019-03-29 09:57:05 +00:00
|
|
|
Self::from_borrowed_ptr_or_panic(py, ptr)
|
|
|
|
}
|
2021-01-15 14:31:40 +00:00
|
|
|
/// Convert from an arbitrary borrowed `PyObject`.
|
|
|
|
///
|
|
|
|
/// # Safety
|
|
|
|
///
|
2021-01-16 14:11:11 +00:00
|
|
|
/// Relies on unsafe fn [`from_borrowed_ptr_or_opt`](#method.from_borrowed_ptr_or_opt).
|
2020-02-09 07:35:52 +00:00
|
|
|
unsafe fn from_borrowed_ptr_or_err(
|
|
|
|
py: Python<'p>,
|
|
|
|
ptr: *mut ffi::PyObject,
|
|
|
|
) -> PyResult<&'p Self> {
|
2021-10-30 09:51:02 +00:00
|
|
|
Self::from_borrowed_ptr_or_opt(py, ptr).ok_or_else(|| err::PyErr::fetch(py))
|
2019-03-29 09:57:05 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-09 07:35:52 +00:00
|
|
|
unsafe impl<'p, T> FromPyPointer<'p> for T
|
2019-03-29 09:57:05 +00:00
|
|
|
where
|
2020-02-09 07:35:52 +00:00
|
|
|
T: 'p + crate::PyNativeType,
|
2019-03-29 09:57:05 +00:00
|
|
|
{
|
2020-02-09 07:35:52 +00:00
|
|
|
unsafe fn from_owned_ptr_or_opt(py: Python<'p>, ptr: *mut ffi::PyObject) -> Option<&'p Self> {
|
2020-05-01 16:09:10 +00:00
|
|
|
gil::register_owned(py, NonNull::new(ptr)?);
|
|
|
|
Some(&*(ptr as *mut Self))
|
2020-02-09 07:35:52 +00:00
|
|
|
}
|
|
|
|
unsafe fn from_borrowed_ptr_or_opt(
|
2020-05-01 16:09:10 +00:00
|
|
|
_py: Python<'p>,
|
2020-02-15 04:42:25 +00:00
|
|
|
ptr: *mut ffi::PyObject,
|
|
|
|
) -> Option<&'p Self> {
|
2020-05-01 16:09:10 +00:00
|
|
|
NonNull::new(ptr as *mut Self).map(|p| &*p.as_ptr())
|
2020-02-15 04:42:25 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-07-02 15:08:01 +00:00
|
|
|
/// ```rust,compile_fail
|
|
|
|
/// use pyo3::prelude::*;
|
|
|
|
///
|
|
|
|
/// #[pyclass]
|
|
|
|
/// struct TestClass {
|
|
|
|
/// num: u32,
|
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// let t = TestClass { num: 10 };
|
|
|
|
///
|
|
|
|
/// Python::with_gil(|py| {
|
|
|
|
/// let pyvalue = Py::new(py, t).unwrap().to_object(py);
|
|
|
|
/// let t: TestClass = pyvalue.extract(py).unwrap();
|
|
|
|
/// })
|
|
|
|
/// ```
|
|
|
|
mod test_no_clone {}
|
|
|
|
|
2018-12-01 15:12:27 +00:00
|
|
|
#[cfg(test)]
|
2021-07-26 17:19:53 +00:00
|
|
|
mod tests {
|
2020-11-15 15:10:56 +00:00
|
|
|
use crate::types::{IntoPyDict, PyAny, PyDict, PyList};
|
2023-07-30 20:58:21 +00:00
|
|
|
use crate::{PyObject, Python, ToPyObject};
|
2018-12-01 15:12:27 +00:00
|
|
|
|
2019-02-23 17:01:22 +00:00
|
|
|
use super::PyTryFrom;
|
|
|
|
|
2020-11-15 15:10:56 +00:00
|
|
|
#[test]
|
|
|
|
fn test_try_from() {
|
2021-08-12 00:47:41 +00:00
|
|
|
Python::with_gil(|py| {
|
|
|
|
let list: &PyAny = vec![3, 6, 5, 4, 7].to_object(py).into_ref(py);
|
|
|
|
let dict: &PyAny = vec![("reverse", true)].into_py_dict(py).as_ref();
|
2020-11-15 15:10:56 +00:00
|
|
|
|
2022-03-23 07:07:28 +00:00
|
|
|
assert!(<PyList as PyTryFrom<'_>>::try_from(list).is_ok());
|
|
|
|
assert!(<PyDict as PyTryFrom<'_>>::try_from(dict).is_ok());
|
2020-11-15 15:10:56 +00:00
|
|
|
|
2022-03-23 07:07:28 +00:00
|
|
|
assert!(<PyAny as PyTryFrom<'_>>::try_from(list).is_ok());
|
|
|
|
assert!(<PyAny as PyTryFrom<'_>>::try_from(dict).is_ok());
|
2021-08-12 00:47:41 +00:00
|
|
|
});
|
2020-11-15 15:10:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_try_from_exact() {
|
2021-08-12 00:47:41 +00:00
|
|
|
Python::with_gil(|py| {
|
|
|
|
let list: &PyAny = vec![3, 6, 5, 4, 7].to_object(py).into_ref(py);
|
|
|
|
let dict: &PyAny = vec![("reverse", true)].into_py_dict(py).as_ref();
|
2020-11-15 15:10:56 +00:00
|
|
|
|
2021-08-12 00:47:41 +00:00
|
|
|
assert!(PyList::try_from_exact(list).is_ok());
|
|
|
|
assert!(PyDict::try_from_exact(dict).is_ok());
|
2020-11-15 15:10:56 +00:00
|
|
|
|
2021-08-12 00:47:41 +00:00
|
|
|
assert!(PyAny::try_from_exact(list).is_err());
|
|
|
|
assert!(PyAny::try_from_exact(dict).is_err());
|
|
|
|
});
|
2020-11-15 15:10:56 +00:00
|
|
|
}
|
|
|
|
|
2018-12-01 15:12:27 +00:00
|
|
|
#[test]
|
|
|
|
fn test_try_from_unchecked() {
|
2021-08-12 00:47:41 +00:00
|
|
|
Python::with_gil(|py| {
|
2023-06-05 06:08:27 +00:00
|
|
|
let list = PyList::new(py, [1, 2, 3]);
|
2021-08-12 00:47:41 +00:00
|
|
|
let val = unsafe { <PyList as PyTryFrom>::try_from_unchecked(list.as_ref()) };
|
2022-02-25 19:39:45 +00:00
|
|
|
assert!(list.is(val));
|
2021-08-12 00:47:41 +00:00
|
|
|
});
|
2018-12-01 15:12:27 +00:00
|
|
|
}
|
2022-02-11 22:17:00 +00:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_option_as_ptr() {
|
|
|
|
Python::with_gil(|py| {
|
2023-07-30 20:58:21 +00:00
|
|
|
use crate::AsPyPointer;
|
2022-02-11 22:17:00 +00:00
|
|
|
let mut option: Option<PyObject> = None;
|
|
|
|
assert_eq!(option.as_ptr(), std::ptr::null_mut());
|
|
|
|
|
|
|
|
let none = py.None();
|
|
|
|
option = Some(none.clone());
|
|
|
|
|
|
|
|
let ref_cnt = none.get_refcnt(py);
|
|
|
|
assert_eq!(option.as_ptr(), none.as_ptr());
|
|
|
|
|
|
|
|
// Ensure ref count not changed by as_ptr call
|
|
|
|
assert_eq!(none.get_refcnt(py), ref_cnt);
|
2021-08-12 00:47:41 +00:00
|
|
|
});
|
2018-12-01 15:12:27 +00:00
|
|
|
}
|
|
|
|
}
|