documentation updates for `PyList::new_bound`

This commit is contained in:
David Hewitt 2024-01-23 09:23:30 +00:00
parent 57a49a2b12
commit 1657109ae0
8 changed files with 33 additions and 20 deletions

View File

@ -13,7 +13,7 @@ fails, so usually you will use something like
# use pyo3::types::PyList;
# fn main() -> PyResult<()> {
# Python::with_gil(|py| {
# let list = PyList::new(py, b"foo");
# let list = PyList::new_bound(py, b"foo");
let v: Vec<i32> = list.extract()?;
# assert_eq!(&v, &[102, 111, 111]);
# Ok(())

View File

@ -75,12 +75,12 @@ Python has an [`isinstance`](https://docs.python.org/3/library/functions.html#is
In PyO3 every object has the [`PyAny::is_instance`] and [`PyAny::is_instance_of`] methods which do the same thing.
```rust
use pyo3::Python;
use pyo3::prelude::*;
use pyo3::types::{PyBool, PyList};
Python::with_gil(|py| {
assert!(PyBool::new(py, true).is_instance_of::<PyBool>());
let list = PyList::new(py, &[1, 2, 3, 4]);
let list = PyList::new_bound(py, &[1, 2, 3, 4]);
assert!(!list.is_instance_of::<PyBool>());
assert!(list.is_instance_of::<PyList>());
});

View File

@ -45,7 +45,7 @@ pyo3 = { version = "0.21", features = ["gil-refs"] }
The `PyTryFrom` trait has aged poorly, its [`try_from`] method now conflicts with `try_from` in the 2021 edition prelude. A lot of its functionality was also duplicated with `PyTypeInfo`.
To tighten up the PyO3 traits ahead of [a proposed upcoming API change](https://github.com/PyO3/pyo3/issues/3382) the `PyTypeInfo` trait has had a simpler companion `PyTypeCheck`. The methods [`PyAny::downcast`]({{#PYO3_DOCS_URL}}/pyo3/types/struct.PyAny.html#method.downcast) and [`PyAny::downcast_exact`]({{#PYO3_DOCS_URL}}/pyo3/types/struct.PyAny.html#method.downcast_exact) no longer use `PyTryFrom` as a bound, instead using `PyTypeCheck` and `PyTypeInfo` respectively.
To tighten up the PyO3 traits as part of the deprecation of the GIL Refs API the `PyTypeInfo` trait has had a simpler companion `PyTypeCheck`. The methods [`PyAny::downcast`]({{#PYO3_DOCS_URL}}/pyo3/types/struct.PyAny.html#method.downcast) and [`PyAny::downcast_exact`]({{#PYO3_DOCS_URL}}/pyo3/types/struct.PyAny.html#method.downcast_exact) no longer use `PyTryFrom` as a bound, instead using `PyTypeCheck` and `PyTypeInfo` respectively.
To migrate, switch all type casts to use `obj.downcast()` instead of `try_from(obj)` (and similar for `downcast_exact`).
@ -71,6 +71,9 @@ After:
# use pyo3::types::{PyInt, PyList};
# fn main() -> PyResult<()> {
Python::with_gil(|py| {
// Note that PyList::new is deprecated for PyList::new_bound as part of the GIL Refs API removal,
// see the section below on migration to Bound<T>.
#[allow(deprecated)]
let list = PyList::new(py, 0..5);
let b = list.get_item(0).unwrap().downcast::<PyInt>()?;
Ok(())
@ -234,7 +237,15 @@ impl PyClassAsyncIter {
### Migrating from the GIL-Refs API to `Bound<T>`
TODO
To minimise breakage of code using the GIL-Refs API, the `Bound<T>` smart pointer has been introduced by adding complements to all functions which accept or return GIL Refs. This allows code to migrate by replacing the deprecated APIs with the new ones.
For example, the following APIs have gained updated variants:
- `PyList::new`, `PyTyple::new` and similar constructors have replacements `PyList::new_bound`, `PyTuple::new_bound` etc.
Because the new `Bound<T>` API brings ownership out of the PyO3 framework and into user code, there are a few places where user code is expected to need to adjust while switching to the new API:
- Code will need to add the occasional `&` to borrow the new smart pointer as `&Bound<T>` to pass these types around (or use `.clone()` at the very small cost of increasing the Python reference count)
- `Bound<PyList>` and `Bound<PyTuple>` cannot support indexing with `list[0]`, you should use `list.get_item(0)` instead.
- `Bound<PyTuple>::iter_borrowed` is slightly more efficient than `Bound<PyTuple>::iter`. The default iteration of `Bound<PyTuple>` cannot return borrowed references because Rust does not (yet) have "lending iterators".
## from 0.19.* to 0.20
@ -853,6 +864,7 @@ that these types can now also support Rust's indexing operators as part of a
consistent API:
```rust
#![allow(deprecated)]
use pyo3::{Python, types::PyList};
Python::with_gil(|py| {
@ -1073,7 +1085,7 @@ This should require no code changes except removing `use pyo3::AsPyRef` for code
`pyo3::prelude::*`.
Before:
```rust,compile_fail
```rust,ignore
use pyo3::{AsPyRef, Py, types::PyList};
# pyo3::Python::with_gil(|py| {
let list_py: Py<PyList> = PyList::empty(py).into();
@ -1082,7 +1094,7 @@ let list_ref: &PyList = list_py.as_ref(py);
```
After:
```rust
```rust,ignore
use pyo3::{Py, types::PyList};
# pyo3::Python::with_gil(|py| {
let list_py: Py<PyList> = PyList::empty(py).into();

View File

@ -71,6 +71,7 @@ a list:
# use pyo3::prelude::*;
# use pyo3::types::PyList;
# Python::with_gil(|py| -> PyResult<()> {
#[allow(deprecated)] // PyList::empty is part of the deprecated "GIL Refs" API.
let obj: &PyAny = PyList::empty(py);
// To &PyList with PyAny::downcast
@ -133,6 +134,7 @@ To see all Python types exposed by `PyO3` you should consult the
# use pyo3::prelude::*;
# use pyo3::types::PyList;
# Python::with_gil(|py| -> PyResult<()> {
#[allow(deprecated)] // PyList::empty is part of the deprecated "GIL Refs" API.
let list = PyList::empty(py);
// Use methods from PyAny on all Python types with Deref implementation
@ -173,7 +175,7 @@ For a `Py<PyList>`, the conversions are as below:
# use pyo3::prelude::*;
# use pyo3::types::PyList;
# Python::with_gil(|py| {
let list: Py<PyList> = PyList::empty(py).into();
let list: Py<PyList> = PyList::empty_bound(py).unbind();
// To &PyList with Py::as_ref() (borrows from the Py)
let _: &PyList = list.as_ref(py);

View File

@ -615,10 +615,9 @@ where
/// # use pyo3::types::PyList;
/// #
/// Python::with_gil(|py| {
/// let list: Py<PyList> = PyList::empty(py).into();
/// // FIXME as_ref() no longer makes sense with new Py API, remove this doc
/// // let list: &PyList = list.as_ref(py);
/// // assert_eq!(list.len(), 0);
/// let list: Py<PyList> = PyList::empty_bound(py).into();
/// let list: &PyList = list.as_ref(py);
/// assert_eq!(list.len(), 0);
/// });
/// ```
///

View File

@ -12,7 +12,7 @@
/// use pyo3::{prelude::*, py_run, types::PyList};
///
/// Python::with_gil(|py| {
/// let list = PyList::new(py, &[1, 2, 3]);
/// let list = PyList::new_bound(py, &[1, 2, 3]);
/// py_run!(py, list, "assert list == [1, 2, 3]");
/// });
/// ```

View File

@ -75,10 +75,10 @@ unsafe impl<T> Sync for GILProtected<T> where T: Send {}
///
/// static LIST_CELL: GILOnceCell<Py<PyList>> = GILOnceCell::new();
///
/// pub fn get_shared_list(py: Python<'_>) -> &PyList {
/// pub fn get_shared_list(py: Python<'_>) -> &Bound<'_, PyList> {
/// LIST_CELL
/// .get_or_init(py, || PyList::empty(py).into())
/// .as_ref(py)
/// .get_or_init(py, || PyList::empty_bound(py).unbind())
/// .bind(py)
/// }
/// # Python::with_gil(|py| assert_eq!(get_shared_list(py).len(), 0));
/// ```

View File

@ -88,7 +88,7 @@ impl PyList {
/// # fn main() {
/// Python::with_gil(|py| {
/// let elements: Vec<i32> = vec![0, 1, 2, 3, 4, 5];
/// let list: &PyList = PyList::new(py, elements);
/// let list = PyList::new_bound(py, elements);
/// assert_eq!(format!("{:?}", list), "[0, 1, 2, 3, 4, 5]");
/// });
/// # }
@ -154,7 +154,7 @@ impl PyList {
/// ```
/// use pyo3::{prelude::*, types::PyList};
/// Python::with_gil(|py| {
/// let list = PyList::new(py, [2, 3, 5, 7]);
/// let list = PyList::new_bound(py, [2, 3, 5, 7]);
/// let obj = list.get_item(0);
/// assert_eq!(obj.unwrap().extract::<i32>().unwrap(), 2);
/// });
@ -301,7 +301,7 @@ pub trait PyListMethods<'py> {
/// ```
/// use pyo3::{prelude::*, types::PyList};
/// Python::with_gil(|py| {
/// let list = PyList::new(py, [2, 3, 5, 7]);
/// let list = PyList::new_bound(py, [2, 3, 5, 7]);
/// let obj = list.get_item(0);
/// assert_eq!(obj.unwrap().extract::<i32>().unwrap(), 2);
/// });
@ -414,7 +414,7 @@ impl<'py> PyListMethods<'py> for Bound<'py, PyList> {
/// ```
/// use pyo3::{prelude::*, types::PyList};
/// Python::with_gil(|py| {
/// let list = PyList::new(py, [2, 3, 5, 7]);
/// let list = PyList::new_bound(py, [2, 3, 5, 7]);
/// let obj = list.get_item(0);
/// assert_eq!(obj.unwrap().extract::<i32>().unwrap(), 2);
/// });