From e0a3bdbbe1a5700c122088a53b3930a45f7db500 Mon Sep 17 00:00:00 2001 From: courier-codegen Date: Thu, 24 Sep 2026 00:06:21 +0000 Subject: [PATCH] chore(api): regenerate SDK --- src/courier/_base_client.py | 8 ++++---- tests/test_client.py | 40 +++++++++++++++++++++++++++++++++++-- 2 files changed, 42 insertions(+), 6 deletions(-) diff --git a/src/courier/_base_client.py b/src/courier/_base_client.py index 00130ea..baa8306 100644 --- a/src/courier/_base_client.py +++ b/src/courier/_base_client.py @@ -1023,8 +1023,8 @@ def request( log.debug("Raising timeout error") raise APITimeoutError(request=request) from err - except Exception as err: - log.debug("Encountered Exception", exc_info=True) + except httpx.RequestError as err: + log.debug("Encountered httpx.RequestError", exc_info=True) if remaining_retries > 0: self._sleep_for_retry( @@ -1607,8 +1607,8 @@ async def request( log.debug("Raising timeout error") raise APITimeoutError(request=request) from err - except Exception as err: - log.debug("Encountered Exception", exc_info=True) + except httpx.RequestError as err: + log.debug("Encountered httpx.RequestError", exc_info=True) if remaining_retries > 0: await self._sleep_for_retry( diff --git a/tests/test_client.py b/tests/test_client.py index 30d1d91..3fc52e2 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -909,7 +909,7 @@ def retry_handler(_request: httpx.Request) -> httpx.Response: if nb_retries < failures_before_success: nb_retries += 1 if failure_mode == "exception": - raise RuntimeError("oops") + raise httpx.ConnectError("oops") return httpx.Response(500) return httpx.Response(200) @@ -920,6 +920,23 @@ def retry_handler(_request: httpx.Request) -> httpx.Response: assert response.retries_taken == failures_before_success assert int(response.http_request.headers.get("x-stainless-retry-count")) == failures_before_success + @mock.patch("courier._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout) + @pytest.mark.respx(base_url=base_url) + def test_non_transport_exception_is_not_retried(self, client: Courier, respx_mock: MockRouter) -> None: + # Stands in for Celery's SoftTimeLimitExceeded, which a signal handler raises + # mid-request. It is not a network failure, so it must propagate unretried. + class TaskCancelled(Exception): + pass + + client = client.with_options(max_retries=4) + + respx_mock.post("/send").mock(side_effect=TaskCancelled()) + + with pytest.raises(TaskCancelled): + client.send.with_raw_response.message(message={}) + + assert len(respx_mock.calls) == 1 + @pytest.mark.parametrize("failures_before_success", [0, 2, 4]) @mock.patch("courier._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout) @pytest.mark.respx(base_url=base_url) @@ -1841,7 +1858,7 @@ def retry_handler(_request: httpx.Request) -> httpx.Response: if nb_retries < failures_before_success: nb_retries += 1 if failure_mode == "exception": - raise RuntimeError("oops") + raise httpx.ConnectError("oops") return httpx.Response(500) return httpx.Response(200) @@ -1852,6 +1869,25 @@ def retry_handler(_request: httpx.Request) -> httpx.Response: assert response.retries_taken == failures_before_success assert int(response.http_request.headers.get("x-stainless-retry-count")) == failures_before_success + @mock.patch("courier._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout) + @pytest.mark.respx(base_url=base_url) + async def test_non_transport_exception_is_not_retried( + self, async_client: AsyncCourier, respx_mock: MockRouter + ) -> None: + # Stands in for Celery's SoftTimeLimitExceeded, which a signal handler raises + # mid-request. It is not a network failure, so it must propagate unretried. + class TaskCancelled(Exception): + pass + + client = async_client.with_options(max_retries=4) + + respx_mock.post("/send").mock(side_effect=TaskCancelled()) + + with pytest.raises(TaskCancelled): + await client.send.with_raw_response.message(message={}) + + assert len(respx_mock.calls) == 1 + @pytest.mark.parametrize("failures_before_success", [0, 2, 4]) @mock.patch("courier._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout) @pytest.mark.respx(base_url=base_url)