Ensure all async generators are explicitly closed

Merged
KL
6mo ago
+160-90

Summary

Backports encode/httpcore#1019 by @agronholm into our vendored src/httpcore/.

The upstream PR wraps async for iterations over request/response body streams in a safe_async_iterate() helper that explicitly calls aclose() in a try/finally, rather than relying on the GC.

Under trio this surfaced for us as test_write_timeout[trio] failing with PytestUnraisableExceptionWarning: Exception ignored in: <async_generator object ByteStream.__aiter__> during teardown. The exception was the body iterator being garbage-collected after the timeout aborted the request, with the trio event loop already torn down.

Test plan

  • uv run pytest — 1417 passed, 1 skipped, 0 failed (was 1416 passed, 1 failed)
  • tests/test_timeouts.py::test_write_timeout[trio] now passes
  • CI green on all Python versions

AI Disclaimer

This PR was developed with the assistance of either Claude or Codex. I've reviewed and verified the changes.