| 1145 | @pytest.mark.respx(base_url=base_url) |
| 1146 | @pytest.mark.parametrize(class="st">"failure_mode", [class="st">"status", class="st">"exception"]) |
| 1147 | def test_retries_taken( |
| 1148 | self, |
| 1149 | client: OpenAI, |
| 1150 | failures_before_success: int, |
| 1151 | failure_mode: Literal[class="st">"status", class="st">"exception"], |
| 1152 | respx_mock: MockRouter, |
| 1153 | ) -> None: |
| 1154 | client = client.with_options(max_retries=4) |
| 1155 | |
| 1156 | nb_retries = 0 |
| 1157 | |
| 1158 | def retry_handler(_request: httpx.Request) -> httpx.Response: |
| 1159 | nonlocal nb_retries |
| 1160 | if nb_retries < failures_before_success: |
| 1161 | nb_retries += 1 |
| 1162 | if failure_mode == class="st">"exception": |
| 1163 | raise RuntimeError(class="st">"oops") |
| 1164 | return httpx.Response(500) |
| 1165 | return httpx.Response(200) |
| 1166 | |
| 1167 | respx_mock.post(class="st">"/chat/completions").mock(side_effect=retry_handler) |
| 1168 | |
| 1169 | response = client.chat.completions.with_raw_response.create( |
| 1170 | messages=[ |
| 1171 | { |
| 1172 | class="st">"content": class="st">"string", |
| 1173 | class="st">"role": class="st">"developer", |
| 1174 | } |
| 1175 | ], |
| 1176 | model=class="st">"gpt-5.4", |
| 1177 | ) |
| 1178 | |
| 1179 | assert response.retries_taken == failures_before_success |
| 1180 | assert int(response.http_request.headers.get(class="st">"x-stainless-retry-count")) == failures_before_success |
| 1181 | |
| 1182 | @pytest.mark.parametrize(class="st">"failures_before_success", [0, 2, 4]) |
| 1183 | @mock.patch(class="st">"openai._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout) |