quart icon indicating copy to clipboard operation
quart copied to clipboard

ResourceWarning from `DataBody.__aiter__`

Open graingert opened this issue 2 years ago • 1 comments

from quart-trio I get a:

ResourceWarning: Async generator 'quart.wrappers.response.DataBody.__aiter__.<locals>._aiter' was garbage collected before it had been exhausted. Surround its use in 'async with aclosing(...):' to ensure that it gets cleaned up as soon as you're done using it.

Environment:

  • Python version:
  • Quart version:

graingert avatar Dec 18 '23 12:12 graingert

I'm also unsure how to test this, however I've an alternative fix,

diff --git a/src/quart/wrappers/response.py b/src/quart/wrappers/response.py
index 9460c2e..6b0b364 100644
--- a/src/quart/wrappers/response.py
+++ b/src/quart/wrappers/response.py
@@ -70,18 +70,20 @@ class DataBody(ResponseBody):
         self.data = data
         self.begin = 0
         self.end = len(self.data)
+        self.iter: AsyncGenerator[bytes, None]
 
     async def __aenter__(self) -> DataBody:
+        async def _aiter() -> AsyncGenerator[bytes, None]:
+            yield self.data[self.begin : self.end]
+
+        self.iter = _aiter()
         return self
 
     async def __aexit__(self, exc_type: type, exc_value: BaseException, tb: TracebackType) -> None:
-        pass
+        await self.iter.aclose()
 
     def __aiter__(self) -> AsyncIterator:
-        async def _aiter() -> AsyncGenerator[bytes, None]:
-            yield self.data[self.begin : self.end]
-
-        return _aiter()
+        return self.iter
 
     async def make_conditional(self, begin: int, end: int | None) -> int:
         self.begin = begin

What do you think of this? I prefer it as it is more similar to the IterableBody

pgjones avatar Feb 11 '24 20:02 pgjones