`Python<'_>` is not a valid argument to `async #[pyfunction]`s
The following code fails to compile:
#[pyfunction]
async fn none(py: Python<'_>) -> Bound<'_, PyAny> {
py.None().into_bound(py)
}
The error message is:
error[E0521]: borrowed data escapes outside of function
--> src/lib.rs:7:5
|
7 | #[pyfunction]
| ^^^^^^^^^^^^^
| |
| `py` is a reference that is only valid in the function body
| `py` escapes the function body here
| lifetime `'py` defined here
| argument requires that `'py` must outlive `'static`
|
= note: this error originates in the attribute macro `pyfunction` (in Nightly builds, run with -Z macro-backtrace for more info)
error: future cannot be sent between threads safely
--> src/lib.rs:7:5
|
7 | #[pyfunction]
| ^^^^^^^^^^^^^ future created by async block is not `Send`
|
= help: within `{async block@src/lib.rs:7:5: 7:18}`, the trait `Send` is not implemented for `*mut pyo3::Python<'static>`
It seems to me that the Python token and all Bound<'py, T> can never be held across an await point, as that breaks the Send guarantee. I am also unsure whether that has interactions with the GIL.
But it's more complex than this because async #[pyfunction] are guaranteed (by the way we currently construct them) to be polled with a Python thread attached, so this feels like it should be legal code (the future only ever executes when attached to the thread).
I think in the short term the only thing we can do is improve the error message and document what to do instead. Maybe in the long-term there it is possible to find a way to express a future which can only be polled when attached to a Python thread at the language level, where the future itself is Send even if Python<'_> is not.