From 7b2055f2e151b1996ed9730576d2dcdeddaeda57 Mon Sep 17 00:00:00 2001 From: Michael Waskom Date: Thu, 19 Dec 2024 16:34:49 +0000 Subject: [PATCH] Fix unwrapping exceptions from decorated functions --- src/synchronicity/async_wrap.py | 2 +- src/synchronicity/synchronizer.py | 1 + test/exception_test.py | 25 +++++++++++++++++++++++++ 3 files changed, 27 insertions(+), 1 deletion(-) diff --git a/src/synchronicity/async_wrap.py b/src/synchronicity/async_wrap.py index f60a9c1..9426091 100644 --- a/src/synchronicity/async_wrap.py +++ b/src/synchronicity/async_wrap.py @@ -20,7 +20,7 @@ def wraps_by_interface(interface: Interface, func): Note: Does not forward async generator information other than explicit annotations """ - if inspect.iscoroutinefunction(func) and interface == Interface._ASYNC_WITH_BLOCKING_TYPES: + if is_coroutine_function_follow_wrapped(func) and interface == Interface._ASYNC_WITH_BLOCKING_TYPES: def asyncfunc_deco(user_wrapper): @functools.wraps(func) diff --git a/src/synchronicity/synchronizer.py b/src/synchronicity/synchronizer.py index d671f12..abd6f60 100644 --- a/src/synchronicity/synchronizer.py +++ b/src/synchronicity/synchronizer.py @@ -345,6 +345,7 @@ async def wrapper_coro(): return value def _run_function_sync_future(self, coro, original_func): + print(">>> Running!") coro = wrap_coro_exception(coro) coro = self._wrap_check_async_leakage(coro) loop = self._get_loop(start=True) diff --git a/test/exception_test.py b/test/exception_test.py index 8980e66..6c5a6fd 100644 --- a/test/exception_test.py +++ b/test/exception_test.py @@ -24,6 +24,7 @@ import asyncio import concurrent +import functools import inspect import pytest import time @@ -164,3 +165,27 @@ async def test_function_raises_with_cause_async_syncwrap(synchronizer): await coro assert SLEEP_DELAY < time.monotonic() - t0 < 2 * SLEEP_DELAY assert isinstance(exc.value.__cause__, CustomExceptionCause) + + +def decorator(f): + @functools.wraps(f) + def wrapper(*args, **kwargs): + return f(*args, **kwargs) + + return wrapper + + +f_raises_wrapped = decorator(f_raises) + + +@pytest.mark.asyncio +async def test_wrapped_function_raises_async(synchronizer): + t0 = time.monotonic() + f_raises_s = synchronizer.create_blocking(f_raises_wrapped) + coro = f_raises_s.aio() + assert inspect.iscoroutine(coro) + assert time.monotonic() - t0 < SLEEP_DELAY + with pytest.raises(CustomException) as exc: + await coro + assert SLEEP_DELAY < time.monotonic() - t0 < 2 * SLEEP_DELAY + assert exc.value.__suppress_context__ or exc.value.__context__ is None