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.
async defin Python). Who is calling that function in the use case you envision? You won't be able to mix&match Python asyncio and Rust tokio (or others), but if your Python async function is itself awaited from async Rust, awaiting a Rust async fn should at least be possible.