Remove AsPyRef for just Py::as_ref

This commit is contained in:
David Hewitt 2020-08-09 22:47:54 +01:00
parent bcb90775b4
commit 77ed6d6d69
19 changed files with 92 additions and 76 deletions

View File

@ -122,7 +122,7 @@ fn return_myclass() -> Py<MyClass> {
}
let gil = Python::acquire_gil();
let obj = return_myclass();
let cell = obj.as_ref(gil.python()); // AsPyRef::as_ref returns &PyCell
let cell = obj.as_ref(gil.python()); // Py<MyClass>::as_ref returns &PyCell<MyClass>
let obj_ref = cell.borrow(); // Get PyRef<T>
assert_eq!(obj_ref.num, 1);
```

View File

@ -46,7 +46,7 @@ There are also a few special types related to the GIL and Rust-defined `#[pyclas
| What | Description |
| ------------- | ------------------------------------- |
| `Python` | A GIL token, used to pass to PyO3 constructors to prove ownership of the GIL |
| `Py<T>` | A Python object isolated from the GIL lifetime. This can be sent to other threads. To call Python APIs using this object, it must be used with `AsPyRef::as_ref` to get an `&T` reference bound to the GIL. |
| `Py<T>` | A Python object isolated from the GIL lifetime. This can be sent to other threads. |
| `PyObject` | An alias for `Py<PyAny>` |
| `&PyCell<T>` | A `#[pyclass]` value owned by Python. |
| `PyRef<T>` | A `#[pyclass]` borrowed immutably. |

View File

@ -14,7 +14,6 @@ Now, the canonical implementation is always `IntoPy`, so downstream crates may n
accordingly.
Before:
```rust,ignore
# use pyo3::prelude::*;
struct MyPyObjectWrapper(PyObject);
@ -27,7 +26,6 @@ impl FromPy<MyPyObjectWrapper> for PyObject {
```
After
```rust
# use pyo3::prelude::*;
struct MyPyObjectWrapper(PyObject);
@ -42,7 +40,6 @@ impl IntoPy<PyObject> for MyPyObjectWrapper {
Similarly, code which was using the `FromPy` trait can be trivially rewritten to use `IntoPy`.
Before:
```rust,ignore
# use pyo3::prelude::*;
# Python::with_gil(|py| {
@ -62,6 +59,30 @@ let obj: PyObject = 1.234.into_py(py);
This should change very little from a usage perspective. If you implemented traits for both
`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`.
Before:
```rust,ignore
use pyo3::{AsPyRef, Py, types::PyList};
# pyo3::Python::with_gil(|py| {
let list_py: Py<PyList> = PyList::empty(py).into();
let list_ref: &PyList = list_py.as_ref(py);
# })
```
After:
```rust
use pyo3::{Py, types::PyList};
# pyo3::Python::with_gil(|py| {
let list_py: Py<PyList> = PyList::empty(py).into();
let list_ref: &PyList = list_py.as_ref(py);
# })
```
## from 0.10.* to 0.11
### Stable Rust

View File

@ -140,7 +140,7 @@ 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 AsPyRef::as_ref(py)
// Access the native type using Py::as_ref(py)
// (For #[pyclass] types, as_ref() will return &PyCell<T>)
let _: &PyList = list.as_ref(py);

View File

@ -33,15 +33,23 @@ pub unsafe trait PyNativeType: Sized {
}
}
/// A Python object of known type.
/// A Python object of known type T.
///
/// Accessing this object is thread-safe, since any access to its API requires a
/// `Python<'py>` GIL token.
/// 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::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
/// [the `PyCell` guide entry](https://pyo3.rs/master/class.html#pycell-and-interior-mutability)
/// ).
/// - Use methods directly on `Py`, such as [`Py::call`](#method.call) and
/// [`Py::call_method`](#method.call_method).
///
/// See [the guide](https://pyo3.rs/master/types.html) for an explanation
/// of the different Python object types.
///
/// Technically, it is a safe wrapper around `NonNull<ffi::PyObject>` with
/// `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>);
@ -63,7 +71,52 @@ where
let ob = unsafe { Py::from_owned_ptr(py, obj as _) };
Ok(ob)
}
}
impl<T> Py<T>
where
T: PyTypeInfo,
{
/// Borrows a GIL-bound reference to the contained `T`. By binding to the GIL lifetime, this
/// allows the GIL-bound reference to not require `Python` for any of its methods.
///
/// For native types, this reference is `&T`. For pyclasses, this is `&PyCell<T>`.
///
/// # Examples
/// Get access to `&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.as_ref(py);
/// assert_eq!(list.len(), 0);
/// # });
/// ```
///
/// Get access to `&PyCell<MyClass>` from `Py<MyClass>`:
///
/// ```
/// # 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.as_ref(py);
/// assert!(my_class_cell.try_borrow().is_ok());
/// # });
/// ```
pub fn as_ref<'py>(&'py self, _py: Python<'py>) -> &'py T::AsRefTarget {
let any = self.as_ptr() as *const PyAny;
unsafe { PyNativeType::unchecked_downcast(&*any) }
}
}
impl<T> Py<T>
where
T: PyClass,
{
/// Immutably borrows the value `T`. This borrow lasts untill the returned `PyRef` exists.
///
/// Equivalent to `self.as_ref(py).borrow()` -
@ -355,58 +408,6 @@ impl<T> Py<T> {
}
}
/// Retrieves `&'py` types from `Py<T>` or `PyObject`.
///
/// # Examples
/// `PyObject::as_ref` returns `&PyAny`.
/// ```
/// # use pyo3::prelude::*;
/// let obj: PyObject = {
/// let gil = Python::acquire_gil();
/// let py = gil.python();
/// py.eval("[]", None, None).unwrap().to_object(py)
/// };
/// let gil = Python::acquire_gil();
/// let py = gil.python();
/// assert_eq!(obj.as_ref(py).len().unwrap(), 0);
/// ```
///
/// `Py<T>::as_ref` returns `&PyDict`, `&PyList` or so for native types, and `&PyCell<T>`
/// for `#[pyclass]`.
/// ```
/// # use pyo3::prelude::*;
/// #[pyclass]
/// struct Counter {
/// count: usize,
/// }
/// let counter = {
/// let gil = Python::acquire_gil();
/// let py = gil.python();
/// Py::new(py, Counter { count: 0}).unwrap()
/// };
/// let gil = Python::acquire_gil();
/// let py = gil.python();
/// let counter_cell: &PyCell<Counter> = counter.as_ref(py);
/// let counter_ref = counter_cell.borrow();
/// assert_eq!(counter_ref.count, 0);
/// ```
pub trait AsPyRef: Sized {
type Target;
/// Return reference to object.
fn as_ref<'p>(&'p self, py: Python<'p>) -> &'p Self::Target;
}
impl<T> AsPyRef for Py<T>
where
T: PyTypeInfo,
{
type Target = T::AsRefTarget;
fn as_ref<'p>(&'p self, _py: Python<'p>) -> &'p Self::Target {
let any = self.as_ptr() as *const PyAny;
unsafe { PyNativeType::unchecked_downcast(&*any) }
}
}
impl<T> ToPyObject for Py<T> {
/// Converts `Py` instance -> PyObject.
fn to_object(&self, py: Python) -> PyObject {

View File

@ -140,7 +140,7 @@ pub use crate::conversion::{
};
pub use crate::err::{PyDowncastError, PyErr, PyErrArguments, PyErrValue, PyResult};
pub use crate::gil::{GILGuard, GILPool};
pub use crate::instance::{AsPyRef, Py, PyNativeType, PyObject};
pub use crate::instance::{Py, PyNativeType, PyObject};
pub use crate::pycell::{PyCell, PyRef, PyRefMut};
pub use crate::pyclass::PyClass;
pub use crate::pyclass_init::PyClassInitializer;

View File

@ -12,7 +12,7 @@
pub use crate::err::{PyErr, PyResult};
pub use crate::gil::GILGuard;
pub use crate::instance::{AsPyRef, Py, PyObject};
pub use crate::instance::{Py, PyObject};
pub use crate::pycell::{PyCell, PyRef, PyRefMut};
pub use crate::pyclass_init::PyClassInitializer;
pub use crate::python::Python;

View File

@ -98,7 +98,7 @@ pub unsafe trait PyTypeInfo: Sized {
/// Initializer for layout
type Initializer: PyObjectInit<Self>;
/// Utility type to make AsPyRef work
/// Utility type to make Py::as_ref work
type AsRefTarget: crate::PyNativeType;
/// PyTypeObject instance for this type.

View File

@ -357,7 +357,6 @@ where
#[cfg(test)]
mod test {
use crate::conversion::IntoPy;
use crate::instance::AsPyRef;
use crate::types::dict::IntoPyDict;
#[cfg(not(PyPy))]
use crate::types::PyList;

View File

@ -85,7 +85,6 @@ mod tests {
use super::PyIterator;
use crate::exceptions::PyTypeError;
use crate::gil::GILPool;
use crate::instance::AsPyRef;
use crate::types::{PyDict, PyList};
use crate::Python;
use crate::ToPyObject;

View File

@ -225,7 +225,6 @@ where
#[cfg(test)]
mod test {
use crate::instance::AsPyRef;
use crate::types::PyList;
use crate::Python;
use crate::{IntoPy, PyObject, PyTryFrom, ToPyObject};

View File

@ -326,7 +326,6 @@ mod bigint_conversion {
}
impl<'source> FromPyObject<'source> for $rust_ty {
fn extract(ob: &'source PyAny) -> PyResult<$rust_ty> {
use crate::instance::AsPyRef;
let py = ob.py();
unsafe {
let num = ffi::PyNumber_Index(ob.as_ptr());

View File

@ -396,7 +396,6 @@ impl<'v> PyTryFrom<'v> for PySequence {
#[cfg(test)]
mod test {
use crate::instance::AsPyRef;
use crate::types::PySequence;
use crate::AsPyPointer;
use crate::Python;

View File

@ -303,7 +303,7 @@ impl<'a> std::iter::IntoIterator for &'a PyFrozenSet {
#[cfg(test)]
mod test {
use super::{PyFrozenSet, PySet};
use crate::{AsPyRef, IntoPy, PyObject, PyTryFrom, Python, ToPyObject};
use crate::{IntoPy, PyObject, PyTryFrom, Python, ToPyObject};
use std::collections::{BTreeSet, HashSet};
use std::iter::FromIterator;

View File

@ -146,7 +146,6 @@ impl<'source> FromPyObject<'source> for String {
#[cfg(test)]
mod test {
use super::PyString;
use crate::instance::AsPyRef;
use crate::Python;
use crate::{FromPyObject, PyObject, PyTryFrom, ToPyObject};

View File

@ -242,7 +242,7 @@ tuple_conversion!(
#[cfg(test)]
mod test {
use crate::types::{PyAny, PyTuple};
use crate::{AsPyRef, PyTryFrom, Python, ToPyObject};
use crate::{PyTryFrom, Python, ToPyObject};
use std::collections::HashSet;
#[test]

View File

@ -1,7 +1,7 @@
//! Test slf: PyRef/PyMutRef<Self>(especially, slf.into::<Py>) works
use pyo3::prelude::*;
use pyo3::types::{PyBytes, PyString};
use pyo3::{AsPyRef, PyCell, PyIterProtocol};
use pyo3::{PyCell, PyIterProtocol};
use std::collections::HashMap;
mod common;

View File

@ -1,7 +1,7 @@
use pyo3::prelude::*;
use pyo3::types::IntoPyDict;
use pyo3::types::{PyDict, PyTuple};
use pyo3::{py_run, wrap_pyfunction, AsPyRef, PyCell};
use pyo3::{py_run, wrap_pyfunction, PyCell};
mod common;

View File

@ -1,4 +1,4 @@
use pyo3::{types::PyDict, AsPyRef, Py, PyNativeType, Python};
use pyo3::{types::PyDict, Py, PyNativeType, Python};
fn main() {
let gil = Python::acquire_gil();