Skip to content

Help Wanted: future_into_py can’t be used inside async PyO3 methods due to Send bounds #67

@chitralverma

Description

@chitralverma

When trying to call pyo3_async_runtimes::future_into_py inside an async PyO3 method (#[pymethods] pub async fn ...), compilation fails because the generated future captures a non-Send Python<'_> reference.

use pyo3::prelude::*;
use pyo3_async_runtimes::tokio::future_into_py;
use std::path::PathBuf;

#[pyclass]
pub struct Operator {
    core: Core,
}

#[pymethods]
impl Operator {
    #[pyo3(signature = (path, kwargs=None))]
    pub async fn stat(&self, path: PathBuf, kwargs: Option<Py<PyDict>>) -> PyResult<Metadata> {
        let this = self.core.clone();
        let path = path.to_string_lossy().to_string();

        let kwargs = Python::with_gil(|py| {
            kwargs.map(|v| v.bind(py).extract::<StatOptions>()).transpose()
        })?.unwrap_or_default();

        future_into_py(py, async move {
            this.stat_options(&path, kwargs.into())
                .await
                .map_err(format_pyerr)
                .map(Metadata::new)
        })
    }
}

Error:

error: future cannot be sent between threads safely
   --> src/operator.rs:489:1
    |
489 | #[pymethods]
    | ^^^^^^^^^^^^ future created by async block is not `Send`
    |
    = help: within `{async block@src/operator.rs:489:1: 489:13}`, the trait `std::marker::Send` is not implemented for `*mut pyo3::Python<'static>`
note: captured value is not `Send`
   --> src/operator.rs:489:1
    |
489 | #[pymethods]
    | ^^^^^^^^^^^^ has type `pyo3::Python<'_>` which is not `Send`
note: required by a bound in `new_coroutine`
   --> /.../pyo3-0.26.0/src/impl_/coroutine.rs:22:40
    |
15  | pub fn new_coroutine<'py, F, T, E>(
    |        ------------- required by a bound in this function
...
22  |     F: Future<Output = Result<T, E>> + Send + 'static,
    |                                        ^^^^ required by this bound in `new_coroutine`

This happens because the PyO3 async coroutine internally captures a Python<'_>, which is not Send, but future_into_py currently requires Future + Send + 'static.

Could pyo3_async_runtimes provide a *_non_send or similar variant usable inside async PyO3 methods? This would make it possible to use future_into_py ergonomically from PyO3’s experimental async methods without manual runtime bridging or Send issues.

Or if there is an alternate way of solving this, it will be a great help. thanks!

Context:

  • PyO3: 0.26.0 (with experimental-async feature)
  • pyo3_async_runtimes: 0.26.0
  • Runtime: Tokio

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions