Skip to content

fix(tests): pin pytest-asyncio to a session-scoped event loop - #175

Merged
sshlg merged 1 commit into
mainfrom
fix/pytest-asyncio-session-loop-scope
Jun 26, 2026
Merged

fix(tests): pin pytest-asyncio to a session-scoped event loop#175
sshlg merged 1 commit into
mainfrom
fix/pytest-asyncio-session-loop-scope

Conversation

@sshlg

@sshlg sshlg commented Jun 26, 2026

Copy link
Copy Markdown
Collaborator

Problem

backend-lint-testIntegration tests was failing on main with 201 failed + 202 errors — a cascade of RuntimeError: Event loop is closed and sqlite3.OperationalError: no such table: users. The full suite passed locally (macOS), so it only red-gated CI — and the Heroku auto-deploy (deploy.yml) only fires on a green CI run on main, so this blocked all deploys.

Root cause

pytest-asyncio 1.x ignores the old session-scoped event_loop fixture and defaults to function-scoped loops:

asyncio: mode=Mode.AUTO, asyncio_default_fixture_loop_scope=None, asyncio_default_test_loop_scope=function

The integration suite shares a session-scoped engine whose in-memory SQLite (aiosqlite) connection is bound to the loop it was created on. With per-test function loops, that connection is used from a different, already-closed loop → Event loop is closed → the in-memory DB is gone → no such table for every subsequent test. Linux surfaced it; macOS happened to tolerate it.

Fix

  • asyncio_default_fixture_loop_scope = "session" + asyncio_default_test_loop_scope = "session" so the shared engine and every test run on one session loop (restores pre-1.x behaviour). Verified against the pytest-asyncio 1.x docs.
  • Remove the now-ignored custom event_loop fixture and its unused imports.

Verification

  • Full backend suite locally: 4494 passed, 0 "no such table", 0 "Event loop is closed".
  • ruff format --check + ruff check clean.

Stacked on #174 (StaticPool) and #173 (the original checkpoint-button fix).

🤖 Generated with Claude Code

pytest-asyncio 1.x ignores the old session-scoped `event_loop` fixture and
defaults both fixtures and tests to function-scoped loops
(`asyncio_default_fixture_loop_scope=None`, `asyncio_default_test_loop_scope=
function`). The integration suite shares a session-scoped engine whose
in-memory SQLite (aiosqlite) connection is bound to the loop it was created
on; with per-test function loops that connection is used from a different,
already-closed loop. On Linux CI this surfaced as a cascade of
`RuntimeError: Event loop is closed` / `sqlite3.OperationalError: no such
table: users` across ~400 integration tests (201 failed + 202 errors),
while macOS happened to tolerate it — so the suite passed locally but
red-gated the Heroku auto-deploy, which only fires on a green CI run on main.

- Set `asyncio_default_fixture_loop_scope = "session"` and
  `asyncio_default_test_loop_scope = "session"` so the shared engine and every
  test run on one session loop (restores the pre-1.x behaviour).
- Drop the now-ignored custom `event_loop` fixture (and its now-unused
  `asyncio` / `pytest` imports).

Verified: full backend suite 4494 passed locally, 0 "no such table",
0 "Event loop is closed".

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@sshlg
sshlg merged commit 75ade47 into main Jun 26, 2026
2 checks passed
@sshlg
sshlg deleted the fix/pytest-asyncio-session-loop-scope branch June 26, 2026 10:27
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.

1 participant