Source code for bridge.utils
"""
Cross-cutting utilities.
"""
import inspect
from collections.abc import Callable
from typing import Any
[docs]
async def maybe_await(func: Callable[..., Any] | Any, *args, **kwargs) -> Any:
"""
Wrap a function/method as an awaitable that may be async or sync,
or to return a plain value.
Parameters
----------
func : Callable[..., Any] | Any
A function/method to call, or a plain value.
*args
Positional arguments to pass to the function if `func` is callable.
**kwargs
Keyword arguments to pass to the function if `func` is callable.
Returns
-------
Any
The result of calling the function, or the plain value.
"""
# Case 1: caller passed an already-awaitable object
# e.g. maybe_await(some_async_func()), maybe_await(coro)
if inspect.isawaitable(func):
return await func
# Case 2: caller passed a function / method
if callable(func):
result = func(*args, **kwargs)
if inspect.isawaitable(result):
return await result
return result
# Case 3: plain value (not callable, not awaitable)
if args or kwargs:
raise TypeError(
f"maybe_await: got non-callable {func!r} but also args/kwargs; did you mean maybe_await(some_func, ...)?"
)
return func
[docs]
def require_args(*required):
"""
Ensure that certain keyword arguments are provided to an async function.
Decorator function.
Parameters
----------
required : str
Names of required keyword arguments. Can be multiple.
"""
def decorator(fn):
async def wrapper(**kwargs):
missing = [r for r in required if r not in kwargs]
if missing:
raise ValueError(f"Missing required args: {', '.join(missing)}")
return await fn(**kwargs)
return wrapper
return decorator