Skip to content

Instantly share code, notes, and snippets.

@jomido
Last active January 2, 2021 05:50
Show Gist options
  • Save jomido/4051adfa6f08b34f070f0854f7ae2108 to your computer and use it in GitHub Desktop.
Save jomido/4051adfa6f08b34f070f0854f7ae2108 to your computer and use it in GitHub Desktop.
An asyncio call_later that works with both sync and async functions...woot
import asyncio
def maybeAsync(callable, *args, **kwargs):
"""
Turn a callable into a coroutine if it isn't
"""
if asyncio.iscoroutine(callable):
return callable
return asyncio.coroutine(callable)(*args, **kwargs)
def fire(callable, *args, **kwargs):
"""
Fire a callable as a coroutine, and return it's future. The cool thing
about this function is that (via maybeAsync) it lets you treat synchronous
and asynchronous callables the same, which simplifies code.
"""
return asyncio.ensure_future(maybeAsync(callable, *args, **kwargs))
async def _call_later(delay, callable, *args, **kwargs):
"""
The bus stop, where we wait.
"""
await asyncio.sleep(delay)
fire(callable, *args, **kwargs)
def call_later(delay, callable, *args, **kwargs):
"""
After :delay seconds, call :callable with :args and :kwargs; :callable can
be a synchronous or asynchronous callable (a coroutine). Note that _this_
function is synchronous - mission accomplished - it can be used from within
any synchronous or asynchronous callable.
"""
fire(_call_later, delay, callable, *args, **kwargs)
async def foo(bar, loop=None):
print(bar)
loop.stop()
def sync_foo(bar, loop=None):
print(bar)
loop.stop()
if __name__ == "__main__":
loop = asyncio.get_event_loop()
# NOTE: change :foo below to :sync_foo - it still works!
call_later(2, foo, 5, loop=loop)
loop.run_forever()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment