awestlake87 / pyo3-asyncio

Other
300 stars 45 forks source link

"not currently running on a Tokio 0.2.x runtime." #102

Open xMaxximum opened 1 year ago

xMaxximum commented 1 year ago

πŸ› Bug Reports

When reporting a bug, please provide the following information. If this is not a bug report you can just discard this template.

🌍 Environment

πŸ’₯ Reproducing

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

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

toml:

[dependencies]
async-std = "1.12.0"
futures = "0.3.28"
pyo3 = { version = "0.19", features = ["extension-module"] }
pyo3-asyncio = { git = "https://github.com/awestlake87/pyo3-asyncio", features = ["async-std-runtime"] }
reqwest = "0.11.18"
tokio = { version = "1.29.1", features = ["full"]}
yahoo-finance = "0.3.0"

rust:

#[pyfunction]
fn call_test(py: Python<'_>) -> PyResult<&PyAny> {
    pyo3_asyncio::async_std::future_into_py(py, async move {
        test().await;
        Ok(Python::with_gil(|py| py.None()))
    })
}

async fn test() {
    let data = history::retrieve_interval("AAPL", Interval::_6mo)
        .await
        .unwrap();

    for bar in &data {
        println!(
            "Apple hit an intraday high of ${:.2} on {}.",
            bar.high,
            bar.datetime().format("%b %e %Y")
        );
    }
}

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

py:

import asyncio
import yahoofetcher

async def main():
    await yahoofetcher.call_test()

if __name__ == "__main__":
    asyncio.run(main())

I get this error:

thread 'async-std/runtime' panicked at 'not currently running on a Tokio 0.2.x runtime.', C:\Users\maxim\.cargo\registry\src\github.com-1ecc6299db9ec823\tokio-0.2.25\src\runtime\handle.rs:118:28
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
Traceback (most recent call last):
  File "c:\code\yahoofetcher\src\main.py", line 8, in <module>
    asyncio.run(main())
  File "C:\Users\maxim\AppData\Local\Programs\Python\Python310\lib\asyncio\runners.py", line 44, in run
    return loop.run_until_complete(main)
  File "C:\Users\maxim\AppData\Local\Programs\Python\Python310\lib\asyncio\base_events.py", line 641, in run_until_complete
    return future.result()
  File "c:\code\yahoofetcher\src\main.py", line 5, in main
    await yahoofetcher.call_test()
pyo3_asyncio.RustPanic: rust future panicked

any help would be appreciated, thanks!

xMaxximum commented 1 year ago

For clarification, I merely copied from the tutorial, am I doing something wrong?

awestlake87 commented 1 year ago

You have to be consistent with your runtimes. I think the libraries you are trying to use are built to work with tokio, but you are using the async-std runtime.

You'll either have to use the tokio example code or use a tokio compatibility feature in async-std.

xMaxximum commented 1 year ago

Could you maybe rewrite my code quickly so it uses tokio? I tried a plethora of different ways and kept getting the same error...

awestlake87 commented 1 year ago

Ah yep, you're right. Apparently this yahoo finance library is pretty old, so it's using a 0.2 version of tokio's API. Tokio's runtime doesn't support these older libraries out of the box.

Luckily however, there's a pretty nice solution to this. You can wrap your future in a tokio_compat_02 compatibility layer, and then it should work!

Cargo.toml

[lib]
name = "yahoofetcher"
crate-type = ["cdylib"]

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
futures = "0.3.28"
pyo3 = { version = "0.19", features = ["extension-module"] }
# Added tokio-runtime feature
pyo3-asyncio = { version = "0.19", features = ["tokio-runtime"] }
reqwest = "0.11.18"
tokio = { version = "1.29.1", features = ["full"]}
# Added tokio-compat-02 crate
tokio-compat-02 = "0.2.0"
yahoo-finance = "0.3.0"

lib.rs

use pyo3::prelude::*;
// import the FutureExt trait to enable .compat() usage
use tokio_compat_02::FutureExt;
use yahoo_finance::{history, Interval, Timestamped};

#[pyfunction]
fn call_test(py: Python<'_>) -> PyResult<&PyAny> {
    // Changed to pyo3_asyncio::tokio::future_into_py
    pyo3_asyncio::tokio::future_into_py(py, async move {
        test().await;
        Ok(Python::with_gil(|py| py.None()))
    })
}

async fn test() {
    // Added a .compat() to convert the future into a tokio 0.2-compatible future
    let data = history::retrieve_interval("AAPL", Interval::_6mo)
        .compat()
        .await
        .unwrap();

    for bar in &data {
        println!(
            "Apple hit an intraday high of ${:.2} on {}.",
            bar.high,
            bar.datetime().format("%b %e %Y")
        );
    }
}

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

Basically, any time the yahoo finance library gives you a future to work with, you first call .compat() on it to allow it to work with the modern Tokio API.

I also updated pyo3-asyncio to 0.19 since it's out now.

LMK if this works for you!

xMaxximum commented 1 year ago

Hey,

Sorry for the late response, I was busy with work...

Yes, this does work! Unfortunately I'll have to abandon this though as the yahoo finance library isn't really up-to-date anymore and the only option would be writing something myself - I'll have to think about that

Anyways, thank you again!