diff --git a/thousandeyes-sdk-core/pyproject.toml b/thousandeyes-sdk-core/pyproject.toml index a40bd17c..fd54435e 100644 --- a/thousandeyes-sdk-core/pyproject.toml +++ b/thousandeyes-sdk-core/pyproject.toml @@ -9,7 +9,7 @@ description = "ThousandEyes SDK Core" license = { file = "LICENSE" } requires-python = ">= 3.8" dependencies = [ - "urllib3 >= 2.0.0", + "urllib3 >= 2.6.3", "python-dateutil >=2.8.2", "pydantic >=2.1.0", "typing-extensions >=4.7.1", diff --git a/thousandeyes-sdk-core/src/thousandeyes_sdk/core/thousandeyes_retry.py b/thousandeyes-sdk-core/src/thousandeyes_sdk/core/thousandeyes_retry.py index ecc8d90f..4427020f 100644 --- a/thousandeyes-sdk-core/src/thousandeyes_sdk/core/thousandeyes_retry.py +++ b/thousandeyes-sdk-core/src/thousandeyes_sdk/core/thousandeyes_retry.py @@ -48,11 +48,12 @@ class ThousandEyesRetry(Retry): history: Optional[tuple[RequestHistory, ...]] = None, respect_retry_after_header: bool = True, remove_headers_on_redirect: Collection[str] = Retry.DEFAULT_REMOVE_HEADERS_ON_REDIRECT, - backoff_jitter: float = 0.0) -> None: + backoff_jitter: float = 0.0, + retry_after_max: int = Retry.DEFAULT_RETRY_AFTER_MAX) -> None: super().__init__(total, connect, read, redirect, status, other, allowed_methods, status_forcelist, backoff_factor, backoff_max, raise_on_redirect, raise_on_status, history, respect_retry_after_header, - remove_headers_on_redirect, backoff_jitter) + remove_headers_on_redirect, backoff_jitter, retry_after_max) def is_retry(self, method: str, status_code: int, has_retry_after: bool = False) -> bool: # Always retry on 429, regardless of method or status_forcelist diff --git a/thousandeyes-sdk-core/test/test_thousandeyes_retry.py b/thousandeyes-sdk-core/test/test_thousandeyes_retry.py index 944e5dd6..a3e460ff 100644 --- a/thousandeyes-sdk-core/test/test_thousandeyes_retry.py +++ b/thousandeyes-sdk-core/test/test_thousandeyes_retry.py @@ -41,3 +41,19 @@ def test_parse_reset_header_invalid(): retry = ThousandEyesRetry() assert retry._parse_reset_header("invalid") is None assert retry._parse_reset_header(None) is None + + +def test_retry_new_clones_with_retry_after_max(): + retry = ThousandEyesRetry(retry_after_max=3600) + cloned = retry.new() + assert isinstance(cloned, ThousandEyesRetry) + assert cloned.retry_after_max == 3600 + + +def test_retry_increment_on_429(): + response = Mock(spec=HTTPResponse) + response.status = 429 + response.headers = {"Retry-After": "0"} + retry = ThousandEyesRetry(total=1) + new_retry = retry.increment(method="GET", url="/test", response=response) + assert isinstance(new_retry, ThousandEyesRetry)