It would be nice if I could do:
@click.command()
@ascyncio.coroutine
def command():
yield from whatever
I think the only place that should be changed to make that work would be Context.invoke (check if function is coroutine, do loop.run_until_complete()). But it's hard to subclass context in current click.
Would you mind making this functionality built-in?
Why does that have to be in click? Just have a custom decorator that does asyncio.coroutine + whatever wrapper logic necessary. Eg:
import asyncio
from functools import update_wrapper
def coro(f):
f = asyncio.coroutine(f)
def wrapper(*args, **kwargs):
loop = asyncio.get_event_loop()
return loop.run_until_complete(f(*args, **kwargs))
return update_wrapper(wrapper, f)
Would be used like this then:
@click.command()
@coro
def command():
yield from whatever
For more complex cases you need to accept the loop anyways or get it from somewhere.
Generally I don't want to put builtin support for asyncio into click. It really does not belong there and by pure user count someone will come and ask for twisted or whatever support next :)
Ah, Thanks. I don't know why I didn't find this solution before :)
Just curious if this is still the recommended practice now that async/await is a first-class language feature.
I feel a little dirty having to redundantly decorate all my commands with a @coroutine wrapper as well as a async def. Or maybe theirs a neater way that I've not thought of where I don't need to decorate each command.
Thanks - minor thing I know.
Just curious if this is still the recommended practice now that async/await is a first-class language feature.
I feel a little dirty having to redundantly decorate all my commands with a
@coroutinewrapper as well as aasync def. Or maybe theirs a neater way that I've not thought of where I don't need to decorate each command.Thanks - minor thing I know.
Any update on this? Is it possible to pass an async generator into a progressbar as iterable for example?
Can this issue be re-opened and considered?
This is an updated version making use of asyncio.run() from Python 3.7:
import asyncio
from functools import wraps
def coro(f):
@wraps(f)
def wrapper(*args, **kwargs):
return asyncio.run(f(*args, **kwargs))
return wrapper
Usage:
@click.command()
@coro
async def command():
await asyncio.sleep(1)
click.echo("Delayed hello")
BTW, there is the fork of click, which allows to use it with asyncio https://github.com/python-trio/trio-click
New click user here. Thanks for this great tool.
I naively tried decorating a coroutine with @click.command() and received the cryptic error:
sys:1: RuntimeWarning: coroutine 'main' was never awaited
I believe it would be reasonable for @click.command() to examine the function it is decorating and, if a coroutine is found, automatically wrap it with the @coro decorator suggested above. In the meantime, the workaround worked great.
Most helpful comment
This is an updated version making use of
asyncio.run()from Python 3.7:Usage: