How to call Python's async callback function in Rust?
⚓ Rust 📅 2025-07-28 👤 surdeus 👁️ 11Shows RuntimeError: no running event loop
pub fn start_notify<'py>(
&self,
py: Python<'py>,
character: Bound<'py, PyString>,
callback: PyObject, // Py<PyFunction>,
) -> PyResult<Bound<'py, PyAny>> {
let character = character.extract::<&str>()?;
let uuid = Uuid::try_from(character)
.map_err(|e| PyValueError::new_err(e.to_string()))?;
let device = self.device.clone();
let context = self.context.clone();
pyo3_async_runtimes::tokio::future_into_py(py, async move {
let character = device
.characteristic(uuid)
.await
.map_err(|e| PyRuntimeError::new_err(e.to_string()))?
.ok_or(PyValueError::new_err(format!(
"Characteristic not found: {}",
uuid
)))?;
let mut stream = character
.subscribe()
.await
.map_err(|e| PyRuntimeError::new_err(e.to_string()))?;
let handle = spawn(async move {
while let Some(data) = stream.next().await {
rsutil::info!("received: {}", data.len());
match Python::with_gil(|py| {
let asyncio = py.import("asyncio")?;
let has_loop = asyncio.call_method0("get_event_loop").is_ok();
if !has_loop {
let new_loop = asyncio.call_method0("new_event_loop")?;
asyncio.call_method1("set_event_loop", (new_loop, ))?;
}
let py_data = PyByteArray::new(py, &data);
let coroutine = callback.call1(py, (py_data, ))?;
pyo3_async_runtimes::tokio::into_future(
asyncio.call_method1("ensure_future", (coroutine, ))?
)
}) {
Ok(fut) => if let Err(e) = fut.await {
Python::with_gil(|py| {
e.display(py);
});
},
Err(e) => Python::with_gil(|py| {
e.display(py);
}),
}
}
});
context.lock().await.replace(Context {
notify_character: uuid,
subscribe_task: handle,
});
Ok(())
})
}
1 post - 1 participant
🏷️ Rust_feed