77import re
88import typing
99import urllib .request
10- from collections .abc import Mapping
10+ from collections .abc import AsyncGenerator , Mapping
1111from http .cookiejar import Cookie , CookieJar
1212
1313from ._content import ByteStream , UnattachedStream , encode_request , encode_response
4646 SyncByteStream ,
4747)
4848from ._urls import URL
49- from ._utils import to_bytes_or_str , to_str
49+ from ._utils import safe_async_iterate , to_bytes_or_str , to_str
5050
5151__all__ = ["Cookies" , "Headers" , "Request" , "Response" ]
5252
@@ -979,9 +979,7 @@ async def aread(self) -> bytes:
979979 self ._content = b"" .join ([part async for part in self .aiter_bytes ()])
980980 return self ._content
981981
982- async def aiter_bytes (
983- self , chunk_size : int | None = None
984- ) -> typing .AsyncIterator [bytes ]:
982+ async def aiter_bytes (self , chunk_size : int | None = None ) -> AsyncGenerator [bytes ]:
985983 """
986984 A byte-iterator over the decoded response content.
987985 This allows us to handle gzip, deflate, brotli, and zstd encoded responses.
@@ -994,19 +992,19 @@ async def aiter_bytes(
994992 decoder = self ._get_content_decoder ()
995993 chunker = ByteChunker (chunk_size = chunk_size )
996994 with request_context (request = self ._request ):
997- async for raw_bytes in self .aiter_raw ():
998- decoded = decoder .decode (raw_bytes )
999- for chunk in chunker .decode (decoded ):
1000- yield chunk
995+ async with safe_async_iterate (self .aiter_raw ()) as iterator :
996+ async for raw_bytes in iterator :
997+ decoded = decoder .decode (raw_bytes )
998+ for chunk in chunker .decode (decoded ):
999+ yield chunk
1000+
10011001 decoded = decoder .flush ()
10021002 for chunk in chunker .decode (decoded ):
10031003 yield chunk # pragma: no cover
10041004 for chunk in chunker .flush ():
10051005 yield chunk
10061006
1007- async def aiter_text (
1008- self , chunk_size : int | None = None
1009- ) -> typing .AsyncIterator [str ]:
1007+ async def aiter_text (self , chunk_size : int | None = None ) -> AsyncGenerator [str ]:
10101008 """
10111009 A str-iterator over the decoded response content
10121010 that handles both gzip, deflate, etc but also detects the content's
@@ -1015,28 +1013,28 @@ async def aiter_text(
10151013 decoder = TextDecoder (encoding = self .encoding or "utf-8" )
10161014 chunker = TextChunker (chunk_size = chunk_size )
10171015 with request_context (request = self ._request ):
1018- async for byte_content in self .aiter_bytes ():
1019- text_content = decoder .decode (byte_content )
1020- for chunk in chunker .decode (text_content ):
1021- yield chunk
1016+ async with safe_async_iterate (self .aiter_bytes ()) as iterator :
1017+ async for byte_content in iterator :
1018+ text_content = decoder .decode (byte_content )
1019+ for chunk in chunker .decode (text_content ):
1020+ yield chunk
10221021 text_content = decoder .flush ()
10231022 for chunk in chunker .decode (text_content ):
10241023 yield chunk # pragma: no cover
10251024 for chunk in chunker .flush ():
10261025 yield chunk
10271026
1028- async def aiter_lines (self ) -> typing . AsyncIterator [str ]:
1027+ async def aiter_lines (self ) -> AsyncGenerator [str ]:
10291028 decoder = LineDecoder ()
10301029 with request_context (request = self ._request ):
1031- async for text in self .aiter_text ():
1032- for line in decoder .decode (text ):
1033- yield line
1030+ async with safe_async_iterate (self .aiter_text ()) as iterator :
1031+ async for text in iterator :
1032+ for line in decoder .decode (text ):
1033+ yield line
10341034 for line in decoder .flush ():
10351035 yield line
10361036
1037- async def aiter_raw (
1038- self , chunk_size : int | None = None
1039- ) -> typing .AsyncIterator [bytes ]:
1037+ async def aiter_raw (self , chunk_size : int | None = None ) -> AsyncGenerator [bytes ]:
10401038 """
10411039 A byte-iterator over the raw response content.
10421040 """
@@ -1052,10 +1050,11 @@ async def aiter_raw(
10521050 chunker = ByteChunker (chunk_size = chunk_size )
10531051
10541052 with request_context (request = self ._request ):
1055- async for raw_stream_bytes in self .stream :
1056- self ._num_bytes_downloaded += len (raw_stream_bytes )
1057- for chunk in chunker .decode (raw_stream_bytes ):
1058- yield chunk
1053+ async with safe_async_iterate (self .stream ) as iterator :
1054+ async for raw_stream_bytes in iterator :
1055+ self ._num_bytes_downloaded += len (raw_stream_bytes )
1056+ for chunk in chunker .decode (raw_stream_bytes ):
1057+ yield chunk
10591058
10601059 for chunk in chunker .flush ():
10611060 yield chunk
0 commit comments