awestlake87 / pyo3-asyncio

Other
315 stars 48 forks source link

"RuntimeError: no running event loop" on a basic example #105

Closed JohnScience closed 1 year ago

JohnScience commented 1 year ago

🐛 Bug Reports

C:\Users\USER\Documents\github\pyo3_async_hello>maturin build
🔗 Found pyo3 bindings
🐍 Found CPython 3.11 at C:\Users\USER\AppData\Local\Microsoft\WindowsApps\PythonSoftwareFoundation.Python.3.11_qbz5n2kfra8p0\python.exe
📡 Using build options features from pyproject.toml
    Finished dev [unoptimized + debuginfo] target(s) in 0.17s
📦 Built wheel for CPython 3.11 to C:\Users\USER\Documents\github\pyo3_async_hello\target\wheels\pyo3_async_hello-0.1.0-cp311-none-win_amd64.whl

C:\Users\USER\Documents\github\pyo3_async_hello> pip install C:\Users\USER\Documents\github\pyo3_async_hello\target\wheels\pyo3_async_hello-0.1.0-cp311-none-win_amd64.whl --force-reinstall
Processing c:\users\user\documents\github\pyo3_async_hello\target\wheels\pyo3_async_hello-0.1.0-cp311-none-win_amd64.whl
Installing collected packages: pyo3-async-hello
  Attempting uninstall: pyo3-async-hello
    Found existing installation: pyo3_async_hello 0.1.0
    Uninstalling pyo3_async_hello-0.1.0:
      Successfully uninstalled pyo3_async_hello-0.1.0
Successfully installed pyo3-async-hello-0.1.0

C:\Users\USER\Documents\github\pyo3_async_hello>python
Python 3.11.5 (tags/v3.11.5:cce6ba9, Aug 24 2023, 14:38:34) [MSC v.1936 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> from pyo3_async_hello import hello
>>> import asyncio
>>>
>>> asyncio.run(hello())
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
RuntimeError: no running event loop
>>> exit()

C:\Users\USER\Documents\github\pyo3_async_hello>type src\lib.rs
use pyo3::prelude::*;

#[pyfunction]
fn hello(py: Python) -> PyResult<&PyAny> {
    pyo3_asyncio::async_std::future_into_py(py, async {
        async_std::task::sleep(std::time::Duration::from_secs(1)).await;
        Ok(())
    })
}

/// A Python module implemented in Rust.
#[pymodule]
fn pyo3_async_hello(_py: Python, m: &PyModule) -> PyResult<()> {
    m.add_function(wrap_pyfunction!(hello, m)?)?;
    Ok(())
}

C:\Users\USER\Documents\github\pyo3_async_hello>

Note: conda activate -> maturin dev -> ... didn't help either

🌍 Environment

💥 Reproducing

Please provide a minimal working example. This means both the Rust code and the Python.

src/lib.rs:

use pyo3::prelude::*;

#[pyfunction]
fn hello(py: Python) -> PyResult<&PyAny> {
    pyo3_asyncio::async_std::future_into_py(py, async {
        async_std::task::sleep(std::time::Duration::from_secs(1)).await;
        Ok(())
    })
}

/// A Python module implemented in Rust.
#[pymodule]
fn pyo3_async_hello(_py: Python, m: &PyModule) -> PyResult<()> {
    m.add_function(wrap_pyfunction!(hello, m)?)?;
    Ok(())
}

Python code:

from pyo3_async_hello import hello
import asyncio

asyncio.run(hello())

MWE: https://github.com/JohnScience/pyo3_async_hello

Please also write what exact flags are required to reproduce your results.

awestlake87 commented 1 year ago

This is unintuitive, but documented behavior because the conversion itself needs to call asyncio.get_running_loop(). See this section for a more detailed explanation: https://github.com/awestlake87/pyo3-asyncio#a-note-about-asynciorun

You need to wrap your hello function in a Python coroutine to get it to work since the running loop is not available until you're inside the asyncio.run(...) context.

from pyo3_async_hello import hello
import asyncio

async def main():
    return await hello()

asyncio.run(main())
JohnScience commented 1 year ago

@awestlake87 What a blunder from me, thank you!