|
7 | 7 | import warnings
|
8 | 8 |
|
9 | 9 | import stripe
|
10 |
| -from stripe import error, http_client, version, util |
| 10 | +from stripe import error, oauth_error, http_client, version, util |
11 | 11 | from stripe.multipart_data_generator import MultipartDataGenerator
|
12 | 12 |
|
13 | 13 |
|
@@ -151,38 +151,92 @@ def request(self, method, url, params=None, headers=None):
|
151 | 151 | resp = self.interpret_response(rbody, rcode, rheaders)
|
152 | 152 | return resp, my_api_key
|
153 | 153 |
|
154 |
| - def handle_api_error(self, rbody, rcode, resp, rheaders): |
| 154 | + def handle_error_response(self, rbody, rcode, resp, rheaders): |
155 | 155 | try:
|
156 |
| - err = resp['error'] |
| 156 | + error_data = resp['error'] |
157 | 157 | except (KeyError, TypeError):
|
158 | 158 | raise error.APIError(
|
159 | 159 | "Invalid response object from API: %r (HTTP response code "
|
160 | 160 | "was %d)" % (rbody, rcode),
|
161 | 161 | rbody, rcode, resp)
|
162 | 162 |
|
| 163 | + err = None |
| 164 | + |
| 165 | + # OAuth errors are a JSON object where `error` is a string. In |
| 166 | + # contrast, in API errors, `error` is a hash with sub-keys. We use |
| 167 | + # this property to distinguish between OAuth and API errors. |
| 168 | + if isinstance(error_data, basestring): |
| 169 | + err = self.specific_oauth_error( |
| 170 | + rbody, rcode, resp, rheaders, error_data) |
| 171 | + |
| 172 | + if err is None: |
| 173 | + err = self.specific_api_error( |
| 174 | + rbody, rcode, resp, rheaders, error_data) |
| 175 | + |
| 176 | + raise err |
| 177 | + |
| 178 | + def specific_api_error(self, rbody, rcode, resp, rheaders, error_data): |
| 179 | + util.log_info( |
| 180 | + 'Stripe API error received', |
| 181 | + error_code=error_data.get('code'), |
| 182 | + error_type=error_data.get('type'), |
| 183 | + error_message=error_data.get('message'), |
| 184 | + error_param=error_data.get('param'), |
| 185 | + ) |
| 186 | + |
163 | 187 | # Rate limits were previously coded as 400's with code 'rate_limit'
|
164 |
| - if rcode == 429 or (rcode == 400 and err.get('code') == 'rate_limit'): |
165 |
| - raise error.RateLimitError( |
166 |
| - err.get('message'), rbody, rcode, resp, rheaders) |
| 188 | + if rcode == 429 or (rcode == 400 and |
| 189 | + error_data.get('code') == 'rate_limit'): |
| 190 | + return error.RateLimitError( |
| 191 | + error_data.get('message'), rbody, rcode, resp, rheaders) |
167 | 192 | elif rcode in [400, 404]:
|
168 |
| - raise error.InvalidRequestError( |
169 |
| - err.get('message'), err.get('param'), |
| 193 | + return error.InvalidRequestError( |
| 194 | + error_data.get('message'), error_data.get('param'), |
170 | 195 | rbody, rcode, resp, rheaders)
|
171 | 196 | elif rcode == 401:
|
172 |
| - raise error.AuthenticationError( |
173 |
| - err.get('message'), rbody, rcode, resp, |
174 |
| - rheaders) |
| 197 | + return error.AuthenticationError( |
| 198 | + error_data.get('message'), rbody, rcode, resp, rheaders) |
175 | 199 | elif rcode == 402:
|
176 |
| - raise error.CardError(err.get('message'), err.get('param'), |
177 |
| - err.get('code'), rbody, rcode, resp, |
178 |
| - rheaders) |
| 200 | + return error.CardError( |
| 201 | + error_data.get('message'), error_data.get('param'), |
| 202 | + error_data.get('code'), rbody, rcode, resp, rheaders) |
179 | 203 | elif rcode == 403:
|
180 |
| - raise error.PermissionError( |
181 |
| - err.get('message'), rbody, rcode, resp, |
182 |
| - rheaders) |
| 204 | + return error.PermissionError( |
| 205 | + error_data.get('message'), rbody, rcode, resp, rheaders) |
183 | 206 | else:
|
184 |
| - raise error.APIError(err.get('message'), rbody, rcode, resp, |
185 |
| - rheaders) |
| 207 | + return error.APIError( |
| 208 | + error_data.get('message'), rbody, rcode, resp, rheaders) |
| 209 | + |
| 210 | + def specific_oauth_error(self, rbody, rcode, resp, rheaders, error_code): |
| 211 | + description = resp.get('error_description', error_code) |
| 212 | + |
| 213 | + util.log_info( |
| 214 | + 'Stripe OAuth error received', |
| 215 | + error_code=error_code, |
| 216 | + error_description=description, |
| 217 | + ) |
| 218 | + |
| 219 | + args = [ |
| 220 | + error_code, |
| 221 | + description, |
| 222 | + rbody, |
| 223 | + rcode, |
| 224 | + resp, |
| 225 | + rheaders |
| 226 | + ] |
| 227 | + |
| 228 | + if error_code == 'invalid_grant': |
| 229 | + return oauth_error.InvalidGrantError(*args) |
| 230 | + elif error_code == 'invalid_request': |
| 231 | + return oauth_error.InvalidRequestError(*args) |
| 232 | + elif error_code == 'invalid_scope': |
| 233 | + return oauth_error.InvalidScopeError(*args) |
| 234 | + elif error_code == 'unsupported_grant_type': |
| 235 | + return oauth_error.UnsupportedGrantTypError(*args) |
| 236 | + elif error_code == 'unsupported_response_type': |
| 237 | + return oauth_error.UnsupportedResponseTypError(*args) |
| 238 | + |
| 239 | + return None |
186 | 240 |
|
187 | 241 | def request_headers(self, api_key, method):
|
188 | 242 | user_agent = 'Stripe/v1 PythonBindings/%s' % (version.VERSION,)
|
@@ -299,14 +353,7 @@ def interpret_response(self, rbody, rcode, rheaders):
|
299 | 353 | "(HTTP response code was %d)" % (rbody, rcode),
|
300 | 354 | rbody, rcode, rheaders)
|
301 | 355 | if not (200 <= rcode < 300):
|
302 |
| - util.log_info( |
303 |
| - 'Stripe API error received', |
304 |
| - error_code=resp.get('error', {}).get('code'), |
305 |
| - error_type=resp.get('error', {}).get('type'), |
306 |
| - error_message=resp.get('error', {}).get('message'), |
307 |
| - error_param=resp.get('error', {}).get('param'), |
308 |
| - ) |
309 |
| - self.handle_api_error(rbody, rcode, resp, rheaders) |
| 356 | + self.handle_error_response(rbody, rcode, resp, rheaders) |
310 | 357 | return resp
|
311 | 358 |
|
312 | 359 | # Deprecated request handling. Will all be removed in 2.0
|
@@ -379,37 +426,3 @@ def urllib2_request(self, meth, abs_url, headers, params):
|
379 | 426 | def handle_urllib2_error(self, err, abs_url):
|
380 | 427 | from stripe.http_client import Urllib2Client
|
381 | 428 | return self._deprecated_handle_error(Urllib2Client, err, abs_url)
|
382 |
| - |
383 |
| - |
384 |
| -class OAuthRequestor(APIRequestor): |
385 |
| - def handle_api_error(self, rbody, rcode, resp, rheaders): |
386 |
| - try: |
387 |
| - err_type = resp['error'] |
388 |
| - except (KeyError, TypeError): |
389 |
| - raise error.APIError( |
390 |
| - "Invalid response object from API: %r (HTTP response code " |
391 |
| - "was %d)" % (rbody, rcode), |
392 |
| - rbody, rcode, resp) |
393 |
| - |
394 |
| - description = resp.get('error_description', None) |
395 |
| - raise error.OAuthError( |
396 |
| - err_type, description, rbody, rcode, resp, rheaders) |
397 |
| - |
398 |
| - def interpret_response(self, rbody, rcode, rheaders): |
399 |
| - try: |
400 |
| - if hasattr(rbody, 'decode'): |
401 |
| - rbody = rbody.decode('utf-8') |
402 |
| - resp = util.json.loads(rbody) |
403 |
| - except Exception: |
404 |
| - raise error.APIError( |
405 |
| - "Invalid response body from API: %s " |
406 |
| - "(HTTP response code was %d)" % (rbody, rcode), |
407 |
| - rbody, rcode, rheaders) |
408 |
| - if not (200 <= rcode < 300): |
409 |
| - util.log_info( |
410 |
| - 'Stripe API error received', |
411 |
| - error=resp.get('error'), |
412 |
| - error_description=resp.get('error_description', ''), |
413 |
| - ) |
414 |
| - self.handle_api_error(rbody, rcode, resp, rheaders) |
415 |
| - return resp |
|
0 commit comments