awestlake87 / pyo3-asyncio

Other
300 stars 45 forks source link

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

Closed JohnScience closed 11 months ago

JohnScience commented 11 months 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 11 months 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 11 months ago

@awestlake87 What a blunder from me, thank you!