Skip to content

Commit 48d1503

Browse files
Update client to respect the newer RateLimit header (#115)
* update test to target new header (currently failing) * fix test * bump version
1 parent 8dd7fa3 commit 48d1503

File tree

2 files changed

+29
-3
lines changed

2 files changed

+29
-3
lines changed

closeio_api/__init__.py

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import contextlib
22
import logging
3+
import re
34
import time
45

56
from random import uniform
@@ -12,7 +13,7 @@
1213

1314
# To update the package version, change this variable. This variable is also
1415
# read by setup.py when installing the package.
15-
__version__ = '2.0'
16+
__version__ = '2.1'
1617

1718
class APIError(Exception):
1819
"""Raised when sending a request to the API failed."""
@@ -146,8 +147,20 @@ def _get_rate_limit_sleep_time(self, response):
146147
"""Get rate limit window expiration time from response if the response
147148
status code is 429.
148149
"""
150+
with contextlib.suppress(KeyError):
151+
rate_limit = response.headers["RateLimit"]
152+
# we don't actually need all these values, but per the RFC:
153+
# "Malformed RateLimit header fields MUST be ignored."
154+
match = re.match(
155+
r"limit=(\d+), remaining=(\d+), reset=(\d+)", rate_limit
156+
)
157+
if match:
158+
limit, remaining, reset = match.groups()
159+
return float(reset)
160+
149161
with contextlib.suppress(KeyError):
150162
return float(response.headers["Retry-After"])
163+
151164
with contextlib.suppress(KeyError):
152165
return float(response.headers["RateLimit-Reset"])
153166

tests/test_api.py

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,20 @@ def request_callback(request):
107107
assert resp['data'][0]['name'] == 'Sample Lead'
108108

109109
@responses.activate
110-
def test_retry_on_rate_limit(api_client):
110+
@pytest.mark.parametrize(
111+
"headers",
112+
[
113+
{"RateLimit-Reset": "1"},
114+
{"Retry-After": "1"},
115+
{"RateLimit": "limit=100, remaining=0, reset=1"},
116+
{
117+
"Retry-After": "1",
118+
"RateLimit-Reset": "1",
119+
"RateLimit": "limit=100, remaining=0, reset=1",
120+
},
121+
]
122+
)
123+
def test_retry_on_rate_limit(api_client, headers):
111124
with responses.RequestsMock() as rsps:
112125

113126
# Rate limit the first request and suggest it can be retried in 1 sec.
@@ -117,7 +130,7 @@ def test_retry_on_rate_limit(api_client):
117130
body=json.dumps({}),
118131
status=429,
119132
content_type='application/json',
120-
headers={"Retry-After": "1", "RateLimit-Reset": "1"}
133+
headers=headers,
121134
)
122135

123136
# Respond correctly to the second request.

0 commit comments

Comments
 (0)