Skip to content

Commit

Permalink
FromPyObject docs take 2
Browse files Browse the repository at this point in the history
  • Loading branch information
Icxolu committed Aug 30, 2024
1 parent c467e71 commit 91ef5fe
Showing 1 changed file with 32 additions and 34 deletions.
66 changes: 32 additions & 34 deletions src/conversion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -409,8 +409,8 @@ impl<'a, 'py, T> IntoPyObject<'py> for &'a Py<T> {
/// Extract a type from a Python object.
///
///
/// Normal usage is through the `extract` methods on [`Bound`], [`Borrowed`] and
/// [`Py`], which forward to this trait.
/// Normal usage is through the `extract` methods on [`Bound`], [`Borrowed`] and [`Py`], which
/// forward to this trait.
///
/// # Examples
///
Expand All @@ -434,38 +434,27 @@ impl<'a, 'py, T> IntoPyObject<'py> for &'a Py<T> {
/// # }
/// ```
///
/// Note: depending on the implementation, the extracted result may depend on
/// the Python lifetime `'py` or the input lifetime `'a` of `obj`.
///
/// For example, when extracting a [`Cow<'a, str>`] the result may or may not
/// borrow from the input lifetime `'a`. The behavior depends on the runtime
/// type of the Python object. For a Python byte string, the existing string
/// data can be borrowed (lifetime: `'a`) into a [`Cow::Borrowed`]. For a Python
/// Unicode string, the data may have to be reencoded to UTF-8, and copied into
/// a [`Cow::Owned`]. It does _not_ depend on the Python lifetime `'py`
///
/// An example of a type depending on the Python lifetime `'py` would be
/// [`Bound<'py, PyString>`]. This type holds the invariant of beeing allowed to
/// interact with the Python interpreter, so it inherits the Python lifetime
/// from the input. It is however _not_ tied to the input lifetime `'a` and can
/// be passed around independently of `obj`.
///
/// Special care needs to be taken for collection types, for example [`PyList`].
/// In contrast to a Rust's [`Vec`] a Python list will not hand out references
/// tied to its own lifetime, but "owned" references independent of it. (Similar
/// to [`Vec<Arc<T>>`] where you clone the [`Arc<T>`] out). This makes it
/// impossible to collect borrowed types in a collection, since they would not
/// borrow from the original input list, but the much shorter lived element
/// reference. This restriction is represented in PyO3 using
/// [`FromPyObjectOwned`]. It is used by [`FromPyObject`] implementations on
/// collection types to specify it can only collect types which do _not_ borrow
/// from the input.
/// Note: Depending on the Python version and implementation, some [`FromPyObject`] implementations
/// may produce a result that borrows into the Python type. This is described by the input lifetime
/// `'a` of `obj`.
///
/// Types that must not borrow from the input can use [`FromPyObjectOwned`] as a restriction. This
/// is most often the case for collection types. See its documentation for more details.
///
/// # Details
/// [`Cow<'a, str>`] is an example of an output type that may or may not borrow from the input
/// lifetime `'a`. Which variant will be produced depends on the runtime type of the Python object.
/// For a Python byte string, the existing string data can be borrowed for `'a` into a
/// [`Cow::Borrowed`]. For a Python Unicode string, the data may have to be reencoded to UTF-8, and
/// copied into a [`Cow::Owned`]. It does _not_ depend on the Python lifetime `'py`.
///
/// The output type may also depend on the Python lifetime `'py`. This allows the output type to
/// keep interacting with the Python interpreter. See also [`Bound<'py, T>`].
///
/// [`Cow<'a, str>`]: std::borrow::Cow
/// [`Cow::Borrowed`]: std::borrow::Cow::Borrowed
/// [`Cow::Owned`]: std::borrow::Cow::Owned
/// [`PyList`]: crate::types::PyList
/// [`Arc<T>`]: std::sync::Arc

pub trait FromPyObject<'a, 'py>: Sized {
/// Extracts `Self` from the bound smart pointer `obj`.
///
Expand All @@ -492,11 +481,17 @@ pub trait FromPyObject<'a, 'py>: Sized {
}
}

/// A data structure that can be extracted without borrowing any data from the input
/// A data structure that can be extracted without borrowing any data from the input.
///
/// This is primarily useful for trait bounds. For example a [`FromPyObject`] implementation of a
/// wrapper type may be able to borrow data from the input, but a [`FromPyObject`] implementation of
/// a collection type may only extract owned data.
///
/// This is primarily useful for trait bounds. For example a `FromPyObject` implementation of a
/// wrapper type may be able to borrow data from the input, but a `FromPyObject` implementation of a
/// collection type may only extract owned data.
/// For example [`PyList`] will not hand out references tied to its own lifetime, but "owned"
/// references independent of it. (Similar to [`Vec<Arc<T>>`] where you clone the [`Arc<T>`] out).
/// This makes it impossible to collect borrowed types in a collection, since they would not borrow
/// from the original [`PyList`], but the much shorter lived element reference. See the example
/// below.
///
/// ```
/// # use pyo3::prelude::*;
Expand Down Expand Up @@ -527,6 +522,9 @@ pub trait FromPyObject<'a, 'py>: Sized {
/// }
/// }
/// ```
///
/// [`PyList`]: crate::types::PyList
/// [`Arc<T>`]: std::sync::Arc
pub trait FromPyObjectOwned<'py>: for<'a> FromPyObject<'a, 'py> {}
impl<'py, T> FromPyObjectOwned<'py> for T where T: for<'a> FromPyObject<'a, 'py> {}

Expand Down

0 comments on commit 91ef5fe

Please sign in to comment.