Skip to content

Commit 9312b51

Browse files
committed
Fix rate limit parsing
1 parent 8785e35 commit 9312b51

File tree

4 files changed

+87
-14
lines changed

4 files changed

+87
-14
lines changed

.vscode/settings.json

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,10 @@
44
"flake8.importStrategy": "fromEnvironment",
55
"mypy-type-checker.importStrategy": "fromEnvironment",
66
"isort.importStrategy": "fromEnvironment",
7-
"black-formatter.importStrategy": "fromEnvironment"
7+
"black-formatter.importStrategy": "fromEnvironment",
8+
"workbench.colorCustomizations": {
9+
"activityBar.background": "#121D85",
10+
"titleBar.activeBackground": "#1A28BA",
11+
"titleBar.activeForeground": "#F9FAFE"
12+
}
813
}

descope/auth.py

Lines changed: 28 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -105,18 +105,34 @@ def __init__(
105105
self.public_keys = {kid: (pub_key, alg)}
106106

107107
def _raise_rate_limit_exception(self, response):
108-
resp = response.json()
109-
raise RateLimitException(
110-
resp.get("errorCode", HTTPStatus.TOO_MANY_REQUESTS),
111-
ERROR_TYPE_API_RATE_LIMIT,
112-
resp.get("errorDescription", ""),
113-
resp.get("errorMessage", ""),
114-
rate_limit_parameters={
115-
API_RATE_LIMIT_RETRY_AFTER_HEADER: int(
116-
response.headers.get(API_RATE_LIMIT_RETRY_AFTER_HEADER, 0)
117-
)
118-
},
119-
)
108+
try:
109+
resp = response.json()
110+
raise RateLimitException(
111+
resp.get("errorCode", HTTPStatus.TOO_MANY_REQUESTS),
112+
ERROR_TYPE_API_RATE_LIMIT,
113+
resp.get("errorDescription", ""),
114+
resp.get("errorMessage", ""),
115+
rate_limit_parameters={
116+
API_RATE_LIMIT_RETRY_AFTER_HEADER: self._parse_retry_after(
117+
response.headers
118+
)
119+
},
120+
)
121+
except RateLimitException:
122+
raise
123+
except Exception as e:
124+
raise RateLimitException(
125+
status_code=HTTPStatus.TOO_MANY_REQUESTS,
126+
error_type=ERROR_TYPE_API_RATE_LIMIT,
127+
error_message=ERROR_TYPE_API_RATE_LIMIT,
128+
error_description=ERROR_TYPE_API_RATE_LIMIT,
129+
)
130+
131+
def _parse_retry_after(self, headers):
132+
try:
133+
return int(headers.get(API_RATE_LIMIT_RETRY_AFTER_HEADER, 0))
134+
except (ValueError, TypeError):
135+
return 0
120136

121137
def do_get(
122138
self,

tests/management/test_user.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -965,7 +965,7 @@ def test_search_all(self):
965965
verify=True,
966966
timeout=DEFAULT_TIMEOUT_SECONDS,
967967
)
968-
968+
969969
# Test success flow with time parameters
970970
with patch("requests.post") as mock_post:
971971
network_resp = mock.Mock()

tests/test_auth.py

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
from http import HTTPStatus
12
import json
23
import os
34
import unittest
@@ -678,6 +679,57 @@ def test_api_rate_limit_exception(self):
678679
{API_RATE_LIMIT_RETRY_AFTER_HEADER: 10},
679680
)
680681

682+
def test_api_rate_limit_invalid_response_body(self):
683+
auth = Auth(self.dummy_project_id, self.public_key_dict)
684+
685+
# Test do_post empty body
686+
with patch("requests.post") as mock_request:
687+
mock_request.return_value.ok = False
688+
mock_request.return_value.status_code = 429
689+
mock_request.return_value.json.return_value = "aaa"
690+
with self.assertRaises(RateLimitException) as cm:
691+
auth.do_post("http://test.com", {}, None, None)
692+
the_exception = cm.exception
693+
self.assertEqual(the_exception.status_code, HTTPStatus.TOO_MANY_REQUESTS)
694+
self.assertEqual(the_exception.error_type, ERROR_TYPE_API_RATE_LIMIT)
695+
self.assertEqual(the_exception.error_description, ERROR_TYPE_API_RATE_LIMIT)
696+
self.assertEqual(the_exception.error_message, ERROR_TYPE_API_RATE_LIMIT)
697+
self.assertEqual(the_exception.rate_limit_parameters, {})
698+
699+
def test_api_rate_limit_empty_response_body(self):
700+
auth = Auth(self.dummy_project_id, self.public_key_dict)
701+
702+
# Test do_post empty body
703+
with patch("requests.post") as mock_request:
704+
mock_request.return_value.ok = False
705+
mock_request.return_value.status_code = 429
706+
mock_request.return_value.json.return_value = ""
707+
with self.assertRaises(RateLimitException) as cm:
708+
auth.do_post("http://test.com", {}, None, None)
709+
the_exception = cm.exception
710+
self.assertEqual(the_exception.status_code, HTTPStatus.TOO_MANY_REQUESTS)
711+
self.assertEqual(the_exception.error_type, ERROR_TYPE_API_RATE_LIMIT)
712+
self.assertEqual(the_exception.error_description, ERROR_TYPE_API_RATE_LIMIT)
713+
self.assertEqual(the_exception.error_message, ERROR_TYPE_API_RATE_LIMIT)
714+
self.assertEqual(the_exception.rate_limit_parameters, {})
715+
716+
def test_api_rate_limit_none_response_body(self):
717+
auth = Auth(self.dummy_project_id, self.public_key_dict)
718+
719+
# Test do_post empty body
720+
with patch("requests.post") as mock_request:
721+
mock_request.return_value.ok = False
722+
mock_request.return_value.status_code = 429
723+
mock_request.return_value.json.return_value = None
724+
with self.assertRaises(RateLimitException) as cm:
725+
auth.do_post("http://test.com", {}, None, None)
726+
the_exception = cm.exception
727+
self.assertEqual(the_exception.status_code, HTTPStatus.TOO_MANY_REQUESTS)
728+
self.assertEqual(the_exception.error_type, ERROR_TYPE_API_RATE_LIMIT)
729+
self.assertEqual(the_exception.error_description, ERROR_TYPE_API_RATE_LIMIT)
730+
self.assertEqual(the_exception.error_message, ERROR_TYPE_API_RATE_LIMIT)
731+
self.assertEqual(the_exception.rate_limit_parameters, {})
732+
681733
def test_raise_from_response(self):
682734
auth = Auth(self.dummy_project_id, self.public_key_dict)
683735
with patch("requests.get") as mock_request:

0 commit comments

Comments
 (0)