A plain uv run pytest run (no live servers needed) logs:
Task was destroyed but it is pending!
task: <Task pending name='Task-699' coro=<MemoryBackend._cleanup_task_impl() ...> wait_for=<Future pending ...>>
It shows up in whichever test is running when the garbage collector frees the task (currently around tests/backends/test_redis.py::test_redis_non_utf8_encoding_warns). Visible with uv run pytest -p no:logging -s.
With PYTHONASYNCIODEBUG=1, the task's creation traceback points to tests/backends/test_memory.py::test_cleanup_restarts_on_a_new_loop_after_the_old_one_closed. That test closes the first loop without cancelling the cleanup task on purpose (the #181 scenario), so the stale task is expected. asyncio logs it rather than warning, so filterwarnings = ["error"] (#189) does not fail on it. It is noise that points at an unrelated test.
Proposal
- At the end of that test, release the stale task without logging it: drop it once its "never runs again" state has been asserted. One option is to let the test own a reference until teardown, then clear the
_log_destroy_pending flag; another is to check for a public alternative first.
- Optionally make a stray
Task was destroyed but it is pending! fail the suite, for example with a session-scoped check on the asyncio logger, so a new orphaned task is caught where it starts.
Tests only; no library change.
A plain
uv run pytestrun (no live servers needed) logs:It shows up in whichever test is running when the garbage collector frees the task (currently around
tests/backends/test_redis.py::test_redis_non_utf8_encoding_warns). Visible withuv run pytest -p no:logging -s.With
PYTHONASYNCIODEBUG=1, the task's creation traceback points totests/backends/test_memory.py::test_cleanup_restarts_on_a_new_loop_after_the_old_one_closed. That test closes the first loop without cancelling the cleanup task on purpose (the #181 scenario), so the stale task is expected. asyncio logs it rather than warning, sofilterwarnings = ["error"](#189) does not fail on it. It is noise that points at an unrelated test.Proposal
_log_destroy_pendingflag; another is to check for a public alternative first.Task was destroyed but it is pending!fail the suite, for example with a session-scoped check on theasynciologger, so a new orphaned task is caught where it starts.Tests only; no library change.