Closed vicky5124 closed 2 years ago
What you're doing should be possible. The error you're getting indicates to me that either:
start
function from a Rust thread that is not aware of the running Python event loopstart
before the Python event loop is running.I'd be able to give a more detailed explanation of the problem and potential solutions if I can see where and how start
is being called.
This library does have examples on creating libraries with pyo3-asyncio in the docs. Additionally, these docs might be useful to look at for context on initializing and managing references to the python event loop:
The event loop is indeed running on a different thread. The library spawns a new tokio task, with a gateway reader, that parses the messages it receives and dispatches them to the event loop trait.
Looking at Event Loop References, I got the idea of doing let current_loop = pyo3_asyncio::get_running_loop(py)?;
and storing current_loop on a new field of Event handler, but encountered an issue, can't use generics on #[pyclass]
to define a lifetime for the reference.
error: #[pyclass] cannot have generic parameters: lavasnek_rs
--> src/builders.rs:21:32
|
21 | pub struct EventHandler<'a> {
| ^^^^
I could store let loop_ref = PyObject::from(current_loop);
instead, and use this to run everything:
Python::with_gil(|py| {
let current_loop = slf.current_loop.cast_as(py).unwrap();
pyo3_asyncio::tokio::future_into_py_with_loop(current_loop, async move {
....
})
.unwrap();
});
And it worked! thanks for the information!
@vicky5124 i think the "cant have generic parameters" error is a bug, or at least a misappropriated error, maybe its good to file that with the parent pyo3 project?
@ShadowJonathan I think in this case it's because the @vicky5124 wants to store the event loop reference inside the #[pyclass]
. This is the intended behavior as Python classes defined in Rust must be concrete not generic (even across lifetime parameters).
The solution to this is to use a PyObject
like @vicky5124 discovered. The only change I might make to that snippet is using as_ref
instead of cast_as
to avoid unwrapping the result:
Python::with_gil(|py| {
let current_loop = slf.current_loop.as_ref(py);
pyo3_asyncio::tokio::future_into_py_with_loop(current_loop, async move {
....
})
.unwrap();
});
π Environment
π₯ Reproducing
Is what I'm trying to do down here possible? Have a rust trait be able to call async python code in a library? I think this isn't working because it's a library, and all the examples are shown with binary code with a tokio or async-std runtime running. Or maybe
Python::with_gil()
isn't getting the current instance of python, but it's getting a new one?