Skip to content

test(memory): stop the loop-restart test's stale task being logged later - #349

Merged
allen0099 merged 2 commits into
masterfrom
test/295-pending-task
Sep 29, 2026
Merged

allen0099 merged 2 commits into
masterfrom
test/295-pending-task

Conversation

@allen0099

@allen0099 allen0099 commented Sep 29, 2026 •

Copy link
Copy Markdown
Owner

Closes #295

Problem

test_cleanup_restarts_on_a_new_loop_after_the_old_one_closed leaves a MemoryBackend cleanup task pending on a closed loop on purpose (the #181 scenario). When the garbage collector freed that task, asyncio logged Task was destroyed but it is pending! during an unrelated later test. asyncio logs this instead of warning, so filterwarnings = ["error"] never caught it.

Changes

  • The test releases its stale task quietly. A task on a closed loop can't be cancelled, because cancelling schedules a callback on that loop and raises. So after asserting the MemoryBackend: cleanup task lifecycle across event loops #181 behaviour, and that the stale task is still pending, the test calls the public loop.set_exception_handler() on the closed loop. The handler drops only that one report and passes anything else to default_exception_handler. It relies on no private attribute.
  • A stray pending task now fails the run. tests/conftest.py adds a handler to the asyncio logger that records the message and the test running when it fired. pytest_sessionfinish calls gc.collect() so that a task still waiting to be collected reports before the check. Any record then sets the exit status to failed, and a terminal-summary section prints the message and says to rerun with PYTHONASYNCIODEBUG=1 to find where the task was created.
  • Every MemoryBackend a test builds is closed on the test's loop. The guard exposed 135 more leaked cleanup tasks in the lowest tox env. pytest-asyncio 0.26 (our floor) closes each test's loop without cancelling pending tasks. 1.x runs the test in an asyncio.Runner, which cancels them, so the leak didn't show there.
    • setup_default_backend is now async and awaits aclose() while the loop is still open. Its sync stop_cleanup() used to run after the loop had already closed.
    • A new autouse close_memory_backends fixture records every MemoryBackend built during a test, as close_network_clients does for network clients. That includes the library's fallback backend. The fixture closes each one at teardown.

Tests only. No library change and no changelog fragment, since nothing user-facing changes.

Verification

  • uv run pytest -p no:logging -s 2>&1 | grep "Task was destroyed": one match before, none after (also none with PYTHONASYNCIODEBUG=1).
  • tox -e lowest and the latest-dependency suite both pass with the guard active.
  • With the fix in the test reverted, the suite fails on both dependency sets with the new summary section, and the single test fails on its own too.
  • ruff, pre-commit and the full suite with coverage pass.

The #181 test leaves a cleanup task pending on a closed loop on purpose.
When the garbage collector freed it, asyncio logged "Task was destroyed
but it is pending!" in whichever later test was running. The test now
installs an exception handler on the closed loop that drops that one
report, after asserting the task is still pending.

A handler on the asyncio logger now records the message for the whole
run; at session end it collects garbage and fails the run, naming the
test the task was freed in, so a new orphaned task cannot go unnoticed.

Closes #295
pytest-asyncio 0.26, the floor the lowest tox env runs, closes each
test's loop without cancelling pending tasks; 1.x runs the test in an
asyncio.Runner, which cancels them. The cleanup task a MemoryBackend
starts on its first operation therefore stayed pending under lowest, and
the new pending-task guard failed the run with 135 reports.

The default-backend fixture is now async and awaits aclose() while the
loop is open, and a new autouse fixture records every MemoryBackend built
during a test, including the library's fallback, and closes it at
teardown.
@allen0099
allen0099 merged commit 9ff0da4 into master Sep 29, 2026
11 checks passed
@allen0099
allen0099 deleted the test/295-pending-task branch September 29, 2026 06:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Tests: the MemoryBackend loop-restart test leaves a pending task that is logged in a later test

1 participant