Skip to content

Commit

Permalink
Improve docs for Py::as_ref() and Py::into_ref()
Browse files Browse the repository at this point in the history
Co-authored-by: Georg Brandl <georg@python.org>
  • Loading branch information
davidhewitt and birkenfeld committed Aug 10, 2020
1 parent 7d0b3b3 commit afcc149
Show file tree
Hide file tree
Showing 3 changed files with 26 additions and 29 deletions.
9 changes: 6 additions & 3 deletions guide/src/migration.md
Expand Up @@ -60,9 +60,12 @@ This should change very little from a usage perspective. If you implemented trai
`PyObject` and `Py<T>`, you may find you can just remove the `PyObject` implementation.

### `AsPyRef` has been removed
The only implementor of `AsPyRef` was `Py<T>`, so the `AsPyRef::as_ref` method has been moved to
`Py::as_ref`. This should require no code changes except removing the old `use` for code which
did not use `pyo3::prelude`.
As `PyObject` has been changed to be just a type alias, the only remaining implementor of `AsPyRef`
was `Py<T>`. This removed the need for a trait, so the `AsPyRef::as_ref` method has been moved to
`Py::as_ref`.

This should require no code changes except removing `use pyo3::AsPyRef` for code which did not use
`pyo3::prelude::*`.

Before:
```rust,ignore
Expand Down
13 changes: 10 additions & 3 deletions guide/src/types.md
Expand Up @@ -140,11 +140,18 @@ Can be cloned using Python reference counts with `.clone()`.
# let py = gil.python();
let list: Py<PyList> = PyList::empty(py).into();

// Access the native type using Py::as_ref(py) or Py::into_ref(py)
// (For #[pyclass] types, these will return &PyCell<T>)
// Access to the native type using Py::as_ref(py) or Py::into_ref(py)
// (For #[pyclass] types T, these will return &PyCell<T>)

// Py::as_ref() borrows the object
let _: &PyList = list.as_ref(py);
let _: &PyList = list.clone().into_ref(py);

# let list_clone = list.clone(); // Just so that the .into() example for PyObject compiles.
// Py::into_ref() moves the reference into pyo3's "object storage"; useful for making APIs
// which return gil-bound references.
let _: &PyList = list.into_ref(py);

# let list = list_clone;
// Convert to PyObject with .into()
let _: PyObject = list.into();
```
Expand Down
33 changes: 10 additions & 23 deletions src/instance.rs
Expand Up @@ -37,7 +37,7 @@ pub unsafe trait PyNativeType: Sized {
///
/// Accessing this object is thread-safe, since any access to its API requires a `Python<'py>` GIL
/// token. There are a few different ways to use the Python object contained:
/// - [`Py::as_ref`](#method.as_ref) to borrow a GIL-bound reference to the contained object,
/// - [`Py::as_ref`](#method.as_ref) to borrow a GIL-bound reference to the contained object.
/// - [`Py::borrow`](#method.borrow), [`Py::try_borrow`](#method.try_borrow),
/// [`Py::borrow_mut`](#method.borrow_mut), or [`Py::try_borrow_mut`](#method.try_borrow_mut),
/// to directly access a `#[pyclass]` value (which has RefCell-like behavior, see
Expand All @@ -48,9 +48,6 @@ pub unsafe trait PyNativeType: Sized {
///
/// See [the guide](https://pyo3.rs/master/types.html) for an explanation
/// of the different Python object types.
///
/// `Py<T>` is implemented as a safe wrapper around `NonNull<ffi::PyObject>` with
/// specified type information.
#[repr(transparent)]
pub struct Py<T>(NonNull<ffi::PyObject>, PhantomData<T>);

Expand Down Expand Up @@ -112,32 +109,22 @@ where
unsafe { PyNativeType::unchecked_downcast(&*any) }
}

/// Similar to [`as_ref`](#method.as_ref), but instead consumes this `Py` and registers the
/// Similar to [`as_ref`](#method.as_ref), and also consumes this `Py` and registers the
/// Python object reference in PyO3's object storage. The reference count for the Python
/// object will not be decreased until the GIL lifetime ends.
///
/// # Examples
/// Create `&PyList` from `Py<PyList>`:
/// ```
/// # use pyo3::prelude::*;
/// # use pyo3::types::PyList;
/// # Python::with_gil(|py| {
/// let list: Py<PyList> = PyList::empty(py).into();
/// let list: &PyList = list.into_ref(py);
/// assert_eq!(list.len(), 0);
/// # });
/// ```
///
/// Create `&PyCell<MyClass>` from `Py<MyClass>`:
/// Useful when returning GIL-bound references from functions:
/// ```
/// # use pyo3::prelude::*;
/// #[pyclass]
/// struct MyClass { }
/// # Python::with_gil(|py| {
/// let my_class: Py<MyClass> = Py::new(py, MyClass { }).unwrap();
/// let my_class_cell: &PyCell<MyClass> = my_class.into_ref(py);
/// assert!(my_class_cell.try_borrow().is_ok());
/// # });
/// fn new_py_any(py: Python, value: impl IntoPy<PyObject>) -> &PyAny {
/// let obj: PyObject = value.into_py(py);
///
/// // .as_ref(py) would not be suitable here, because a reference to `obj` may not be
/// // returned from the function.
/// obj.into_ref(py)
/// }
/// ```
pub fn into_ref(self, py: Python) -> &T::AsRefTarget {
unsafe { py.from_owned_ptr(self.into_ptr()) }
Expand Down

0 comments on commit afcc149

Please sign in to comment.