11from contextlib import suppress
22from datetime import datetime
33from email .utils import parsedate_to_datetime
4- from typing import Any , Awaitable , Callable , Dict , Optional , Set
4+ from typing import (
5+ Any ,
6+ Awaitable ,
7+ Callable ,
8+ Dict ,
9+ Optional ,
10+ Set ,
11+ Literal ,
12+ AsyncGenerator ,
13+ )
514
615import httpx
716import tenacity
@@ -17,14 +26,14 @@ def __init__(
1726 self ,
1827 * ,
1928 configuration : Configuration ,
20- request_type : Optional [str ] = None ,
29+ method : Optional [str ] = None ,
2130 url : Optional [str ] = None ,
2231 body : Optional [Dict ] = None ,
2332 ** httpx_async_client_kwargs ,
2433 ):
2534 self .configuration = configuration
2635 self ._client = httpx .AsyncClient (** httpx_async_client_kwargs )
27- self ._callback = getattr (self ._client , request_type ) if request_type else None
36+ self ._callback = getattr (self ._client , method ) if method else None
2837 self ._url = url
2938 self ._body = body
3039 if self ._callback is not None :
@@ -77,6 +86,30 @@ async def _():
7786
7887 return await _ ()
7988
89+ async def _stream (
90+ self , method : Literal ["GET" ], url : str , * args , ** kwargs
91+ ) -> AsyncGenerator [bytes , None ]:
92+ n_attempts = self .configuration .retries .total
93+ assert isinstance (n_attempts , int )
94+
95+ @tenacity .retry (
96+ reraise = True ,
97+ wait = self ._wait_callback ,
98+ stop = tenacity .stop_after_attempt (n_attempts ),
99+ retry = tenacity .retry_if_exception_type (httpx .HTTPStatusError ),
100+ )
101+ async def _ () -> AsyncGenerator [bytes , None ]:
102+ async with self ._client .stream (
103+ method = method , url = url , * args , ** kwargs
104+ ) as response :
105+ if response .status_code in self .configuration .retries .status_forcelist :
106+ response .raise_for_status ()
107+ async for chunk in response .aiter_bytes ():
108+ yield chunk
109+
110+ async for chunk in _ ():
111+ yield chunk
112+
80113 async def put (self , * args , ** kwargs ) -> httpx .Response :
81114 return await self ._request (self ._client .put , * args , ** kwargs )
82115
@@ -92,6 +125,12 @@ async def patch(self, *args, **kwargs) -> httpx.Response:
92125 async def get (self , * args , ** kwargs ) -> httpx .Response :
93126 return await self ._request (self ._client .get , * args , ** kwargs )
94127
128+ async def stream (
129+ self , method : Literal ["GET" ], url : str , * args , ** kwargs
130+ ) -> AsyncGenerator [bytes , None ]:
131+ async for chunk in self ._stream (method = method , url = url , * args , ** kwargs ):
132+ yield chunk
133+
95134 def _wait_callback (self , retry_state : tenacity .RetryCallState ) -> int :
96135 assert retry_state .outcome is not None
97136 if retry_state .outcome and retry_state .outcome .exception ():
0 commit comments