Function pyo3_asyncio::tokio::local_future_into_py_with_loop [−][src]
pub fn local_future_into_py_with_loop<'p, F>(
event_loop: &'p PyAny,
fut: F
) -> PyResult<&PyAny> where
F: Future<Output = PyResult<PyObject>> + 'static,
Expand description
Convert a !Send
Rust Future into a Python awaitable
Arguments
event_loop
- The Python event loop that the awaitable should be attached tofut
- The Rust future to be converted
Examples
use std::{rc::Rc, time::Duration}; use pyo3::prelude::*; /// Awaitable non-send sleep function #[pyfunction] fn sleep_for(py: Python, secs: u64) -> PyResult<&PyAny> { // Rc is non-send so it cannot be passed into pyo3_asyncio::tokio::future_into_py let secs = Rc::new(secs); pyo3_asyncio::tokio::local_future_into_py_with_loop( pyo3_asyncio::tokio::get_current_loop(py)?, async move { tokio::time::sleep(Duration::from_secs(*secs)).await; Python::with_gil(|py| Ok(py.None())) } ) } #[pyo3_asyncio::tokio::main] async fn main() -> PyResult<()> { let event_loop = Python::with_gil(|py| -> PyResult<PyObject> { Ok(pyo3_asyncio::tokio::get_current_loop(py)?.into()) })?; // the main coroutine is running in a Send context, so we cannot use LocalSet here. Instead // we use spawn_blocking in order to use LocalSet::block_on tokio::task::spawn_blocking(move || { // LocalSet allows us to work with !Send futures within tokio. Without it, any calls to // pyo3_asyncio::tokio::local_future_into_py will panic. tokio::task::LocalSet::new().block_on( pyo3_asyncio::tokio::get_runtime(), pyo3_asyncio::tokio::scope_local(event_loop, async { Python::with_gil(|py| { let py_future = sleep_for(py, 1)?; pyo3_asyncio::tokio::into_future(py_future) })? .await?; Ok(()) }) ) }).await.unwrap() }