Skip to content

fix(tests): unblock Windows pytest cleanup of components fixture (#206)#754

Merged
memtomem merged 1 commit intomainfrom
fix/206-windows-handle-leak
May 3, 2026
Merged

fix(tests): unblock Windows pytest cleanup of components fixture (#206)#754
memtomem merged 1 commit intomainfrom
fix/206-windows-handle-leak

Conversation

@memtomem
Copy link
Copy Markdown
Owner

@memtomem memtomem commented May 3, 2026

Summary

  • OnnxEmbedder.close() and FastEmbedReranker.close() now gc.collect() after dropping self._model, forcing the underlying ORT InferenceSession (mmap on the model file + thread-local arenas) to release promptly. Best-effort handle hygiene.
  • Three components-style fixtures (conftest.py) and two test_cli_ingest Codex tests now mkdir(exist_ok=True) (with shutil.rmtree(..., ignore_errors=True) first where .md content gets written), so reused tmp_path roots from a prior failed-cleanup session no longer trip FileExistsError [WinError 183]. Each site has an inline #206 reference.

Storage.close() already runs PRAGMA wal_checkpoint(TRUNCATE) and closes the read-pool — no change needed there.

Closes #206. Original report by @powerzist during #162.

Why both source-level and site-targeted

The issue's acceptance bullets allow either approach:

  • If source fix is sufficient: no exist_ok=True needed at sites.
  • If site-targeted: each site needs a comment pointing at upstream cause.

Neither is fully reliable on its own under Windows file-locking semantics (handles get released when the previous Python process dies, but Windows takes a moment; AV/indexing services can also briefly hold scans). The site-targeted change is the load-bearing one — without it, any future regression in a .close() method silently re-introduces the failure. The source-level change makes it less likely the leftover ever happens in the first place. Defense in depth, with comments at every site so neither layer becomes invisible.

Test plan

  • uv run ruff check packages/memtomem/src packages/memtomem/tests — clean
  • uv run ruff format --check packages/memtomem/src packages/memtomem/tests — clean
  • uv run pytest -m "not ollama" packages/memtomem/tests — 4012 passed, 7 skipped, 46 deselected
  • Windows verification — pinging @powerzist who originally reported the leak in their environment, since this repo doesn't run a Windows CI matrix (ci: add Windows runner to CI matrix #634)

🤖 Generated with Claude Code

 #206)

On Windows, pytest's tmp_path roots are reused across sessions, and any file
handle held past ``close_components()`` blocks ``rmtree`` on the next session,
leaving stale dirs behind that trip ``FileExistsError [WinError 183]`` on the
following ``mkdir()`` (reported by @powerzist during #162).

Two layered changes:

- ``OnnxEmbedder.close()`` and ``FastEmbedReranker.close()`` now call
  ``gc.collect()`` after dropping ``self._model``, forcing the underlying ORT
  ``InferenceSession`` (mmap on the model file + thread-local arenas) to
  release before pytest reuses ``tmp_path``. Best-effort handle hygiene —
  helps but isn't fully reliable under Windows file-locking timing.
- The three ``components``-style fixtures and the two ``test_cli_ingest``
  Codex tests now ``mkdir(exist_ok=True)`` (with ``shutil.rmtree`` first where
  the dir gets populated with .md files). Each site links to #206 so the
  workaround stays visible if the underlying close paths regress.

``Storage.close()`` already runs ``PRAGMA wal_checkpoint(TRUNCATE)`` and
closes the read-pool — no change needed there.

Linux suite green (4012 passed). Windows confirmation by @powerzist on the
PR, since CI doesn't run a Windows matrix.

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
@memtomem
Copy link
Copy Markdown
Owner Author

memtomem commented May 3, 2026

@powerzist — could you give this a try in your Windows environment when you have a chance? You filed the original report in #206, and since the repo doesn't run a Windows CI matrix yet (#634), your reproduction is the only way to confirm the FileExistsError [WinError 183] actually goes away across consecutive pytest sessions. The relevant tests are test_cli_ingest.py::TestCodexIngestIntegration (skipped without Ollama, but the components fixture itself is exercised by most of the suite). No rush — happy to wait.

@memtomem memtomem merged commit 870c6a0 into main May 3, 2026
9 checks passed
@github-actions github-actions Bot locked and limited conversation to collaborators May 3, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Windows: test components fixture leaves SQLite/embedder handles open, blocking pytest cleanup

1 participant