-
Notifications
You must be signed in to change notification settings - Fork 831
Supporting async for #[pyfunction] and #[pymethods] #1406
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
…'static and Send requirements for into_coroutine
What we need for making |
Correct, that's all that's needed. There were some conversations about adding it in this thread in the pyo3-asyncio repo, so I figured I'd just open a PR to demonstrate my ideas on it (I probably should have mentioned that in the PR). I'm not pushing for it to be added for the Given the caveats with |
Thanks very much for this @awestlake87. In the long term I would really like to see this syntax supported. I think that one of the great things about At the moment I agree with @kngwyu that we don't urgently need this syntax (as it is just sugar) so I'd prefer to give us more time to learn about the async integration before we think about merging. Especially with the complication around runtimes, as you noted. |
I was thinking about the problems with |
I was thinking similarly. I think the receiver would be |
Regarding async I'm not too familiar with macros, but I reckon we could support async methods if they only use #[pyclass]
#[derive(Clone)]
struct MyClass {
// <snip>
}
#[pymethods]
impl MyClass {
async fn my_function(&self, my_param: u32) -> Vec<String> {
// <snip>
}
} Although I'm not sure how useful that would be in the wild. Here, for example, I wrote an associated function that behaves just like an async method for Python. It returns the list of book titles written by George Orwell in a hypothetical MongoDB database. It works because |
I think rather than requiring Thank you for that example 👍 |
In the end, the only way to circumvent that, is to own But you are right, strictly speaking, I don't see anything preventing an |
Hmm this is probably another motivation for #1068 - where if a |
I used to run into this compiler error a lot when writing Rust/Python async code, but I think the compiler is being sensible here. Holding the GIL across an Usually what I do to get around this is wrap all Python calls in a I agree that it does push some complexity on the implementer to use |
Should we maybe close this as it's out of scope right now? |
Sure, no worries on my part. I've been waiting to let the pyo3-asyncio mature before I take another look at the proc macro stuff. I think I can manage to make a downstream solution for this as well instead of making changes to the core! I can always find it later if need be. |
👍 thanks again @awestlake87 for all the work you put into async pyo3! |
Here's a first attempt at supporting async functions via
pyo3-asyncio
in the#[pyfunction]
and#[pymethods]
proc macro. Currently this PR adds support for async#[pyfunction]
but not#[pymethods]
just yet because it requires recognizing that functions returningimpl Future
should be treated the same as async functions.I kept things simple to get a good baseline for discussion. Currently there's no way to select a runtime, I just assume
async-std
. I'm not sure how the#[pyfunction]
attribute should go about selecting one just yet. Also, there's currently no support forimpl Future
, which is the desugared form ofasync fn
.impl Future
could be useful in cases where the 'static lifetime of the returned future cannot be inferred correctly.The reason why
#[pymethods]
has issues is because&self
screws up the'static
requirement forinto_coroutine
. I don't think any async method that accesses member variables can be reasonably supported with theasync fn
syntax because of the'static
lifetime requirement, so it would have to fall back toimpl Future
to separate accessing member variables from theasync { }
body in nearly all cases. I think this is just an unfortunate consequence of how Rust desugarsasync fn
. Idk if this is something that Rust could improve over time, but at the moment I think we're stuck with it. I also can't see the'static
lifetime requirement going away since we can't safely make assumptions about lifetimes across the ffi boundary.