Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion guide/src/async-await.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use pyo3::prelude::*;

#[pyfunction]
#[pyo3(signature=(seconds, result=None))]
async fn sleep(seconds: f64, result: Option<PyObject>) -> Option<PyObject> {
async fn sleep(seconds: f64, result: Option<Py<PyAny>>) -> Option<Py<PyAny>> {
let (tx, rx) = oneshot::channel();
thread::spawn(move || {
thread::sleep(Duration::from_secs_f64(seconds));
Expand Down
4 changes: 2 additions & 2 deletions guide/src/class.md
Original file line number Diff line number Diff line change
Expand Up @@ -413,7 +413,7 @@ impl SubSubClass {
}

#[staticmethod]
fn factory_method(py: Python<'_>, val: usize) -> PyResult<PyObject> {
fn factory_method(py: Python<'_>, val: usize) -> PyResult<Py<PyAny>> {
let base = PyClassInitializer::from(BaseClass::new());
let sub = base.add_subclass(SubClass { val2: val });
if val % 2 == 0 {
Expand Down Expand Up @@ -748,7 +748,7 @@ To create a constructor which takes a positional class argument, you can combine
# use pyo3::prelude::*;
# use pyo3::types::PyType;
# #[pyclass]
# struct BaseClass(PyObject);
# struct BaseClass(Py<PyAny>);
#
#[pymethods]
impl BaseClass {
Expand Down
10 changes: 5 additions & 5 deletions guide/src/class/protocols.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ given signatures should be interpreted as follows:
#[pymethods]
impl NotHashable {
#[classattr]
const __hash__: Option<PyObject> = None;
const __hash__: Option<Py<PyAny>> = None;
}
```
</details>
Expand Down Expand Up @@ -162,15 +162,15 @@ use std::sync::Mutex;

#[pyclass]
struct MyIterator {
iter: Mutex<Box<dyn Iterator<Item = PyObject> + Send>>,
iter: Mutex<Box<dyn Iterator<Item = Py<PyAny>> + Send>>,
}

#[pymethods]
impl MyIterator {
fn __iter__(slf: PyRef<'_, Self>) -> PyRef<'_, Self> {
slf
}
fn __next__(slf: PyRefMut<'_, Self>) -> Option<PyObject> {
fn __next__(slf: PyRefMut<'_, Self>) -> Option<Py<PyAny>> {
slf.iter.lock().unwrap().next()
}
}
Expand Down Expand Up @@ -283,7 +283,7 @@ Use the `#[pyclass(sequence)]` annotation to instruct PyO3 to fill the `sq_lengt
#[pymethods]
impl NoContains {
#[classattr]
const __contains__: Option<PyObject> = None;
const __contains__: Option<Py<PyAny>> = None;
}
```
</details>
Expand Down Expand Up @@ -439,7 +439,7 @@ use pyo3::gc::PyVisit;

#[pyclass]
struct ClassWithGCSupport {
obj: Option<PyObject>,
obj: Option<Py<PyAny>>,
}

#[pymethods]
Expand Down
3 changes: 1 addition & 2 deletions guide/src/conversions/tables.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
## Mapping of Rust types to Python types

When writing functions callable from Python (such as a `#[pyfunction]` or in a `#[pymethods]` block), the trait `FromPyObject` is required for function arguments, and `IntoPy<PyObject>` is required for function return values.
When writing functions callable from Python (such as a `#[pyfunction]` or in a `#[pymethods]` block), the trait `FromPyObject` is required for function arguments, and `IntoPyObject` is required for function return values.

Consult the tables in the following section to find the Rust types provided by PyO3 which implement these traits.

Expand Down Expand Up @@ -54,7 +54,6 @@ It is also worth remembering the following special types:
| `Python<'py>` | A GIL token, used to pass to PyO3 constructors to prove ownership of the GIL. |
| `Bound<'py, T>` | A Python object connected to the GIL lifetime. This provides access to most of PyO3's APIs. |
| `Py<T>` | A Python object isolated from the GIL lifetime. This can be sent to other threads. |
| `PyObject` | An alias for `Py<PyAny>` |
| `PyRef<T>` | A `#[pyclass]` borrowed immutably. |
| `PyRefMut<T>` | A `#[pyclass]` borrowed mutably. |

Expand Down
7 changes: 3 additions & 4 deletions guide/src/conversions/traits.md
Original file line number Diff line number Diff line change
Expand Up @@ -580,7 +580,7 @@ forward the implementation to the inner type.

// newtype tuple structs are implicitly `transparent`
#[derive(IntoPyObject)]
struct TransparentTuple(PyObject);
struct TransparentTuple(Py<PyAny>);

#[derive(IntoPyObject)]
#[pyo3(transparent)]
Expand All @@ -599,7 +599,7 @@ For `enum`s each variant is converted according to the rules for `struct`s above

#[derive(IntoPyObject)]
enum Enum<'a, 'py, K: Hash + Eq, V> { // enums are supported and convert using the same
TransparentTuple(PyObject), // rules on the variants as the structs above
TransparentTuple(Py<PyAny>), // rules on the variants as the structs above
#[pyo3(transparent)]
TransparentStruct { inner: Bound<'py, PyAny> },
Tuple(&'a str, HashMap<K, V>),
Expand Down Expand Up @@ -645,7 +645,7 @@ demonstrated below.
```rust,no_run
# use pyo3::prelude::*;
# #[allow(dead_code)]
struct MyPyObjectWrapper(PyObject);
struct MyPyObjectWrapper(Py<PyAny>);

impl<'py> IntoPyObject<'py> for MyPyObjectWrapper {
type Target = PyAny; // the Python type
Expand Down Expand Up @@ -741,7 +741,6 @@ In the example above we used `BoundObject::into_any` and `BoundObject::unbind` t
[`FromPyObject`]: {{#PYO3_DOCS_URL}}/pyo3/conversion/trait.FromPyObject.html
[`IntoPyObject`]: {{#PYO3_DOCS_URL}}/pyo3/conversion/trait.IntoPyObject.html
[`IntoPyObjectExt`]: {{#PYO3_DOCS_URL}}/pyo3/conversion/trait.IntoPyObjectExt.html
[`PyObject`]: {{#PYO3_DOCS_URL}}/pyo3/type.PyObject.html

[`PyRef`]: {{#PYO3_DOCS_URL}}/pyo3/pycell/struct.PyRef.html
[`PyRefMut`]: {{#PYO3_DOCS_URL}}/pyo3/pycell/struct.PyRefMut.html
Expand Down
2 changes: 1 addition & 1 deletion guide/src/function/signature.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ Arguments of type `Python` must not be part of the signature:
# use pyo3::prelude::*;
#[pyfunction]
#[pyo3(signature = (lambda))]
pub fn simple_python_bound_function(py: Python<'_>, lambda: PyObject) -> PyResult<()> {
pub fn simple_python_bound_function(py: Python<'_>, lambda: Py<PyAny>) -> PyResult<()> {
Ok(())
}
```
Expand Down
9 changes: 9 additions & 0 deletions guide/src/migration.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,14 @@ For this reason we chose to rename these to more modern terminology introduced i
- `pyo3::prepare_freethreaded_python` is now called `Python::initialize`.
</details>

### Deprecation of `PyObject` type alias
<details open>
<summary><small>Click to expand</small></summary>

The type alias `PyObject` (aka `Py<PyAny>`) is often confused with the identically named FFI definition `pyo3::ffi::PyObject`. For this reason we are deprecating its usage. To migrate simply replace its usage by the target type `Py<PyAny>`.

</details>

### Deprecation of `GILProtected`
<details open>
<summary><small>Click to expand</small></summary>
Expand Down Expand Up @@ -186,6 +194,7 @@ impl ToPyObject for MyPyObjectWrapper {

After:
```rust,no_run
# #![allow(deprecated)]
# use pyo3::prelude::*;
# #[allow(dead_code)]
# struct MyPyObjectWrapper(PyObject);
Expand Down
4 changes: 2 additions & 2 deletions guide/src/python-from-rust/function-calls.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ Both of these APIs take `args` and `kwargs` arguments (for positional and keywor
* [`call1`]({{#PYO3_DOCS_URL}}/pyo3/types/trait.PyAnyMethods.html#tymethod.call1) and [`call_method1`]({{#PYO3_DOCS_URL}}/pyo3/types/trait.PyAnyMethods.html#tymethod.call_method1) to call only with positional `args`.
* [`call0`]({{#PYO3_DOCS_URL}}/pyo3/types/trait.PyAnyMethods.html#tymethod.call0) and [`call_method0`]({{#PYO3_DOCS_URL}}/pyo3/types/trait.PyAnyMethods.html#tymethod.call_method0) to call with no arguments.

For convenience the [`Py<T>`](../types.md#pyt-and-pyobject) smart pointer also exposes these same six API methods, but needs a `Python` token as an additional first argument to prove the GIL is held.
For convenience the [`Py<T>`](../types.md#pyt) smart pointer also exposes these same six API methods, but needs a `Python` token as an additional first argument to prove the GIL is held.

The example below calls a Python function behind a `PyObject` (aka `Py<PyAny>`) reference:
The example below calls a Python function behind a `Py<PyAny>` reference:

```rust
use pyo3::prelude::*;
Expand Down
2 changes: 1 addition & 1 deletion guide/src/python-typing-hints.md
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,7 @@ impl MyClass {
pub fn __class_getitem__(
cls: &Bound<'_, PyType>,
key: &Bound<'_, PyAny>,
) -> PyResult<PyObject> {
) -> PyResult<Py<PyAny>> {
/* implementation details */
}
}
Expand Down
2 changes: 1 addition & 1 deletion guide/src/trait-bounds.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ How could we expose this solver to Python thanks to PyO3 ?
## Implementation of the trait bounds for the Python class

If a Python class implements the same three methods as the `Model` trait, it seems logical it could be adapted to use the solver.
However, it is not possible to pass a `PyObject` to it as it does not implement the Rust trait (even if the Python model has the required methods).
However, it is not possible to pass a `Py<PyAny>` to it as it does not implement the Rust trait (even if the Python model has the required methods).

In order to implement the trait, we must write a wrapper around the calls in Rust to the Python model.
The method signatures must be the same as the trait, keeping in mind that the Rust trait cannot be changed for the purpose of making the code available in Python.
Expand Down
8 changes: 4 additions & 4 deletions guide/src/types.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@ The recommendation of when to use each of these smart pointers is as follows:

The sections below also explain these smart pointers in a little more detail.

### `Py<T>` (and `PyObject`)
### `Py<T>`

[`Py<T>`][Py] is the foundational smart pointer in PyO3's API. The type parameter `T` denotes the type of the Python object. Very frequently this is `PyAny`, meaning any Python object. This is so common that `Py<PyAny>` has a type alias `PyObject`.
[`Py<T>`][Py] is the foundational smart pointer in PyO3's API. The type parameter `T` denotes the type of the Python object. Very frequently this is `PyAny`, meaning any Python object.

Because `Py<T>` is not bound to [the `'py` lifetime](./python-from-rust.md#the-py-lifetime), it is the type to use when storing a Python object inside a Rust `struct` or `enum` which do not want to have a lifetime parameter. In particular, [`#[pyclass]`][pyclass] types are not permitted to have a lifetime, so `Py<T>` is the correct type to store Python objects inside them.

Expand Down Expand Up @@ -117,11 +117,11 @@ fn add<'py>(
# })
```

If naming the `'py` lifetime adds unwanted complexity to the function signature, it is also acceptable to return `PyObject` (aka `Py<PyAny>`), which has no lifetime. The cost is instead paid by a slight increase in implementation complexity, as seen by the introduction of a call to [`Bound::unbind`]:
If naming the `'py` lifetime adds unwanted complexity to the function signature, it is also acceptable to return `Py<PyAny>`, which has no lifetime. The cost is instead paid by a slight increase in implementation complexity, as seen by the introduction of a call to [`Bound::unbind`]:

```rust
# use pyo3::prelude::*;
fn add(left: &Bound<'_, PyAny>, right: &Bound<'_, PyAny>) -> PyResult<PyObject> {
fn add(left: &Bound<'_, PyAny>, right: &Bound<'_, PyAny>) -> PyResult<Py<PyAny>> {
let output: Bound<'_, PyAny> = left.add(right)?;
Ok(output.unbind())
}
Expand Down
1 change: 1 addition & 0 deletions newsfragments/5325.changed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
deprecated `PyObject` type alias for `Py<PyAny>`
12 changes: 6 additions & 6 deletions pyo3-macros-backend/src/pyclass.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1237,7 +1237,7 @@ fn impl_complex_enum_struct_variant_cls(
complex_enum_variant_field_getter(&variant_cls_type, field_name, field.span, ctx)?;

let field_getter_impl = quote! {
fn #field_name(slf: #pyo3_path::PyClassGuard<'_, Self>, py: #pyo3_path::Python<'_>) -> #pyo3_path::PyResult<#pyo3_path::PyObject> {
fn #field_name(slf: #pyo3_path::PyClassGuard<'_, Self>, py: #pyo3_path::Python<'_>) -> #pyo3_path::PyResult<#pyo3_path::Py<#pyo3_path::PyAny>> {
#[allow(unused_imports)]
use #pyo3_path::impl_::pyclass::Probe as _;
match &*slf.into_super() {
Expand Down Expand Up @@ -1313,7 +1313,7 @@ fn impl_complex_enum_tuple_variant_field_getters(
})
.collect();
let field_getter_impl: syn::ImplItemFn = parse_quote! {
fn #field_name(slf: #pyo3_path::PyClassGuard<'_, Self>, py: #pyo3_path::Python<'_>) -> #pyo3_path::PyResult<#pyo3_path::PyObject> {
fn #field_name(slf: #pyo3_path::PyClassGuard<'_, Self>, py: #pyo3_path::Python<'_>) -> #pyo3_path::PyResult<#pyo3_path::Py<#pyo3_path::PyAny>> {
#[allow(unused_imports)]
use #pyo3_path::impl_::pyclass::Probe as _;
match &*slf.into_super() {
Expand Down Expand Up @@ -1374,7 +1374,7 @@ fn impl_complex_enum_tuple_variant_getitem(
.collect();

let mut get_item_method_impl: syn::ImplItemFn = parse_quote! {
fn __getitem__(slf: #pyo3_path::PyClassGuard<'_, Self>, py: #pyo3_path::Python<'_>, idx: usize) -> #pyo3_path::PyResult< #pyo3_path::PyObject> {
fn __getitem__(slf: #pyo3_path::PyClassGuard<'_, Self>, py: #pyo3_path::Python<'_>, idx: usize) -> #pyo3_path::PyResult< #pyo3_path::Py<#pyo3_path::PyAny>> {
match idx {
#( #match_arms, )*
_ => ::std::result::Result::Err(#pyo3_path::exceptions::PyIndexError::new_err("tuple index out of range")),
Expand Down Expand Up @@ -1582,7 +1582,7 @@ pub fn gen_complex_enum_variant_attr(

let variant_cls = format_ident!("{}_{}", cls, member);
let associated_method = quote! {
fn #wrapper_ident(py: #pyo3_path::Python<'_>) -> #pyo3_path::PyResult<#pyo3_path::PyObject> {
fn #wrapper_ident(py: #pyo3_path::Python<'_>) -> #pyo3_path::PyResult<#pyo3_path::Py<#pyo3_path::PyAny>> {
::std::result::Result::Ok(py.get_type::<#variant_cls>().into_any().unbind())
}
};
Expand Down Expand Up @@ -1953,7 +1953,7 @@ fn pyclass_richcmp_simple_enum(
py: #pyo3_path::Python,
other: &#pyo3_path::Bound<'_, #pyo3_path::PyAny>,
op: #pyo3_path::pyclass::CompareOp
) -> #pyo3_path::PyResult<#pyo3_path::PyObject> {
) -> #pyo3_path::PyResult<#pyo3_path::Py<#pyo3_path::PyAny>> {
#eq

#eq_int
Expand Down Expand Up @@ -1987,7 +1987,7 @@ fn pyclass_richcmp(
py: #pyo3_path::Python,
other: &#pyo3_path::Bound<'_, #pyo3_path::PyAny>,
op: #pyo3_path::pyclass::CompareOp
) -> #pyo3_path::PyResult<#pyo3_path::PyObject> {
) -> #pyo3_path::PyResult<#pyo3_path::Py<#pyo3_path::PyAny>> {
let self_val = self;
if let ::std::result::Result::Ok(other) = other.cast::<Self>() {
let other = &*other.borrow();
Expand Down
2 changes: 1 addition & 1 deletion pyo3-macros-backend/src/pyimpl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,7 @@ pub fn gen_py_const(cls: &syn::Type, spec: &ConstSpec, ctx: &Ctx) -> MethodAndMe
let Ctx { pyo3_path, .. } = ctx;

let associated_method = quote! {
fn #wrapper_ident(py: #pyo3_path::Python<'_>) -> #pyo3_path::PyResult<#pyo3_path::PyObject> {
fn #wrapper_ident(py: #pyo3_path::Python<'_>) -> #pyo3_path::PyResult<#pyo3_path::Py<#pyo3_path::PyAny>> {
#pyo3_path::IntoPyObjectExt::into_py_any(#cls::#member, py)
}
};
Expand Down
2 changes: 1 addition & 1 deletion pyo3-macros-backend/src/pymethod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -565,7 +565,7 @@ pub(crate) fn impl_py_class_attribute(
let body = quotes::ok_wrap(fncall, ctx);

let associated_method = quote! {
fn #wrapper_ident(py: #pyo3_path::Python<'_>) -> #pyo3_path::PyResult<#pyo3_path::PyObject> {
fn #wrapper_ident(py: #pyo3_path::Python<'_>) -> #pyo3_path::PyResult<#pyo3_path::Py<#pyo3_path::PyAny>> {
let function = #cls::#name; // Shadow the method name to avoid #3017
let result = #body;
#pyo3_path::impl_::wrap::converter(&result).map_into_pyobject(py, result)
Expand Down
10 changes: 5 additions & 5 deletions pytests/src/awaitable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,13 @@ use pyo3::prelude::*;
#[pyclass]
#[derive(Debug)]
pub(crate) struct IterAwaitable {
result: Option<PyResult<PyObject>>,
result: Option<PyResult<Py<PyAny>>>,
}

#[pymethods]
impl IterAwaitable {
#[new]
fn new(result: PyObject) -> Self {
fn new(result: Py<PyAny>) -> Self {
IterAwaitable {
result: Some(Ok(result)),
}
Expand All @@ -31,7 +31,7 @@ impl IterAwaitable {
pyself
}

fn __next__(&mut self, py: Python<'_>) -> PyResult<PyObject> {
fn __next__(&mut self, py: Python<'_>) -> PyResult<Py<PyAny>> {
match self.result.take() {
Some(res) => match res {
Ok(v) => Err(PyStopIteration::new_err(v)),
Expand All @@ -46,13 +46,13 @@ impl IterAwaitable {
pub(crate) struct FutureAwaitable {
#[pyo3(get, set, name = "_asyncio_future_blocking")]
py_block: bool,
result: Option<PyResult<PyObject>>,
result: Option<PyResult<Py<PyAny>>>,
}

#[pymethods]
impl FutureAwaitable {
#[new]
fn new(result: PyObject) -> Self {
fn new(result: Py<PyAny>) -> Self {
FutureAwaitable {
py_block: false,
result: Some(Ok(result)),
Expand Down
2 changes: 1 addition & 1 deletion pytests/src/objstore.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use pyo3::prelude::*;
#[pyclass]
#[derive(Default)]
pub struct ObjStore {
obj: Vec<PyObject>,
obj: Vec<Py<PyAny>>,
}

#[pymethods]
Expand Down
4 changes: 2 additions & 2 deletions src/conversions/std/path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use crate::ffi_ptr_ext::FfiPtrExt;
use crate::instance::Bound;
use crate::sync::GILOnceCell;
use crate::types::any::PyAnyMethods;
use crate::{ffi, FromPyObject, PyAny, PyErr, PyObject, PyResult, Python};
use crate::{ffi, FromPyObject, Py, PyAny, PyErr, PyResult, Python};
use std::borrow::Cow;
use std::ffi::OsString;
use std::path::{Path, PathBuf};
Expand All @@ -25,7 +25,7 @@ impl<'py> IntoPyObject<'py> for &Path {

#[inline]
fn into_pyobject(self, py: Python<'py>) -> Result<Self::Output, Self::Error> {
static PY_PATH: GILOnceCell<PyObject> = GILOnceCell::new();
static PY_PATH: GILOnceCell<Py<PyAny>> = GILOnceCell::new();
PY_PATH
.import(py, "pathlib", "Path")?
.call((self.as_os_str(),), None)
Expand Down
Loading
Loading