Source code for duck.contrib.sync
"""
Sync + Asynchronous helper tools.
This module provides utility functions to convert between synchronous and asynchronous
functions using **asgiref's** `async_to_sync` and custom **Duck's** `sync_to_async`, with optional LRU caching
to improve performance in high-frequency conversion scenarios.
"""
from typing import Callable, Any
from functools import lru_cache
from asyncio import iscoroutine
from asgiref.sync import (
async_to_sync as _async_to_sync,
iscoroutinefunction,
AsyncToSync,
)
from duck.contrib.sync.smart_async import (
sync_to_async,
transaction_context,
disable_transaction_context,
)
__all__ = [
"iscoroutine",
"iscoroutinefunction",
"sync_to_async",
"async_to_sync",
"convert_to_async_if_needed",
"convert_to_sync_if_needed",
"ensure_async",
"ensure_sync",
"transaction_context",
"disable_transaction_context",
]
[docs]
@lru_cache(maxsize=256)
def async_to_sync(func: Callable) -> AsyncToSync:
"""
Converts an asynchronous function into a synchronous one, with optional LRU caching.
Args:
func (Callable): The asynchronous function to convert.
Returns:
AsyncToSync: A synchronous version of the input async function.
"""
return _async_to_sync(func)
[docs]
def convert_to_async_if_needed(func: Callable) -> Callable:
"""
Automatically converts a function to asynchronous if it's synchronous,
or returns it unchanged if it's already a coroutine function.
Args:
func (Callable): The function to convert if needed.
Returns:
Callable: An async function if `func` was sync, otherwise the original.
"""
from asgiref.sync import SyncToAsync
if iscoroutinefunction(func) or isinstance(func, SyncToAsync):
return func
func = sync_to_async(func)
return func
[docs]
def convert_to_sync_if_needed(func: Callable) -> Callable:
"""
Automatically converts a coroutine function to synchronous if it's asynchronous,
or returns it unchanged if it's already a non-coroutine function.
Args:
func (Callable): The function to convert if needed.
Returns:
Callable: A sync function if `func` was async, otherwise the original.
"""
if not iscoroutinefunction(func) or isinstance(func, AsyncToSync):
return func
return async_to_sync(func)
# Helper aliases
ensure_async = convert_to_async_if_needed
ensure_sync = convert_to_sync_if_needed