On Wed, Sep 03, 2025 at 01:11:14AM -0400, John Snow wrote: > This is not strictly needed functionality-wise, but doing this allows > sphinx to see which decorated methods are async. Without this, sphinx > misses the "async" classifier on generated docs, which ... for an async > library, isn't great. > > It does make an already gnarly function even gnarlier, though. > > So, what's going on here? > > A synchronous function (like require() before this patch) can return a > coroutine that can be awaited on, for example: > > def some_func(): > return asyncio.task(asyncio.sleep(5)) > > async def some_async_func(): > await some_func() > > However, this function is not considered to be an "async" function in > the eyes of the abstract syntax tree. Specifically, > some_func.__code__.co_flags will not be set with CO_COROUTINE. > > The interpreter uses this flag to know if it's legal to use "await" from > within the body of the function. Since this function is just wrapping > another function, it doesn't matter much for the decorator, but sphinx > uses the stdlib inspect.iscoroutinefunction() to determine when to add > the "async" prefix in generated output. This function uses the presence > of CO_COROUTINE. > > So, in order to preserve the "async" flag for docs, the require() > decorator needs to differentiate based on whether it is decorating a > sync or async function and use a different wrapping mechanism > accordingly. > > Phew. > > Signed-off-by: John Snow <[email protected]> > cherry picked from commit 40aa9699d619849f528032aa456dd061a4afa957 > Signed-off-by: John Snow <[email protected]> > --- > python/qemu/qmp/protocol.py | 53 ++++++++++++++++++++++--------------- > 1 file changed, 32 insertions(+), 21 deletions(-)
Reviewed-by: Daniel P. Berrangé <[email protected]> With regards, Daniel -- |: https://berrange.com -o- https://www.flickr.com/photos/dberrange :| |: https://libvirt.org -o- https://fstop138.berrange.com :| |: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|
