use pyo3::prelude::{PyAnyMethods as _, PyModule, PyModuleMethods as _};
use pyo3::{pyfunction, pymodule, wrap_pyfunction, Bound, PyAny, PyObject, PyResult, Python};
#[pyfunction]
fn async_callback<'py>(
py: Python<'py>,
callback: PyObject
) -> PyResult<Bound<'py, PyAny>> {
pyo3_async_runtimes::tokio::future_into_py(py, async move {
match Python::with_gil(|py| {
let asyncio = py.import("asyncio")?;
let coroutine = callback.call0(py)?;
pyo3_async_runtimes::tokio::into_future(
asyncio.call_method1("ensure_future", (coroutine, ))?
)
}) {
Ok(bound) => {
if let Err(e) = bound.await {
Python::with_gil(|py| {
e.display(py);
})
}
},
Err(e) => {
Python::with_gil(|py| {
e.display(py);
})
},
}
Ok(())
})
}
#[pymodule]
fn async_py(_py: Python, m: &Bound<'_, PyModule>) -> PyResult<()> {
m.add_function(wrap_pyfunction!(async_callback, m)?)?;
Ok(())
}
import asyncio;
from async_py import async_callback
async def callback():
print("Hello from asynco-py!")
async def main():
await async_callback(callback)
if __name__ == "__main__":
asyncio.run(main())
Shows:
Traceback (most recent call last):
File "/usr/lib/python3.13/asyncio/tasks.py", line 746, in ensure_future
loop = events.get_event_loop()
File "/usr/lib/python3.13/asyncio/events.py", line 716, in get_event_loop
raise RuntimeError('There is no current event loop in thread %r.'
% threading.current_thread().name)
RuntimeError: There is no current event loop in thread 'Dummy-1'.
<sys>:0: RuntimeWarning: coroutine 'callback' was never awaited
RuntimeWarning: Enable tracemalloc to get the object allocation traceback