CastError is not Send
Bug Description
I'm not sure if this actually is a bug or expected behavior, but with the update from pyo3 0.26 to 0.27 some of by code broke, because the error returned by Py<PyAny>::extract is no longer Send (I think because of the change in https://github.com/PyO3/pyo3/pull/5468).
Steps to Reproduce
Code like this used to work
use anyhow::Context;
let point: Py<PyAny> = ...
let point: PyReadonlyArray1<f64> = point
.extract(py)
.context("some info")?;
This now gives a compile error.
Backtrace
error[E0277]: `NonNull<PyObject>` cannot be sent between threads safely
--> src/pyfunc.rs:531:18
|
531 | .context("Initializition array returned incorrect argument")?;
| ^^^^^^^ `NonNull<PyObject>` cannot be sent between threads safely
|
= help: within `CastError<'_, '_>`, the trait `Send` is not implemented for `NonNull<PyObject>`
= help: the trait `anyhow::Context<T, E>` is implemented for `Result<T, E>`
note: required because it appears within the type `pyo3::Borrowed<'_, '_, pyo3::PyAny>`
--> /home/adr/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/pyo3-0.27.1/src/instance.rs:931:12
|
931 | pub struct Borrowed<'a, 'py, T>(NonNull<ffi::PyObject>, PhantomData<&'a Py<T>>, Python<'p...
| ^^^^^^^^
note: required because it appears within the type `CastError<'_, '_>`
--> /home/adr/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/pyo3-0.27.1/src/err/cast_error.rs:11:12
|
11 | pub struct CastError<'a, 'py> {
| ^^^^^^^^^
= note: required for `Result<PyReadonlyArray<'_, f64, ...>, ...>` to implement `anyhow::Context<PyReadonlyArray<'_, f64, Dim<[usize; 1]>>, CastError<'_, '_>>`
= note: the full name for the type has been written to '/home/adr/git/nuts-py/target/debug/deps/_lib-d99f07d11670af81.long-type-7367848190499037911.txt'
= note: consider using `--verbose` to print the full type name to the console
help: consider removing this method call, as the receiver has type `pyo3::Py<pyo3::PyAny>` and `pyo3::Py<pyo3::PyAny>: Send` trivially holds
|
529 - let init_point: PyReadonlyArray1<f64> = init_point
530 - .extract(py)
529 + let init_point: PyReadonlyArray1<f64> = init_point
|
Your operating system and version
archlinux
Your Python version (python --version)
3.13
Your Rust version (rustc --version)
1.90.0
Your PyO3 version
0.27.1
How did you install python? Did you use a virtualenv?
pixi
Additional Info
No response
Thanks for the report.
We have been reworking error handling to help avoid creating Python exceptions when in pure-rust code, which benefits performance. CastError is one such error.
Making CastError send would incur Python reference count overhead where it is currently not needed. I think for now I'd suggest changing code to something like:
use anyhow::{anyhow, Context};
let point: Py<PyAny> = ...
let point: PyReadonlyArray1<f64> = point
.extract(py)
.map_err(|e| anyhow!("some info: {e}"))?;
which will format the cast error to a string without needing to create a full Python exception.
I guess there's also the question if the error should have a reference to the objects that it tried to cast, which I think introduces the question of Send in the first place?