Sometimes you need to call an async function synchronously. This add_sync_version decorator makes it straightforward by adding a .sync attribute to your async function. The .sync version uses asyncio.new_event_loop().run_until_complete to run the async code in a blocking way. Just decorate your function with @add_sync_version, and you can call func.sync(*args, **kwargs) when sync access is needed. Inspired by Guido's comment here , it’s a simple way to handle mixed async and sync requirements.

import asyncio
import functools


def add_sync_version(func):
    """
    Decorator that adds a `.sync` attribute to an async function, allowing it 
    to be called synchronously. The synchronous version uses a new event loop 
    to run the async function.

    Example:
        @add_sync_version
        async def spam():
            return "Hello, async world!"

        # Async usage:
        result = await spam()

        # Synchronous usage:
        result = spam.sync()

    Args:
        func (coroutine): The async function to wrap.

    Returns:
        coroutine: The original async function with an added `.sync` attribute.
    """
    assert asyncio.iscoroutinefunction(func)

    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        return asyncio.new_event_loop().run_until_complete(func(*args, **kwargs))

    func.sync = wrapper
    return func

Published

Category

snippets

Tags

Contact