pwo.async_test runs every test in a fresh event loop and TortoiseMixin builds one TortoiseContext per loop. Dropping the previous context when the loop changed orphaned its aiosqlite connections; their non-daemon worker threads then blocked threading._shutdown forever, so the suite printed OK but the interpreter never exited. Add TortoiseMixin.aclose() and a tests.helpers.async_test wrapper that closes the context in a finally on the test's own loop, and switch the test modules over to it.
33 lines
1.0 KiB
Python
33 lines
1.0 KiB
Python
"""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
|