2

I have read this answer(How to call Rust async method from Python?) and what I want to do is the opposite of this.

I want to call a Python async function and await it in tokio's runtime. Is it possible?

I have given it some tries but I am facing an error in the output.

This is how my python file looks like:

import rust_package

async def h():
    print("message from coroutine")


print("Hello world")
s = rust_package.Server()
s.start(h)

and this is how my lib.rs looks like:

#[pyclass]
struct Server {}

#[pymethods]
impl Server {
    #[new]
    fn new() -> Self {
        Self {}
    }

    fn start(mut self_: PyRefMut<Self>, test: &PyAny) {


        let f = pyo3_asyncio::into_future(test).unwrap();
        let rt = tokio::runtime::Runtime::new().unwrap();
        pyo3_asyncio::tokio::init(rt);
        Python::with_gil(|py| {
            pyo3_asyncio::tokio::run_until_complete(py, async move {
                tokio::time::sleep(Duration::from_secs(1)).await;
                f.await.unwrap();
                Ok(())
            })
            .unwrap();
        });
}

#[pymodule]
pub fn roadrunner(py: Python<'_>, m: &PyModule) -> PyResult<()> {
    m.add_class::<Server>()?;
    pyo3_asyncio::try_init(py);
    Ok(())
}

I am getting the following error:

Hello world
Exception in callback <builtins.PyEnsureFuture object a
t 0x10bc1bd20>()
handle: <Handle <builtins.PyEnsureFuture object at 0x10
bc1bd20>()>
Traceback (most recent call last):
  File "/usr/local/Cellar/[email protected]/3.9.5/Frameworks/P
ython.framework/Versions/3.9/lib/python3.9/asyncio/even
ts.py", line 80, in _run
    self._context.run(self._callback, *self._args)
  File "/usr/local/Cellar/[email protected]/3.9.5/Frameworks/P
ython.framework/Versions/3.9/lib/python3.9/asyncio/task
s.py", line 679, in ensure_future
    raise TypeError('An asyncio.Future, a coroutine or
an awaitable is '
TypeError: An asyncio.Future, a coroutine or an awaitab
le is required

I clearly am passing an async function and converting it to a future. I am unable to figure out where I am going wrong. I have read the documentation of pyo3-async multiple times but I am still unable to figure it out. I would really appreciate some help.

Thanks in advance.

2
  • 1
    s.start(h) passes a function to start, not a coroutine. Have you tried s.start(h()) instead? Commented May 26, 2021 at 15:15
  • 1
    Thank you @sebpuetz. I have been stuck on this issue for many days and you helped me a ton. It fixes the problem. Commented May 26, 2021 at 16:05

1 Answer 1

3

As suggested by @sebpuetz ,

All I needed was to change

s.start(h)

to

s.start(h())

as h on its own is just a function. h() is a coroutine, which was the required item.

Sign up to request clarification or add additional context in comments.

1 Comment

This is the nice thing about Rust - as much as the compiler is sometimes frustrating, it would have caught something like this at compile time!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.