From 2640aeac9fed1a40e60fcd2353a2753a0e6b0230 Mon Sep 17 00:00:00 2001 From: Austin de Coup-Crank Date: Tue, 4 Feb 2025 19:32:10 -0600 Subject: [PATCH 1/2] Closes #17: Add default fallback (#18) * Add default fallback * Update changelog * Version fix * Fix test --- docs/changelog.md | 5 +++++ retryhttp/_wait.py | 12 +++++++----- tests/test_wait.py | 2 +- 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/docs/changelog.md b/docs/changelog.md index 4b5e878..c1aefe1 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -1,5 +1,10 @@ # Changelog +## v1.3.0 + +* Fix typing error ([#15](https://github.com/austind/retryhttp/pull/15)) +* Add default fallback wait strategy [`tenacity.wait_random_exponential`][] to [`retryhttp.wait_from_header`][] and [`retryhttp.wait_retry_after`][] ([#17](https://github.com/austind/retryhttp/pull/)) + ## v1.2.0 * Added `wait_max` argument to [`retryhttp.wait_from_header`][] and [`retryhttp.wait_retry_after`][], which defaults to 120.0 seconds. diff --git a/retryhttp/_wait.py b/retryhttp/_wait.py index 008524f..d6ddec7 100644 --- a/retryhttp/_wait.py +++ b/retryhttp/_wait.py @@ -32,7 +32,7 @@ class wait_from_header(wait_base): program will hang if the server responds with an excessive wait value. fallback (wait_base): Wait strategy to use if `header` is not present, or unable to parse to a `float` value, or if value parsed from header - exceeds `wait_max`. Defaults to `None`. + exceeds `wait_max`. Defaults to `tenacity.wait_exponential`. Raises: ValueError: If `fallback` is `None`, and any one of the following is true: @@ -47,7 +47,7 @@ def __init__( self, header: str, wait_max: Union[PositiveFloat, PositiveInt, None] = 120.0, - fallback: Optional[wait_base] = None, + fallback: Optional[wait_base] = wait_exponential(), ) -> None: self.header = header self.wait_max = float(wait_max) if wait_max else None @@ -69,7 +69,9 @@ def _get_wait_value(self, retry_state: RetryCallState) -> float: if retry_state.outcome: exc = retry_state.outcome.exception() if isinstance(exc, get_default_http_status_exceptions()): - value = exc.response.headers.get(self.header, "") + value = exc.response.headers.get(self.header) + if value is None: + raise ValueError(f"Header not present: {self.header}") if re.match(r"^\d+$", value): return float(value) else: @@ -115,7 +117,7 @@ class wait_retry_after(wait_from_header): program will hang if the server responds with an excessive wait value. fallback (wait_base): Wait strategy to use if `header` is not present, or unable to parse to a `float` value, or if value parsed from header - exceeds `wait_max`. Defaults to `None`. + exceeds `wait_max`. Defaults to `tenacity.wait_exponential()`. Raises: ValueError: If `fallback` is `None`, and any one of the following is true: @@ -129,7 +131,7 @@ class wait_retry_after(wait_from_header): def __init__( self, wait_max: Union[PositiveFloat, PositiveInt, None] = 120.0, - fallback: Optional[wait_base] = None, + fallback: Optional[wait_base] = wait_exponential(), ) -> None: super().__init__(header="Retry-After", wait_max=wait_max, fallback=fallback) diff --git a/tests/test_wait.py b/tests/test_wait.py index aac4052..7df38a4 100644 --- a/tests/test_wait.py +++ b/tests/test_wait.py @@ -11,7 +11,7 @@ @retry( retry=retry_if_server_error(), - wait=wait_from_header(header="Retry-After", wait_max=5), + wait=wait_from_header(header="Retry-After", wait_max=5, fallback=None), stop=stop_after_attempt(3), ) def planned_downtime_impatient_no_fallback(): From 244fd4514446d9b16cc3276f37e2179e4035a616 Mon Sep 17 00:00:00 2001 From: Austin de Coup-Crank Date: Tue, 4 Feb 2025 19:34:37 -0600 Subject: [PATCH 2/2] Bump version --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 6d938a5..4f917c9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -10,7 +10,7 @@ build-backend="setuptools.build_meta" [project] name = "retryhttp" -version = "1.2.0" +version = "1.3.0" description = "Retry potentially transient HTTP errors in Python." license = {file = "LICENSE"} readme = "README.md"