Rewrite documentation for FromPy and PyObject changes
This commit is contained in:
parent
f29e6bae7a
commit
20959ecc92
|
@ -44,10 +44,10 @@ The table below contains the Python type and the corresponding function argument
|
|||
There are also a few special types related to the GIL and Rust-defined `#[pyclass]`es which may come in useful:
|
||||
|
||||
| What | Description |
|
||||
| ------------- | ------------------------------- |
|
||||
| ------------- | ------------------------------------- |
|
||||
| `Python` | A GIL token, used to pass to PyO3 constructors to prove ownership of the GIL |
|
||||
| `PyObject` | 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 a `&PyAny` reference. |
|
||||
| `Py<T>` | Same as above, for a specific Python type or `#[pyclass]` T. |
|
||||
| `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. |
|
||||
| `PyObject` | An alias for `Py<PyAny>` |
|
||||
| `&PyCell<T>` | A `#[pyclass]` value owned by Python. |
|
||||
| `PyRef<T>` | A `#[pyclass]` borrowed immutably. |
|
||||
| `PyRefMut<T>` | A `#[pyclass]` borrowed mutably. |
|
||||
|
@ -119,6 +119,28 @@ mutable references, you have to extract the PyO3 reference wrappers [`PyRef`]
|
|||
and [`PyRefMut`]. They work like the reference wrappers of
|
||||
`std::cell::RefCell` and ensure (at runtime) that Rust borrows are allowed.
|
||||
|
||||
### `IntoPy<T>`
|
||||
|
||||
This trait defines the to-python conversion for a Rust type. It is usually implemented as
|
||||
`IntoPy<PyObject>`, which is the trait needed for returning a value from `#[pyfunction]` and
|
||||
`#[pymethods]`.
|
||||
|
||||
All types in PyO3 implement this trait, as does a `#[pyclass]` which doesn't use `extends`.
|
||||
|
||||
Occasionally you may choose to implement this for custom types which are mapped to Python types
|
||||
_without_ having a unique python type.
|
||||
|
||||
```
|
||||
use pyo3::prelude::*;
|
||||
|
||||
struct MyPyObjectWrapper(PyObject);
|
||||
|
||||
impl IntoPy<PyObject> for MyPyObjectWrapper {
|
||||
fn into_py(self, py: Python) -> PyObject {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### The `ToPyObject` trait
|
||||
|
||||
|
@ -216,22 +238,10 @@ fn main() {
|
|||
}
|
||||
```
|
||||
|
||||
### `FromPy<T>` and `IntoPy<T>`
|
||||
|
||||
Many conversions in PyO3 can't use `std::convert::From` because they need a GIL token.
|
||||
The [`FromPy`] trait offers an `from_py` method that works just like `from`, except for taking a `Python<'_>` argument.
|
||||
I.e. `FromPy<T>` could be converting a Rust object into a Python object even though it is called [`FromPy`] - it doesn't say anything about which side of the conversion is a Python object.
|
||||
|
||||
Just like `From<T>`, if you implement `FromPy<T>` you gain a blanket implementation of [`IntoPy`] for free.
|
||||
|
||||
Eventually, traits such as [`ToPyObject`] will be replaced by this trait and a [`FromPy`] trait will be added that will implement
|
||||
[`IntoPy`], just like with `From` and `Into`.
|
||||
|
||||
[`IntoPy`]: https://docs.rs/pyo3/latest/pyo3/conversion/trait.IntoPy.html
|
||||
[`FromPy`]: https://docs.rs/pyo3/latest/pyo3/conversion/trait.FromPy.html
|
||||
[`FromPyObject`]: https://docs.rs/pyo3/latest/pyo3/conversion/trait.FromPyObject.html
|
||||
[`ToPyObject`]: https://docs.rs/pyo3/latest/pyo3/conversion/trait.ToPyObject.html
|
||||
[`PyObject`]: https://docs.rs/pyo3/latest/pyo3/struct.PyObject.html
|
||||
[`PyObject`]: https://docs.rs/pyo3/latest/pyo3/type.PyObject.html
|
||||
[`PyTuple`]: https://docs.rs/pyo3/latest/pyo3/types/struct.PyTuple.html
|
||||
[`PyAny`]: https://docs.rs/pyo3/latest/pyo3/struct.PyAny.html
|
||||
[`IntoPyDict`]: https://docs.rs/pyo3/latest/pyo3/types/trait.IntoPyDict.html
|
||||
|
|
|
@ -192,15 +192,12 @@ mod io {
|
|||
pyo3::import_exception!(io, UnsupportedOperation);
|
||||
}
|
||||
|
||||
fn tell(file: PyObject) -> PyResult<u64> {
|
||||
fn tell(file: &PyAny) -> PyResult<u64> {
|
||||
use pyo3::exceptions::*;
|
||||
|
||||
let gil = Python::acquire_gil();
|
||||
let py = gil.python();
|
||||
|
||||
match file.call_method0(py, "tell") {
|
||||
match file.call_method0("tell") {
|
||||
Err(_) => Err(io::UnsupportedOperation::py_err("not supported: tell")),
|
||||
Ok(x) => x.extract::<u64>(py),
|
||||
Ok(x) => x.extract::<u64>(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -187,5 +187,5 @@ If you have a static function, you can expose it with `#[pyfunction]` and use [`
|
|||
[`PyAny::call`]: https://docs.rs/pyo3/latest/pyo3/struct.PyAny.html#tymethod.call
|
||||
[`PyAny::call0`]: https://docs.rs/pyo3/latest/pyo3/struct.PyAny.html#tymethod.call0
|
||||
[`PyAny::call1`]: https://docs.rs/pyo3/latest/pyo3/struct.PyAny.html#tymethod.call1
|
||||
[`PyObject`]: https://docs.rs/pyo3/latest/pyo3/struct.PyObject.html
|
||||
[`PyObject`]: https://docs.rs/pyo3/latest/pyo3/type.PyObject.html
|
||||
[`wrap_pyfunction!`]: https://docs.rs/pyo3/latest/pyo3/macro.wrap_pyfunction.html
|
||||
|
|
|
@ -3,6 +3,65 @@
|
|||
This guide can help you upgrade code through breaking changes from one PyO3 version to the next.
|
||||
For a detailed list of all changes, see [CHANGELOG.md](https://github.com/PyO3/pyo3/blob/master/CHANGELOG.md)
|
||||
|
||||
## from 0.11.* to 0.12
|
||||
|
||||
### `FromPy` has been removed
|
||||
To simplify the PyO3 public conversion trait hierarchy, the `FromPy` has been removed. In PyO3
|
||||
`0.11` there were two ways to define the to-Python conversion for a type: `FromPy<T> for PyObject`,
|
||||
and `IntoPy<PyObject> for T`.
|
||||
|
||||
Now, the canonical implementation is always `IntoPy`, so downstream crates may need to adjust
|
||||
accordingly.
|
||||
|
||||
Before:
|
||||
|
||||
```rust,ignore
|
||||
# use pyo3::prelude::*;
|
||||
struct MyPyObjectWrapper(PyObject);
|
||||
|
||||
impl FromPy<MyPyObjectWrapper> for PyObject {
|
||||
fn from_py(other: MyPyObjectWrapper, _py: Python) -> Self {
|
||||
other.0
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
After
|
||||
|
||||
```rust
|
||||
# use pyo3::prelude::*;
|
||||
struct MyPyObjectWrapper(PyObject);
|
||||
|
||||
impl IntoPy<PyObject> for MyPyObjectWrapper {
|
||||
fn into_py(self, _py: Python) -> PyObject {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
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| {
|
||||
let obj = PyObject::from_py(1.234, py);
|
||||
# })
|
||||
```
|
||||
|
||||
After:
|
||||
```rust
|
||||
# use pyo3::prelude::*;
|
||||
# Python::with_gil(|py| {
|
||||
let obj: PyObject = 1.234.into_py(py);
|
||||
# })
|
||||
```
|
||||
|
||||
### `PyObject` is now a type alias of `Py<PyAny>`
|
||||
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.
|
||||
|
||||
## from 0.10.* to 0.11
|
||||
|
||||
### Stable Rust
|
||||
|
|
|
@ -24,7 +24,7 @@ In PyO3, holding the GIL is modeled by acquiring a token of the type
|
|||
* It provides some global API for the Python interpreter, such as
|
||||
[`eval`][eval].
|
||||
* It can be passed to functions that require a proof of holding the GIL,
|
||||
such as [`PyObject::clone_ref`][clone_ref].
|
||||
such as [`Py::clone_ref`][clone_ref].
|
||||
* Its lifetime can be used to create Rust references that implicitly guarantee
|
||||
holding the GIL, such as [`&'py PyAny`][PyAny].
|
||||
|
||||
|
@ -71,10 +71,7 @@ let obj: &PyAny = PyList::empty(py);
|
|||
// Convert to &ConcreteType using PyAny::downcast
|
||||
let _: &PyList = obj.downcast().unwrap();
|
||||
|
||||
// Convert to PyObject using .into() or .to_object(py)
|
||||
let _: PyObject = obj.into();
|
||||
|
||||
// Convert to Py<PyAny> using .into() or Py::from
|
||||
// Convert to Py<PyAny> (aka PyObject) using .into()
|
||||
let _: Py<PyAny> = obj.into();
|
||||
|
||||
// Convert to Py<ConcreteType> using PyAny::extract
|
||||
|
@ -115,51 +112,24 @@ let _: &PyAny = list;
|
|||
// For more explicit &PyAny conversion, use .as_ref()
|
||||
let _: &PyAny = list.as_ref();
|
||||
|
||||
// To convert to PyObject use .into() or .to_object(py)
|
||||
let _: PyObject = list.into();
|
||||
|
||||
// To convert to Py<T> use .into() or Py::from()
|
||||
let _: Py<PyList> = list.into();
|
||||
|
||||
// To convert to PyObject use .into() or .to_object(py)
|
||||
let _: PyObject = list.into();
|
||||
```
|
||||
|
||||
### `PyObject`
|
||||
### `Py<T>`
|
||||
|
||||
**Represents:** a GIL independent reference to a Python object of unspecified
|
||||
type.
|
||||
**Represents:** a GIL independent reference to a Python object. This can be a Python native type
|
||||
(like `PyTuple`), or a `pyclass` type implemented in Rust. The most commonly-used variant,
|
||||
`Py<PyAny>`, is also known as `PyObject`.
|
||||
|
||||
**Used:** Whenever you want to carry around references to "some" Python object,
|
||||
without caring about a GIL lifetime. For example, storing Python object
|
||||
references in a Rust struct that outlives the Python-Rust FFI boundary,
|
||||
or returning objects from functions implemented in Rust back to Python.
|
||||
**Used:** Whenever you want to carry around references to a Python object without caring about a
|
||||
GIL lifetime. For example, storing Python object references in a Rust struct that outlives the
|
||||
Python-Rust FFI boundary, or returning objects from functions implemented in Rust back to Python.
|
||||
|
||||
Can be cloned using Python reference counts with `.clone_ref()`.
|
||||
|
||||
**Conversions:**
|
||||
|
||||
```rust
|
||||
# use pyo3::prelude::*;
|
||||
# use pyo3::types::PyList;
|
||||
# let gil = Python::acquire_gil();
|
||||
# let py = gil.python();
|
||||
let obj: PyObject = PyList::empty(py).into();
|
||||
|
||||
// Convert to &PyAny using AsPyRef::as_ref
|
||||
let _: &PyAny = obj.as_ref(py);
|
||||
|
||||
// Convert to &ConcreteType using PyObject::cast_as
|
||||
let _: &PyList = obj.cast_as(py).unwrap();
|
||||
|
||||
// Convert to Py<ConcreteType> using PyObject::extract
|
||||
let _: Py<PyList> = obj.extract(py).unwrap();
|
||||
```
|
||||
|
||||
### `Py<SomeType>`
|
||||
|
||||
**Represents:** a GIL independent reference to a Python object of known type.
|
||||
This can be a Python native type (like `PyTuple`), or a `pyclass` type
|
||||
implemented in Rust.
|
||||
|
||||
**Used:** Like `PyObject`, but with a known inner type.
|
||||
Can be cloned using Python reference counts with `.clone()`.
|
||||
|
||||
**Conversions:**
|
||||
|
||||
|
@ -178,10 +148,6 @@ let _: &PyList = list.as_ref(py);
|
|||
let _: PyObject = list.into();
|
||||
```
|
||||
|
||||
**Note:** `PyObject` is semantically equivalent to `Py<PyAny>` and might be
|
||||
merged with it in the future.
|
||||
|
||||
|
||||
### `PyCell<SomeType>`
|
||||
|
||||
**Represents:** a reference to a Rust object (instance of `PyClass`) which is
|
||||
|
@ -248,7 +214,7 @@ This trait marks structs that mirror native Python types, such as `PyList`.
|
|||
|
||||
|
||||
[eval]: https://docs.rs/pyo3/latest/pyo3/struct.Python.html#method.eval
|
||||
[clone_ref]: https://docs.rs/pyo3/latest/pyo3/struct.PyObject.html#method.clone_ref
|
||||
[clone_ref]: https://docs.rs/pyo3/latest/pyo3/struct.Py.html#method.clone_ref
|
||||
[pyo3::types]: https://docs.rs/pyo3/latest/pyo3/types/index.html
|
||||
[PyAny]: https://docs.rs/pyo3/latest/pyo3/types/struct.PyAny.html
|
||||
[PyList_append]: https://docs.rs/pyo3/latest/pyo3/types/struct.PyList.html#method.append
|
||||
|
|
|
@ -2,10 +2,11 @@
|
|||
|
||||
//! Conversions between various states of Rust and Python types and their wrappers.
|
||||
use crate::err::{self, PyDowncastError, PyResult};
|
||||
use crate::instance::PyObject;
|
||||
use crate::type_object::PyTypeInfo;
|
||||
use crate::types::PyTuple;
|
||||
use crate::{ffi, gil, Py, PyAny, PyCell, PyClass, PyNativeType, PyRef, PyRefMut, Python};
|
||||
use crate::{
|
||||
ffi, gil, Py, PyAny, PyCell, PyClass, PyNativeType, PyObject, PyRef, PyRefMut, Python,
|
||||
};
|
||||
use std::ptr::NonNull;
|
||||
|
||||
/// This trait represents that **we can do zero-cost conversion from the object
|
||||
|
@ -133,6 +134,9 @@ where
|
|||
}
|
||||
|
||||
/// Similar to [std::convert::Into], just that it requires a gil token.
|
||||
///
|
||||
/// `IntoPy<PyObject>` (aka `IntoPy<Py<PyAny>>`) should be implemented to define a conversion from
|
||||
/// Rust to Python which can be used by most of PyO3's methods.
|
||||
pub trait IntoPy<T>: Sized {
|
||||
/// Performs the conversion.
|
||||
fn into_py(self, py: Python) -> T;
|
||||
|
@ -141,10 +145,10 @@ pub trait IntoPy<T>: Sized {
|
|||
/// `FromPyObject` is implemented by various types that can be extracted from
|
||||
/// a Python object reference.
|
||||
///
|
||||
/// Normal usage is through the helper methods `PyObject::extract` or
|
||||
/// `PyAny::extract`:
|
||||
/// Normal usage is through the helper methods `Py::extract` or `PyAny::extract`:
|
||||
///
|
||||
/// ```let obj: PyObject = ...;
|
||||
/// ```rust,ignore
|
||||
/// let obj: Py<PyAny> = ...;
|
||||
/// let value: &TargetType = obj.extract(py)?;
|
||||
///
|
||||
/// let any: &PyAny = ...;
|
||||
|
@ -161,9 +165,6 @@ pub trait IntoPy<T>: Sized {
|
|||
/// Since which case applies depends on the runtime type of the Python object,
|
||||
/// both the `obj` and `prepared` variables must outlive the resulting string slice.
|
||||
///
|
||||
/// In cases where the result does not depend on the `'prepared` lifetime,
|
||||
/// the inherent method `PyObject::extract()` can be used.
|
||||
///
|
||||
/// The trait's conversion method takes a `&PyAny` argument but is called
|
||||
/// `FromPyObject` for historical reasons.
|
||||
pub trait FromPyObject<'source>: Sized {
|
||||
|
|
|
@ -558,6 +558,12 @@ impl<T> std::fmt::Debug for Py<T> {
|
|||
}
|
||||
}
|
||||
|
||||
/// A commonly-used alias for `Py<PyAny>`.
|
||||
///
|
||||
/// This is an owned reference a Python object without any type information. This value can also be
|
||||
/// safely sent between threads.
|
||||
///
|
||||
/// See the documentation for [`Py`](struct.Py.html).
|
||||
pub type PyObject = Py<PyAny>;
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
|
@ -12,8 +12,7 @@
|
|||
|
||||
pub use crate::err::{PyErr, PyResult};
|
||||
pub use crate::gil::GILGuard;
|
||||
pub use crate::instance::PyObject;
|
||||
pub use crate::instance::{AsPyRef, Py};
|
||||
pub use crate::instance::{AsPyRef, Py, PyObject};
|
||||
pub use crate::pycell::{PyCell, PyRef, PyRefMut};
|
||||
pub use crate::pyclass_init::PyClassInitializer;
|
||||
pub use crate::python::Python;
|
||||
|
|
|
@ -166,9 +166,8 @@ impl PyByteArray {
|
|||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::exceptions;
|
||||
use crate::instance::PyObject;
|
||||
use crate::types::PyByteArray;
|
||||
use crate::Python;
|
||||
use crate::{PyObject, Python};
|
||||
|
||||
#[test]
|
||||
fn test_len() {
|
||||
|
|
|
@ -25,9 +25,8 @@ use crate::ffi::{
|
|||
PyDateTime_TIME_GET_HOUR, PyDateTime_TIME_GET_MICROSECOND, PyDateTime_TIME_GET_MINUTE,
|
||||
PyDateTime_TIME_GET_SECOND,
|
||||
};
|
||||
use crate::instance::PyObject;
|
||||
use crate::types::PyTuple;
|
||||
use crate::{AsPyPointer, PyAny, Python, ToPyObject};
|
||||
use crate::{AsPyPointer, PyAny, PyObject, Python, ToPyObject};
|
||||
use std::os::raw::c_int;
|
||||
#[cfg(not(PyPy))]
|
||||
use std::ptr;
|
||||
|
|
|
@ -1,13 +1,12 @@
|
|||
// Copyright (c) 2017-present PyO3 Project and Contributors
|
||||
|
||||
use crate::err::{self, PyErr, PyResult};
|
||||
use crate::instance::PyNativeType;
|
||||
use crate::instance::PyObject;
|
||||
use crate::types::{PyAny, PyList};
|
||||
#[cfg(not(PyPy))]
|
||||
use crate::IntoPyPointer;
|
||||
use crate::{
|
||||
ffi, AsPyPointer, FromPyObject, IntoPy, PyTryFrom, Python, ToBorrowedObject, ToPyObject,
|
||||
ffi, AsPyPointer, FromPyObject, IntoPy, PyNativeType, PyObject, PyTryFrom, Python,
|
||||
ToBorrowedObject, ToPyObject,
|
||||
};
|
||||
use std::collections::{BTreeMap, HashMap};
|
||||
use std::ptr::NonNull;
|
||||
|
|
|
@ -11,7 +11,7 @@ use std::os::raw::c_double;
|
|||
///
|
||||
/// You can usually avoid directly working with this type
|
||||
/// by using [`ToPyObject`](trait.ToPyObject.html)
|
||||
/// and [extract](struct.PyObject.html#method.extract)
|
||||
/// and [extract](struct.PyAny.html#method.extract)
|
||||
/// with `f32`/`f64`.
|
||||
#[repr(transparent)]
|
||||
pub struct PyFloat(PyAny);
|
||||
|
|
|
@ -6,12 +6,11 @@ use crate::err::{PyErr, PyResult};
|
|||
use crate::exceptions;
|
||||
use crate::ffi;
|
||||
use crate::instance::PyNativeType;
|
||||
use crate::instance::PyObject;
|
||||
use crate::pyclass::PyClass;
|
||||
use crate::type_object::PyTypeObject;
|
||||
use crate::types::PyTuple;
|
||||
use crate::types::{PyAny, PyDict, PyList};
|
||||
use crate::{AsPyPointer, IntoPy, Py, Python, ToPyObject};
|
||||
use crate::{AsPyPointer, IntoPy, Py, PyObject, Python, ToPyObject};
|
||||
use std::ffi::{CStr, CString};
|
||||
use std::os::raw::c_char;
|
||||
use std::str;
|
||||
|
|
|
@ -50,7 +50,7 @@ macro_rules! int_fits_larger_int {
|
|||
///
|
||||
/// You can usually avoid directly working with this type
|
||||
/// by using [`ToPyObject`](trait.ToPyObject.html)
|
||||
/// and [extract](struct.PyObject.html#method.extract)
|
||||
/// and [extract](struct.PyAny.html#method.extract)
|
||||
/// with the primitive Rust integer types.
|
||||
#[repr(transparent)]
|
||||
pub struct PyLong(PyAny);
|
||||
|
|
|
@ -397,11 +397,10 @@ impl<'v> PyTryFrom<'v> for PySequence {
|
|||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::instance::AsPyRef;
|
||||
use crate::instance::PyObject;
|
||||
use crate::types::PySequence;
|
||||
use crate::AsPyPointer;
|
||||
use crate::Python;
|
||||
use crate::{PyTryFrom, ToPyObject};
|
||||
use crate::{PyObject, PyTryFrom, ToPyObject};
|
||||
|
||||
fn get_object() -> PyObject {
|
||||
// Convenience function for getting a single unique object
|
||||
|
|
|
@ -147,9 +147,8 @@ impl<'source> FromPyObject<'source> for String {
|
|||
mod test {
|
||||
use super::PyString;
|
||||
use crate::instance::AsPyRef;
|
||||
use crate::instance::PyObject;
|
||||
use crate::Python;
|
||||
use crate::{FromPyObject, PyTryFrom, ToPyObject};
|
||||
use crate::{FromPyObject, PyObject, PyTryFrom, ToPyObject};
|
||||
|
||||
#[test]
|
||||
fn test_non_bmp() {
|
||||
|
|
Loading…
Reference in a new issue