Merge pull request #1620 from mejrs/pyany

pyany documentation
This commit is contained in:
David Hewitt 2021-05-21 07:19:32 +01:00 committed by GitHub
commit c168466d1f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -11,31 +11,28 @@ use std::cell::UnsafeCell;
use std::cmp::Ordering;
use std::os::raw::c_int;
/// A Python object with GIL lifetime
/// Represents any Python object.
///
/// Represents any Python object. All Python objects can be cast to `PyAny`.
/// In addition, if the inner object is an instance of type `T`, we can downcast
/// `PyAny` into `T`.
/// It currently only appears as a *reference*, `&PyAny`,
/// with a lifetime that represents the scope during which the GIL is held.
///
/// `PyAny` is used as a reference with a lifetime that represents that the GIL
/// is held, therefore its API does not require a `Python<'py>` token.
/// `PyAny` has some interesting properties, which it shares
/// with the other [native Python types](crate::types):
///
/// - It can only be obtained and used while the GIL is held,
/// therefore its API does not require a [`Python<'py>`](crate::Python) token.
/// - It can't be used in situations where the GIL is temporarily released,
/// such as [`Python::allow_threads`](crate::Python::allow_threads)'s closure.
/// - The underlying Python object, if mutable, can be mutated through any reference.
/// - It can be converted to the GIL-independent [`Py`]`<`[`PyAny`]`>`,
/// allowing it to outlive the GIL scope. However, using [`Py`]`<`[`PyAny`]`>`'s API
/// *does* require a [`Python<'py>`](crate::Python) token.
///
/// It can be cast to a concrete type with PyAny::downcast (for native Python types only)
/// and FromPyObject::extract. See their documentation for more information.
///
/// See [the guide](https://pyo3.rs/main/types.html) for an explanation
/// of the different Python object types.
///
/// # Examples
///
/// ```
/// use pyo3::prelude::*;
/// use pyo3::types::{PyAny, PyDict, PyList};
/// Python::with_gil(|py| {
/// let dict = PyDict::new(py);
/// assert!(dict.is_instance::<PyAny>().unwrap());
/// let any: &PyAny = dict.as_ref();
/// assert!(any.downcast::<PyDict>().is_ok());
/// assert!(any.downcast::<PyList>().is_err());
/// });
/// ```
#[repr(transparent)]
pub struct PyAny(UnsafeCell<ffi::PyObject>);
@ -67,7 +64,22 @@ pyobject_native_type_extract!(PyAny);
pyobject_native_type_sized!(PyAny, ffi::PyObject);
impl PyAny {
/// Convert this PyAny to a concrete Python type.
/// Converts this `PyAny` to a concrete Python type.
///
/// # Examples
///
/// ```rust
/// use pyo3::prelude::*;
/// use pyo3::types::{PyAny, PyDict, PyList};
///
/// Python::with_gil(|py| {
/// let dict = PyDict::new(py);
/// assert!(dict.is_instance::<PyAny>().unwrap());
/// let any: &PyAny = dict.as_ref();
/// assert!(any.downcast::<PyDict>().is_ok());
/// assert!(any.downcast::<PyList>().is_err());
/// });
/// ```
pub fn downcast<T>(&self) -> Result<&T, PyDowncastError>
where
for<'py> T: PyTryFrom<'py>,
@ -130,9 +142,9 @@ impl PyAny {
})
}
/// Compares two Python objects.
/// Returns an [`Ordering`] between `self` and `other`.
///
/// This is equivalent to:
/// This is equivalent to the following Python code:
/// ```python
/// if self == other:
/// return Equal
@ -143,6 +155,39 @@ impl PyAny {
/// else:
/// raise TypeError("PyAny::compare(): All comparisons returned false")
/// ```
///
/// # Examples
///
/// ```rust
/// use pyo3::prelude::*;
/// use pyo3::types::PyFloat;
/// use std::cmp::Ordering;
///
/// # fn main() -> PyResult<()> {
/// Python::with_gil(|py| -> PyResult<()> {
/// let a = PyFloat::new(py, 0_f64);
/// let b = PyFloat::new(py, 42_f64);
/// assert_eq!(a.compare(b)?, Ordering::Less);
/// Ok(())
/// })?;
/// # Ok(())}
/// ```
///
/// It will return `PyErr` for values that cannot be compared:
///
/// ```rust
/// use pyo3::prelude::*;
/// use pyo3::types::{PyFloat, PyString};
///
/// # fn main() -> PyResult<()> {
/// Python::with_gil(|py| -> PyResult<()> {
/// let a = PyFloat::new(py, 0_f64);
/// let b = PyString::new(py, "zero");
/// assert!(a.compare(b).is_err());
/// Ok(())
/// })?;
/// # Ok(())}
/// ```
pub fn compare<O>(&self, other: O) -> PyResult<Ordering>
where
O: ToPyObject,
@ -169,16 +214,40 @@ impl PyAny {
})
}
/// Compares two Python objects.
/// Tests whether two Python objects obey a given [`CompareOp`].
///
/// Depending on the value of `compare_op`, this is equivalent to one of the
/// following Python expressions:
/// * CompareOp::Eq: `self == other`
/// * CompareOp::Ne: `self != other`
/// * CompareOp::Lt: `self < other`
/// * CompareOp::Le: `self <= other`
/// * CompareOp::Gt: `self > other`
/// * CompareOp::Ge: `self >= other`
///
/// <div style="width:1px">
///
/// | `compare_op` | <span style="white-space: pre">Python expression</span> |
/// | :---: | :----: |
/// | [`CompareOp::Eq`] | <span style="white-space: pre">`self == other`</span> |
/// | [`CompareOp::Ne`] | <span style="white-space: pre">`self != other`</span> |
/// | [`CompareOp::Lt`] | <span style="white-space: pre">`self < other`</span> |
/// | [`CompareOp::Le`] | <span style="white-space: pre">`self <= other`</span> |
/// | [`CompareOp::Gt`] | <span style="white-space: pre">`self > other`</span> |
/// | [`CompareOp::Ge`] | <span style="white-space: pre">`self >= other`</span> |
///
/// </div>
///
/// # Examples
///
/// ```rust
/// use pyo3::prelude::*;
/// use pyo3::types::PyInt;
/// use pyo3::class::basic::CompareOp;
///
/// # fn main() -> PyResult<()> {
/// Python::with_gil(|py| -> PyResult<()> {
/// let a: &PyInt = 0_u8.into_py(py).into_ref(py).downcast()?;
/// let b: &PyInt = 42_u8.into_py(py).into_ref(py).downcast()?;
/// assert!(a.rich_compare(b, CompareOp::Le)?.is_true()?);
/// Ok(())
/// })?;
/// # Ok(())}
/// ```
pub fn rich_compare<O>(&self, other: O, compare_op: CompareOp) -> PyResult<&PyAny>
where
O: ToPyObject,