pub fn future_into_py_with_locals<F, T>(
    py: Python<'_>,
    locals: TaskLocals,
    fut: F
) -> PyResult<&PyAny>where
    F: Future<Output = PyResult<T>> + Send + 'static,
    T: IntoPy<PyObject>,
Expand description

Convert a Rust Future into a Python awaitable

If the asyncio.Future returned by this conversion is cancelled via asyncio.Future.cancel, the Rust future will be cancelled as well (new behaviour in v0.15).

Python contextvars are preserved when calling async Python functions within the Rust future via into_future (new behaviour in v0.15).

Although contextvars are preserved for async Python functions, synchronous functions will unfortunately fail to resolve them when called within the Rust future. This is because the function is being called from a Rust thread, not inside an actual Python coroutine context.

As a workaround, you can get the contextvars from the current task locals using get_current_locals and TaskLocals::context, then wrap your synchronous function in a call to contextvars.Context.run. This will set the context, call the synchronous function, and restore the previous context when it returns or raises an exception.

Arguments

  • py - PyO3 GIL guard
  • locals - The task locals for the given future
  • fut - The Rust future to be converted

Examples

use std::time::Duration;

use pyo3::prelude::*;

/// Awaitable sleep function
#[pyfunction]
fn sleep_for<'p>(py: Python<'p>, secs: &'p PyAny) -> PyResult<&'p PyAny> {
    let secs = secs.extract()?;
    pyo3_asyncio::async_std::future_into_py_with_locals(
        py,
        pyo3_asyncio::async_std::get_current_locals(py)?,
        async move {
            async_std::task::sleep(Duration::from_secs(secs)).await;
            Python::with_gil(|py| Ok(py.None()))
        }
    )
}