Skip to content

Commit 9f59f4d

Browse files
authored
Release v1.3.1 (#22)
* Closes #17: Add default fallback (#18) * Add default fallback * Update changelog * Version fix * Fix test * Bump version * Fix mypy errors (#21) * Begin fixing mypy errors * Add types-requests dependency * Finish fixing mypy errors * Bump version * Remove CD pipeline * Fix mypy errors (#21) * Begin fixing mypy errors * Add types-requests dependency * Finish fixing mypy errors * Bump version * Remove CD pipeline
1 parent 7664f68 commit 9f59f4d

File tree

6 files changed

+57
-112
lines changed

6 files changed

+57
-112
lines changed

.github/workflows/cd.yml

Lines changed: 0 additions & 92 deletions
This file was deleted.

docs/changelog.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# Changelog
22

3+
## v1.3.1
4+
5+
* Fixed all outstanding mypy errors. ([#20](https://github.com/austind/retryhttp/issues/20)
6+
37
## v1.3.0
48

59
* Fix typing error ([#15](https://github.com/austind/retryhttp/pull/15))

pyproject.toml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ build-backend="setuptools.build_meta"
1010

1111
[project]
1212
name = "retryhttp"
13-
version = "1.3.0"
13+
version = "1.3.1"
1414
description = "Retry potentially transient HTTP errors in Python."
1515
license = {file = "LICENSE"}
1616
readme = "README.md"
@@ -40,6 +40,7 @@ dependencies = [
4040
"httpx",
4141
"pydantic",
4242
"requests",
43+
"types-requests",
4344
"tenacity"
4445
]
4546

@@ -51,6 +52,7 @@ httpx = [
5152
]
5253
requests = [
5354
"requests",
55+
"types-requests",
5456
"tenacity",
5557
]
5658
dev = [
@@ -59,6 +61,7 @@ dev = [
5961
"respx",
6062
"ruff",
6163
"nox",
64+
"types-requests",
6265
]
6366
docs = [
6467
"mkdocs",

retryhttp/_retry.py

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from typing import Any, Optional, Sequence, Tuple, Type, Union
1+
from typing import Any, Callable, Optional, Sequence, Tuple, Type, Union, overload
22

33
from tenacity import (
44
RetryCallState,
@@ -24,6 +24,32 @@
2424
from ._wait import wait_context_aware, wait_retry_after
2525

2626

27+
@overload
28+
def retry(func: F) -> F: ...
29+
30+
31+
@overload
32+
def retry(
33+
func: None = None,
34+
*,
35+
max_attempt_number: int = 3,
36+
retry_server_errors: bool = True,
37+
retry_network_errors: bool = True,
38+
retry_timeouts: bool = True,
39+
retry_rate_limited: bool = True,
40+
wait_server_errors: wait_base = wait_random_exponential(),
41+
wait_network_errors: wait_base = wait_exponential(),
42+
wait_timeouts: wait_base = wait_random_exponential(),
43+
wait_rate_limited: wait_base = wait_retry_after(),
44+
server_error_codes: Union[Sequence[int], int] = (500, 502, 503, 504),
45+
network_errors: Union[
46+
Type[BaseException], Tuple[Type[BaseException], ...], None
47+
] = None,
48+
timeouts: Union[Type[BaseException], Tuple[Type[BaseException], ...], None] = None,
49+
**kwargs: Any,
50+
) -> Callable[[F], F]: ...
51+
52+
2753
def retry(
2854
func: Optional[F] = None,
2955
*,
@@ -42,7 +68,7 @@ def retry(
4268
] = None,
4369
timeouts: Union[Type[BaseException], Tuple[Type[BaseException], ...], None] = None,
4470
**kwargs: Any,
45-
) -> F:
71+
) -> Union[F, Callable[[F], F]]:
4672
"""Retry potentially transient HTTP errors with sensible default behavior.
4773
4874
By default, retries the following errors, for a total of 3 attempts, with
@@ -105,7 +131,7 @@ def retry(
105131
if timeouts is None:
106132
timeouts = get_default_timeouts()
107133

108-
retry_strategies = []
134+
retry_strategies: list[retry_base] = []
109135
if retry_server_errors:
110136
retry_strategies.append(
111137
retry_if_server_error(server_error_codes=server_error_codes)

retryhttp/_utils.py

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,7 @@
2222
pass
2323

2424

25-
def get_default_network_errors() -> Tuple[
26-
Union[Type[httpx.NetworkError], Type[requests.ConnectionError]], ...
27-
]:
25+
def get_default_network_errors() -> Tuple[Type[BaseException], ...]:
2826
"""Get all network errors to use by default.
2927
3028
Args:
@@ -37,7 +35,7 @@ def get_default_network_errors() -> Tuple[
3735
N/A
3836
3937
"""
40-
exceptions = []
38+
exceptions: list[type[BaseException]] = []
4139
if _HTTPX_INSTALLED:
4240
exceptions.extend(
4341
[
@@ -56,41 +54,37 @@ def get_default_network_errors() -> Tuple[
5654
return tuple(exceptions)
5755

5856

59-
def get_default_timeouts() -> Tuple[
60-
Type[Union[httpx.TimeoutException, requests.Timeout]], ...
61-
]:
57+
def get_default_timeouts() -> Tuple[Type[BaseException], ...]:
6258
"""Get all timeout exceptions to use by default.
6359
6460
Returns:
6561
tuple: Timeout exceptions.
6662
6763
"""
68-
exceptions = []
64+
exceptions: list[Type[BaseException]] = []
6965
if _HTTPX_INSTALLED:
7066
exceptions.append(httpx.TimeoutException)
7167
if _REQUESTS_INSTALLED:
7268
exceptions.append(requests.Timeout)
7369
return tuple(exceptions)
7470

7571

76-
def get_default_http_status_exceptions() -> Tuple[
77-
Union[Type[httpx.HTTPStatusError], Type[requests.HTTPError]], ...
78-
]:
72+
def get_default_http_status_exceptions() -> Tuple[Type[BaseException], ...]:
7973
"""Get default HTTP status 4xx or 5xx exceptions.
8074
8175
Returns:
8276
tuple: HTTP status exceptions.
8377
8478
"""
85-
exceptions = []
79+
exceptions: list[Type[BaseException]] = []
8680
if _HTTPX_INSTALLED:
8781
exceptions.append(httpx.HTTPStatusError)
8882
if _REQUESTS_INSTALLED:
8983
exceptions.append(requests.HTTPError)
9084
return tuple(exceptions)
9185

9286

93-
def is_rate_limited(exc: Union[BaseException, None]) -> bool:
87+
def is_rate_limited(exc: Optional[BaseException]) -> bool:
9488
"""Whether a given exception indicates the user has been rate limited.
9589
9690
Args:
@@ -100,7 +94,10 @@ def is_rate_limited(exc: Union[BaseException, None]) -> bool:
10094
bool: Whether exc indicates rate limiting.
10195
10296
"""
103-
if isinstance(exc, get_default_http_status_exceptions()):
97+
if exc is None:
98+
return False
99+
exceptions = get_default_http_status_exceptions()
100+
if isinstance(exc, exceptions) and hasattr(exc, "response"):
104101
return exc.response.status_code == 429
105102
return False
106103

@@ -120,9 +117,12 @@ def is_server_error(
120117
bool: whether exc indicates an error included in status_codes.
121118
122119
"""
120+
if exc is None:
121+
return False
123122
if isinstance(status_codes, int):
124123
status_codes = [status_codes]
125-
if isinstance(exc, get_default_http_status_exceptions()):
124+
exceptions = get_default_http_status_exceptions()
125+
if isinstance(exc, exceptions) and hasattr(exc, "response"):
126126
return exc.response.status_code in status_codes
127127
return False
128128

retryhttp/_wait.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,11 @@ def _get_wait_value(self, retry_state: RetryCallState) -> float:
6868
"""
6969
if retry_state.outcome:
7070
exc = retry_state.outcome.exception()
71-
if isinstance(exc, get_default_http_status_exceptions()):
71+
if exc is None:
72+
return 0
73+
if isinstance(exc, get_default_http_status_exceptions()) and hasattr(
74+
exc, "response"
75+
):
7276
value = exc.response.headers.get(self.header)
7377
if value is None:
7478
raise ValueError(f"Header not present: {self.header}")

0 commit comments

Comments
 (0)