@@ -758,6 +758,65 @@ def test_retrying_status_errors_doesnt_leak(self, respx_mock: MockRouter) -> Non
758758
759759 assert _get_open_connections (self .client ) == 0
760760
761+ @pytest .mark .parametrize ("failures_before_success" , [0 , 2 , 4 ])
762+ @mock .patch ("openai._base_client.BaseClient._calculate_retry_timeout" , _low_retry_timeout )
763+ @pytest .mark .respx (base_url = base_url )
764+ def test_retries_taken (self , client : OpenAI , failures_before_success : int , respx_mock : MockRouter ) -> None :
765+ client = client .with_options (max_retries = 4 )
766+
767+ nb_retries = 0
768+
769+ def retry_handler (_request : httpx .Request ) -> httpx .Response :
770+ nonlocal nb_retries
771+ if nb_retries < failures_before_success :
772+ nb_retries += 1
773+ return httpx .Response (500 )
774+ return httpx .Response (200 )
775+
776+ respx_mock .post ("/chat/completions" ).mock (side_effect = retry_handler )
777+
778+ response = client .chat .completions .with_raw_response .create (
779+ messages = [
780+ {
781+ "content" : "content" ,
782+ "role" : "system" ,
783+ }
784+ ],
785+ model = "gpt-4-turbo" ,
786+ )
787+
788+ assert response .retries_taken == failures_before_success
789+
790+ @pytest .mark .parametrize ("failures_before_success" , [0 , 2 , 4 ])
791+ @mock .patch ("openai._base_client.BaseClient._calculate_retry_timeout" , _low_retry_timeout )
792+ @pytest .mark .respx (base_url = base_url )
793+ def test_retries_taken_new_response_class (
794+ self , client : OpenAI , failures_before_success : int , respx_mock : MockRouter
795+ ) -> None :
796+ client = client .with_options (max_retries = 4 )
797+
798+ nb_retries = 0
799+
800+ def retry_handler (_request : httpx .Request ) -> httpx .Response :
801+ nonlocal nb_retries
802+ if nb_retries < failures_before_success :
803+ nb_retries += 1
804+ return httpx .Response (500 )
805+ return httpx .Response (200 )
806+
807+ respx_mock .post ("/chat/completions" ).mock (side_effect = retry_handler )
808+
809+ with client .chat .completions .with_streaming_response .create (
810+ messages = [
811+ {
812+ "content" : "content" ,
813+ "role" : "system" ,
814+ }
815+ ],
816+ model = "gpt-4-turbo" ,
817+ ) as response :
818+ assert response .retries_taken == failures_before_success
819+
761820
762821class TestAsyncOpenAI :
763822 client = AsyncOpenAI (base_url = base_url , api_key = api_key , _strict_response_validation = True )
@@ -1488,3 +1547,66 @@ async def test_retrying_status_errors_doesnt_leak(self, respx_mock: MockRouter)
14881547 )
14891548
14901549 assert _get_open_connections (self .client ) == 0
1550+
1551+ @pytest .mark .parametrize ("failures_before_success" , [0 , 2 , 4 ])
1552+ @mock .patch ("openai._base_client.BaseClient._calculate_retry_timeout" , _low_retry_timeout )
1553+ @pytest .mark .respx (base_url = base_url )
1554+ @pytest .mark .asyncio
1555+ async def test_retries_taken (
1556+ self , async_client : AsyncOpenAI , failures_before_success : int , respx_mock : MockRouter
1557+ ) -> None :
1558+ client = async_client .with_options (max_retries = 4 )
1559+
1560+ nb_retries = 0
1561+
1562+ def retry_handler (_request : httpx .Request ) -> httpx .Response :
1563+ nonlocal nb_retries
1564+ if nb_retries < failures_before_success :
1565+ nb_retries += 1
1566+ return httpx .Response (500 )
1567+ return httpx .Response (200 )
1568+
1569+ respx_mock .post ("/chat/completions" ).mock (side_effect = retry_handler )
1570+
1571+ response = await client .chat .completions .with_raw_response .create (
1572+ messages = [
1573+ {
1574+ "content" : "content" ,
1575+ "role" : "system" ,
1576+ }
1577+ ],
1578+ model = "gpt-4-turbo" ,
1579+ )
1580+
1581+ assert response .retries_taken == failures_before_success
1582+
1583+ @pytest .mark .parametrize ("failures_before_success" , [0 , 2 , 4 ])
1584+ @mock .patch ("openai._base_client.BaseClient._calculate_retry_timeout" , _low_retry_timeout )
1585+ @pytest .mark .respx (base_url = base_url )
1586+ @pytest .mark .asyncio
1587+ async def test_retries_taken_new_response_class (
1588+ self , async_client : AsyncOpenAI , failures_before_success : int , respx_mock : MockRouter
1589+ ) -> None :
1590+ client = async_client .with_options (max_retries = 4 )
1591+
1592+ nb_retries = 0
1593+
1594+ def retry_handler (_request : httpx .Request ) -> httpx .Response :
1595+ nonlocal nb_retries
1596+ if nb_retries < failures_before_success :
1597+ nb_retries += 1
1598+ return httpx .Response (500 )
1599+ return httpx .Response (200 )
1600+
1601+ respx_mock .post ("/chat/completions" ).mock (side_effect = retry_handler )
1602+
1603+ async with client .chat .completions .with_streaming_response .create (
1604+ messages = [
1605+ {
1606+ "content" : "content" ,
1607+ "role" : "system" ,
1608+ }
1609+ ],
1610+ model = "gpt-4-turbo" ,
1611+ ) as response :
1612+ assert response .retries_taken == failures_before_success
0 commit comments