Skip to content

Commit d5784d3

Browse files
MaybeNetworkbboe
andauthored
Add TooManyRequests Exception (#112)
Co-authored-by: Bryce Boe <bbzbryce@gmail.com>
1 parent 437c2e4 commit d5784d3

6 files changed

Lines changed: 392 additions & 0 deletions

CHANGES.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ Unreleased
1212
- Add a ``URITooLarge`` exception.
1313
- :class:`.ScriptAuthorizer` has a new parameter ``two_factor_callback `` that supplies
1414
OTPs (One-Time Passcodes) when :meth:`.ScriptAuthorizer.refresh` is called.
15+
- Add a ``TooManyRequests`` exception.
1516

1617
2.0.0 (2021-02-23)
1718
------------------

prawcore/exceptions.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,29 @@ class TooLarge(ResponseException):
146146
"""Indicate that the request data exceeds the allowed limit."""
147147

148148

149+
class TooManyRequests(ResponseException):
150+
"""Indicate that the user has sent too many requests in a given amount of time."""
151+
152+
def __init__(self, response):
153+
"""Initialize a TooManyRequests exception instance.
154+
155+
:param response: A requests.response instance that may contain a retry-after
156+
header and a message.
157+
158+
"""
159+
self.response = response
160+
self.retry_after = response.headers.get("retry-after")
161+
self.message = response.text # Not all response bodies are valid JSON
162+
163+
msg = f"received {response.status_code} HTTP response"
164+
if self.retry_after:
165+
msg += (
166+
f". Please wait at least {float(self.retry_after)} seconds "
167+
"before re-trying this request."
168+
)
169+
PrawcoreException.__init__(self, msg)
170+
171+
149172
class UnavailableForLegalReasons(ResponseException):
150173
"""Indicate that the requested URL is unavailable due to legal reasons."""
151174

prawcore/sessions.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
ServerError,
2626
SpecialError,
2727
TooLarge,
28+
TooManyRequests,
2829
UnavailableForLegalReasons,
2930
URITooLong,
3031
)
@@ -103,6 +104,7 @@ class Session(object):
103104
codes["request_entity_too_large"]: TooLarge,
104105
codes["request_uri_too_large"]: URITooLong,
105106
codes["service_unavailable"]: ServerError,
107+
codes["too_many_requests"]: TooManyRequests,
106108
codes["unauthorized"]: authorization_error_class,
107109
codes["unavailable_for_legal_reasons"]: UnavailableForLegalReasons,
108110
# Cloudflare status (not named in requests)
Lines changed: 207 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,207 @@
1+
{
2+
"http_interactions": [
3+
{
4+
"recorded_at": "2021-05-24T01:25:55",
5+
"request": {
6+
"body": {
7+
"encoding": "utf-8",
8+
"string": "grant_type=client_credentials"
9+
},
10+
"headers": {
11+
"Accept": [
12+
"*/*"
13+
],
14+
"Accept-Encoding": [
15+
"gzip, deflate"
16+
],
17+
"Authorization": [
18+
"Basic <BASIC_AUTH>"
19+
],
20+
"Connection": [
21+
"close"
22+
],
23+
"Content-Length": [
24+
"29"
25+
],
26+
"Content-Type": [
27+
"application/x-www-form-urlencoded"
28+
],
29+
"Cookie": [
30+
"edgebucket=kR68ZnqFfUmfBDhP1U; loid=0tL8IPJr2JUXUhUQRu; redesign_optout=true; session_tracker=BZGb7bKat7vYMk9eYY.0.1388120953197.Z0FBQUFBQmVxTTE1Tzd0eUxURl9ZZnlDbHmxekVJX19jNXhMOEVGaWh6cWthMUlGZDFMamVkZWdOYlVnemljTEs0cWttMFVxTXR4bUYyMzhXai0tY0RYckd4OG5INEF6dHpDaktqZDVXced4ZTdxU1VrUWx1T1jOdzEtSldwWDU2SW5odlBiM1VYTkc"
31+
],
32+
"User-Agent": [
33+
"prawcore:test (by /u/bboe) prawcore/2.0.0"
34+
]
35+
},
36+
"method": "POST",
37+
"uri": "https://www.reddit.com/api/v1/access_token"
38+
},
39+
"response": {
40+
"body": {
41+
"encoding": "UTF-8",
42+
"string": "{\"access_token\": \"-000000000000000000000000000000\", \"token_type\": \"bearer\", \"expires_in\": 3600, \"scope\": \"*\"}"
43+
},
44+
"headers": {
45+
"Accept-Ranges": [
46+
"bytes"
47+
],
48+
"Connection": [
49+
"close"
50+
],
51+
"Content-Length": [
52+
"109"
53+
],
54+
"Content-Type": [
55+
"application/json; charset=UTF-8"
56+
],
57+
"Date": [
58+
"Mon, 24 May 2021 01:25:56 GMT"
59+
],
60+
"Server": [
61+
"snooserv"
62+
],
63+
"Strict-Transport-Security": [
64+
"max-age=15552000; includeSubDomains; preload"
65+
],
66+
"Via": [
67+
"1.1 varnish"
68+
],
69+
"X-Moose": [
70+
"majestic"
71+
],
72+
"cache-control": [
73+
"max-age=0, must-revalidate"
74+
],
75+
"x-content-type-options": [
76+
"nosniff"
77+
],
78+
"x-frame-options": [
79+
"SAMEORIGIN"
80+
],
81+
"x-ratelimit-remaining": [
82+
"298"
83+
],
84+
"x-ratelimit-reset": [
85+
"244"
86+
],
87+
"x-ratelimit-used": [
88+
"2"
89+
],
90+
"x-reddit-loid": [
91+
"0000000000car6psso.2.1621819556332.Z0FBQUFBQmdxd0NrQkxiclluM1duWFMwemhFNzlNQWMyQmtZu0pyZUlzMjFMMU5IbXE5VHhyX2xhbjBnaWtPVDhYQVZkSEdaODlzV2FKRTZZdEc0QWdyRjBKS0xYREV3dnhialBzZ2pnSzZMMUc1NnVyOUpPMlJGN3R5b2FoV1hEbTBxNzVkY0RyR3c"
92+
],
93+
"x-xss-protection": [
94+
"1; mode=block"
95+
]
96+
},
97+
"status": {
98+
"code": 200,
99+
"message": "OK"
100+
},
101+
"url": "https://www.reddit.com/api/v1/access_token"
102+
}
103+
},
104+
{
105+
"recorded_at": "2021-05-24T01:25:55",
106+
"request": {
107+
"body": {
108+
"encoding": "utf-8",
109+
"string": ""
110+
},
111+
"headers": {
112+
"Accept": [
113+
"*/*"
114+
],
115+
"Accept-Encoding": [
116+
"gzip, deflate"
117+
],
118+
"Authorization": [
119+
"bearer -000000000000000000000000000000"
120+
],
121+
"Connection": [
122+
"keep-alive"
123+
],
124+
"Cookie": [
125+
"edgebucket=kR68ZnqFfUmfBDhP1U; loid=0tL8IPJr2kUXUhUQRu; redesign_optout=true; session_tracker=BZGb7bKat7vYMk9eYY.0.1388120953197.Z0FBQUFBQmVxTTE1Tzd0eUxURl9ZZnlDbHmxekVJX19CNXhMOEVGaWh6cWthMUlGZDFMamVkZWdOYlVnemljTEs0cWttMFVxTXR4bUYyMzhXai0tY0RYckd4OG5INEF6dHpDaktkZDVXced4ZTdxU1VrUWx1T1jOdzEtSldwWDU2SW5odlBiM1VYTkc"
126+
],
127+
"User-Agent": [
128+
"python-requests/2.25.1"
129+
]
130+
},
131+
"method": "GET",
132+
"uri": "https://oauth.reddit.com/api/v1/me?raw_json=1"
133+
},
134+
"response": {
135+
"body": {
136+
"base64_string": "H4sIAKQAq2AC/31UwW7bMAy9+yvYXtoCadwCxQ6ZZ2DHHQYMw36AsWhLqC1pFB3PGPbvo2ynyXpYDjFNPT0+PjIpqhsTGpkjgZWhr4tqfQBUltDkQENx0lP9IwT4in6G7/RzpCSpKteDFZRkPscAx2Bm+L295E8bvBwgDdj3cCI26HEHyA77HVjqTySu0UxCnx4TsWs/Xl2enBF7gA9PT/HXdX5A7pw/wBPgKOF88qfYAvv8jwRLrrMq4uUdyxGb147D6M0BhFVARCYvMHJ/X5bTNO2ZjHGSBFXkvglDuSZyuM82Ee+j7x7Ah0emSCiQGg7aqYQInKtetOXvqnwzqyrPPlfZs81L+1xPNiCIJaYdqCDjiW8U/LwiiqKoYj3RHROkwDzv4DgKzGEEjKqAtTQcCVAnIYDegGJPiiXyehTUOh0kb4MsWg7DcrlHoX7eKxrIt4GbTGG1PKRIZKB3gxMI/u2qStR2LzXVElrptHDKmch0ynbicUy0r8pYL9pdu6rVBnyWuAjNPeRMiiG0zndaieDkMEMZjhwm3Y27BMrEgJ3SFklYgQeIPWEiaCz6jlb8BQUrKsvBU3Am+7C8W5dgoJQUVWCHzl8EboQTasMveqEJ3tynh8VM4Rmu4cvQYo1J+2AanNeVyMWMtt6HSJx22VJWkmGgTJBda3qn2lQAvmYTFpYhaPt66qFS45naT7dWJB7KsnNix+PV+p0fk3t15edvX25rdWsh2YYDWl2FyhQ2+fqLxfq/Jqz95LVct1E3bvk/+AucXvM4KAQAAA==",
137+
"encoding": "UTF-8",
138+
"string": ""
139+
},
140+
"headers": {
141+
"Accept-Ranges": [
142+
"bytes"
143+
],
144+
"Connection": [
145+
"keep-alive"
146+
],
147+
"Content-Encoding": [
148+
"gzip"
149+
],
150+
"Content-Length": [
151+
"592"
152+
],
153+
"Content-Type": [
154+
"text/html; charset=UTF-8"
155+
],
156+
"Date": [
157+
"Mon, 24 May 2021 01:25:56 GMT"
158+
],
159+
"Server": [
160+
"snooserv"
161+
],
162+
"Set-Cookie": [
163+
"loid=0000000000car6nb4e.2.1621819556473.Z0FBQUFBQmdxd0NrUkVqOS1jdmFDWmlMOS1oRFh3Wk5vUmdyTlNYMWV3dXA2aDNlQl80ZkNHLTVXNTFsSjNCRF9ieFhhUTFfSG1JUG5LOVFrNjJmaE9Qencycm5haHczNmtkcFVmVkpwbXJIQVhsZVJrUoJmaVdpOWg3ZW9sWEYxbWhRWXNwM1pBZnA; Domain=reddit.com; Max-Age=63071999; Path=/; expires=Wed, 24-May-2023 01:25:56 GMT; secure; SameSite=None; Secure",
164+
"session_tracker=ROpQgUS0os93hYoKLL.0.1621819556476.Z0FBQUFBQmdxd0NrZnFyMm1vbE9rc2xxTlF2RkZQWEl3OENXcHNrS3F6Ynd3Z1YtWXRuNjZTQUc4ZXg4X2dJZFJfd2tWS1Q5bVhtR1ZaYXFJS1p3bkZHY2ttV0VGRnJRbHRXZjZiYkNkQTY0NFpGWk1WSm85Zldwd182NkROTlpGaG5wSWdoNTZWOEQ; Domain=reddit.com; Max-Age=7199; Path=/; expires=Mon, 24-May-2021 03:25:56 GMT; secure; SameSite=None; Secure",
165+
"csv=1; Max-Age=63072000; Domain=.reddit.com; Path=/; Secure; SameSite=None"
166+
],
167+
"Strict-Transport-Security": [
168+
"max-age=15552000; includeSubDomains; preload"
169+
],
170+
"Vary": [
171+
"accept-encoding"
172+
],
173+
"Via": [
174+
"1.1 varnish"
175+
],
176+
"X-Moose": [
177+
"majestic"
178+
],
179+
"cache-control": [
180+
"max-age=0, must-revalidate"
181+
],
182+
"retry-after": [
183+
"4"
184+
],
185+
"x-content-type-options": [
186+
"nosniff"
187+
],
188+
"x-frame-options": [
189+
"SAMEORIGIN"
190+
],
191+
"x-ua-compatible": [
192+
"IE=edge"
193+
],
194+
"x-xss-protection": [
195+
"1; mode=block"
196+
]
197+
},
198+
"status": {
199+
"code": 429,
200+
"message": "Too Many Requests"
201+
},
202+
"url": "https://oauth.reddit.com/api/v1/me?raw_json=1"
203+
}
204+
}
205+
],
206+
"recorded_with": "betamax/0.8.1"
207+
}
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
{
2+
"http_interactions": [
3+
{
4+
"recorded_at": "2021-05-25T01:26:39",
5+
"request": {
6+
"body": {
7+
"encoding": "utf-8",
8+
"string": "grant_type=client_credentials"
9+
},
10+
"headers": {
11+
"Accept": [
12+
"*/*"
13+
],
14+
"Accept-Encoding": [
15+
"gzip, deflate"
16+
],
17+
"Authorization": [
18+
"Basic <BASIC_AUTH>"
19+
],
20+
"Connection": [
21+
"close"
22+
],
23+
"Content-Length": [
24+
"29"
25+
],
26+
"Content-Type": [
27+
"application/x-www-form-urlencoded"
28+
],
29+
"User-Agent": [
30+
"python-requests/2.25.1 prawcore/2.0.0"
31+
]
32+
},
33+
"method": "POST",
34+
"uri": "https://www.reddit.com/api/v1/access_token"
35+
},
36+
"response": {
37+
"body": {
38+
"encoding": "UTF-8",
39+
"string": "{\"message\": \"Too Many Requests\", \"error\": 429}"
40+
},
41+
"headers": {
42+
"Accept-Ranges": [
43+
"bytes"
44+
],
45+
"Connection": [
46+
"close"
47+
],
48+
"Content-Length": [
49+
"46"
50+
],
51+
"Content-Type": [
52+
"application/json; charset=UTF-8"
53+
],
54+
"Date": [
55+
"Tue, 25 May 2021 01:26:41 GMT"
56+
],
57+
"Server": [
58+
"snooserv"
59+
],
60+
"Strict-Transport-Security": [
61+
"max-age=15552000; includeSubDomains; preload"
62+
],
63+
"Via": [
64+
"1.1 varnish"
65+
],
66+
"X-Moose": [
67+
"majestic"
68+
],
69+
"cache-control": [
70+
"max-age=0, must-revalidate"
71+
],
72+
"set-cookie": [
73+
"loid=0000000000cbfksba7.2.1621906001718.Z0FBQUFBQmdyRkpSbC1uQTdNNDhncTI4cDRyTk1sb0xlUEJfZzhjVkVCdjI1WWxySnNBaG5tcVBfb1c5ZlI5aUJvWk5jSm1uQlVXYjQyY1Nna3k3NUN5b1hHalJsQ3FiVlZKWHUtbXRZQWhTWXk0bDufWGloZzdyY1RPaElkaE12dTZNN1RsblFSUHQ; Domain=reddit.com; Max-Age=63071999; Path=/; expires=Thu, 25-May-2023 01:26:41 GMT; secure",
74+
"session_tracker=txIKGQAv1AKgdUH1IA.0.1621906001718.Z0FBQUFBQmdyRkpSbjVMdlJYYU0zYXRuYjA2dERQUkxVbU5yWnF2b3R3ZDVmbTdmd1prejhfcFRaUHvTQTRjbwFoeGtVQ01oZkpBeXVNUlJNelVmZWVETUlCel83cGxfckRieXVwUFpqRVBtdDl6d01qSGFZTy1FMHhuaGszbzh4YTlMTUQ5kVZqZE4; Domain=reddit.com; Max-Age=7199; Path=/; expires=Tue, 25-May-2021 03:26:41 GMT; secure",
75+
"edgebucket=3pCscH0HWW3O5QUtVI; Domain=reddit.com; Max-Age=63071999; Path=/; secure"
76+
],
77+
"x-content-type-options": [
78+
"nosniff"
79+
],
80+
"x-frame-options": [
81+
"SAMEORIGIN"
82+
],
83+
"x-ua-compatible": [
84+
"IE=edge"
85+
],
86+
"x-xss-protection": [
87+
"1; mode=block"
88+
]
89+
},
90+
"status": {
91+
"code": 429,
92+
"message": "Too Many Requests"
93+
},
94+
"url": "https://www.reddit.com/api/v1/access_token"
95+
}
96+
}
97+
],
98+
"recorded_with": "betamax/0.8.1"
99+
}

0 commit comments

Comments
 (0)