pythonrustpython-3.8pyo3

How to call Rust async method from Python?


I want to use a Rust async method in Python. I'm trying to use PyO3 or rust-cpython.

For example, for sync Rust functions, I can use,

#[pyfunction]
fn myfunc(a: String) -> PyResult<String> {
   let mut contents = String::new();
   contents = a.to_string() + " appended";
   Ok((contents))
}

#[pymodule]
fn MyModule(py: Python, m: &PyModule) -> PyResult<()> {
    m.add_wrapped(wrap_pyfunction!(urlshot))?;
    Ok(())
}

For async methods, how can I do it? For example, I want to call the following method in Python,

async fn hello_world() {
    println!("hello, world!");
}

Solution

  • Since there was no easy way of solving this issue (at least, I hadn't found), I converted my async method to sync one. And called it on Python side as,

    async fn my_method(s: &str) -> Result<String, Error> {
        // do something
    }
    
    #[pyfunction]
    fn my_sync_method(s: String) -> PyResult<String> {
        let mut rt = tokio::runtime::Runtime::new().unwrap();
        let mut contents = String::new();
        rt.block_on(async {
            result = format!("{}", my_sync_method(&s).await.unwrap()).to_string();
        });
       Ok((result))
    }
    
    #[pymodule]
    fn MyModule(py: Python, m: &PyModule) -> PyResult<()> {
        m.add_wrapped(wrap_pyfunction!(my_sync_method))?;
        Ok(())
    }
    

    In the Cargo.toml file, I added the following dependencies,

    
    [dependencies.pyo3]
    git = "https://github.com/PyO3/pyo3"
    features = ["extension-module"]
    

    After running cargo build --release, target/release/libMyModule.so binary file is generated. Rename it as MyModule.so and it now can be imported from Python.

    import MyModule
    result = MyModule.my_sync_method("hello")
    

    Using setuptools-rust, I could bundle it as an ordinary Python package.

    All of the above code and commands are tested on newly-released Linux Mint 20. On MacOS, the binary file will be libMyModule.dylib.