feat: improve async callable detection in CallableObject

- Added support for callable classes with sync __call__
- When a sync callback returns a coroutine/awaitable, its result is now
  detected and awaited automatically
- Ensures sync functions still run in syncio.to_thread, preserving
  thread-safety while handling coroutine-returning sync callables
This commit is contained in:
AlirezaJahaniBiglar 2025-08-22 15:34:18 +03:30
parent ab32296d07
commit 09b998590d

View file

@ -26,7 +26,11 @@ class CallableObject:
def __post_init__(self) -> None:
callback = inspect.unwrap(self.callback)
self.awaitable = inspect.isawaitable(callback) or inspect.iscoroutinefunction(callback)
self.awaitable = (
inspect.isawaitable(callback)
or inspect.iscoroutinefunction(callback)
or inspect.iscoroutinefunction(getattr(callback, "__call__", None))
)
spec = inspect.getfullargspec(callback)
self.params = {*spec.args, *spec.kwonlyargs}
self.varkw = spec.varkw is not None
@ -41,7 +45,12 @@ class CallableObject:
wrapped = partial(self.callback, *args, **self._prepare_kwargs(kwargs))
if self.awaitable:
return await wrapped()
return await asyncio.to_thread(wrapped)
result = await asyncio.to_thread(wrapped)
if inspect.isawaitable(result):
return await result
return result
@dataclass