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
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions