<div dir="ltr"><div dir="ltr"><div dir="ltr">Here's syncer/syncer.py:</div><div dir="ltr"><a href="https://github.com/miyakogi/syncer/blob/master/syncer.py">https://github.com/miyakogi/syncer/blob/master/syncer.py</a></div><div dir="ltr"><br></div><div dir="ltr">I think the singledispatch is pretty cool.<br><div><br></div><div>```python</div><div><div>#!/usr/bin/env python3</div><div># -*- coding: utf-8 -*-</div><div><br></div><div>import sys</div><div>from functools import singledispatch, wraps</div><div>import asyncio</div><div>import inspect</div><div>import types</div><div>from typing import Any, Callable, Generator</div><div><br></div><div><br></div><div>PY35 = sys.version_info >= (3, 5)</div><div><br></div><div><br></div><div>def _is_awaitable(co: Generator[Any, None, Any]) -> bool:</div><div>    if PY35:</div><div>        return inspect.isawaitable(co)</div><div>    else:</div><div>        return (isinstance(co, types.GeneratorType) or</div><div>                isinstance(co, asyncio.Future))</div><div><br></div><div><br></div><div>@singledispatch</div><div>def sync(co: Any):</div><div>    raise TypeError('Called with unsupported argument: {}'.format(co))</div><div><br></div><div><br></div><div>@sync.register(asyncio.Future)</div><div>@sync.register(types.GeneratorType)</div><div>def sync_co(co: Generator[Any, None, Any]) -> Any:</div><div>    if not _is_awaitable(co):</div><div>        raise TypeError('Called with unsupported argument: {}'.format(co))</div><div>    return asyncio.get_event_loop().run_until_complete(co)</div><div><br></div><div><br></div><div>@sync.register(types.FunctionType)</div><div>@sync.register(types.MethodType)</div><div>def sync_fu(f: Callable[..., Any]) -> Callable[..., Any]:</div><div>    if not asyncio.iscoroutinefunction(f):</div><div>        raise TypeError('Called with unsupported argument: {}'.format(f))</div><div><br></div><div>    @wraps(f)</div><div>    def run(*args, **kwargs):</div><div>        return asyncio.get_event_loop().run_until_complete(f(*args, **kwargs))</div><div>    return run</div><div><br></div><div><br></div><div>if PY35:</div><div>    sync.register(types.CoroutineType)(sync_co)</div></div><div>```</div></div></div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Wed, Mar 6, 2019 at 9:20 PM Nathaniel Smith <<a href="mailto:njs@pobox.com">njs@pobox.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">On Wed, Mar 6, 2019 at 4:37 PM pylang <<a href="mailto:pylang3@gmail.com" target="_blank">pylang3@gmail.com</a>> wrote:<br>
>> def maybe_async(fn):<br>
>>     @functools.wraps(fn)<br>
>>     def wrapper(*args, **kwargs):<br>
>>         coro = fn(*args, **kwargs)<br>
>>         if asyncio.get_running_loop() is not None:<br>
>>             return coro<br>
>>         else:<br>
>>             return await coro<br>
><br>
> I was unable to run his example as-is (in Python 3.6 at least) since the `await` keyword is only permitted inside an `async def` function.<br>
<br>
Oh yeah, that was a brain fart. I meant to write:<br>
<br>
def maybe_async(fn):<br>
    @functools.wraps(fn)<br>
    def wrapper(*args, **kwargs):<br>
        coro = fn(*args, **kwargs)<br>
        if asyncio.get_running_loop() is not None:<br>
            return coro<br>
        else:<br>
            return asyncio.run(coro)<br>
<br>
-n<br>
<br>
-- <br>
Nathaniel J. Smith -- <a href="https://vorpus.org" rel="noreferrer" target="_blank">https://vorpus.org</a><br>
_______________________________________________<br>
Python-ideas mailing list<br>
<a href="mailto:Python-ideas@python.org" target="_blank">Python-ideas@python.org</a><br>
<a href="https://mail.python.org/mailman/listinfo/python-ideas" rel="noreferrer" target="_blank">https://mail.python.org/mailman/listinfo/python-ideas</a><br>
Code of Conduct: <a href="http://python.org/psf/codeofconduct/" rel="noreferrer" target="_blank">http://python.org/psf/codeofconduct/</a><br>
</blockquote></div>