"""An ``async_test`` that also closes the app's Tortoise context. ``pwo.async_test`` runs every test in a fresh event loop (``asyncio.Runner``). The app's :class:`~tavolo.tortoise_mixin.TortoiseMixin` builds one ``TortoiseContext`` per loop, so without an explicit close each test orphans an aiosqlite connection whose non-daemon worker thread keeps the interpreter alive after the suite reports "OK". """ from __future__ import annotations import asyncio from functools import wraps from typing import Any, Callable, Coroutine from tavolo.app import tortoise_mixin def async_test(coro: Callable[..., Coroutine[Any, Any, None]]) -> Callable[..., None]: """Like ``pwo.async_test``, but close the Tortoise context afterwards.""" @wraps(coro) def wrapper(*args: Any, **kwargs: Any) -> None: async def run() -> None: try: await coro(*args, **kwargs) finally: await tortoise_mixin.aclose() with asyncio.Runner() as runner: runner.run(run()) return wrapper