diff --git a/tests/unit/http/test_http_client.py b/tests/unit/http/test_http_client.py index 2f65cab70b..a61326bcf7 100644 --- a/tests/unit/http/test_http_client.py +++ b/tests/unit/http/test_http_client.py @@ -4,6 +4,8 @@ from mock import patch, Mock from requests import Session +from twilio.base.version import Version +from twilio.base.exceptions import TwilioRestException from twilio.http.http_client import TwilioHttpClient from twilio.http.response import Response @@ -64,7 +66,7 @@ def test_request_where_class_timeout_manually_set(self): self.client.timeout = 30 response = self.client.request( - 'doesnt matter', 'doesnt matter') + 'doesnt matter', 'doesnt matter') self.assertEqual('other.twilio.com', self.request_mock.headers['Host']) self.assertEqual(200, response.status_code) self.assertEqual('testing-unicode: Ω≈ç√, 💩', response.content) @@ -143,6 +145,28 @@ def test_request_behind_proxy(self): self.client.request('doesnt matter', 'doesnt matter') self.assertEqual(proxies, self.session_mock.proxies) + def test_exception_with_details(self): + v1 = MyVersion(self.client) + error_text = """{ + "code": 20001, + "message": "Bad request", + "more_info": "https://www.twilio.com/docs/errors/20001", + "status": 400, + "details": { + "foo":"bar" + } + }""" + self.session_mock.send.return_value = Response(400, error_text) + try: + v1.fetch("get", "none", None, None, None, None, None) + self.fail('should not happen') + except TwilioRestException as err: + self.assertEqual(400, err.status) + self.assertEqual(20001, err.code) + self.assertEqual("get", err.method) + self.assertEqual("Unable to fetch record: Bad request", err.msg) + self.assertEqual({"foo": "bar"}, err.details) + class TestHttpClientSession(unittest.TestCase): @@ -186,3 +210,10 @@ def test_session_not_preserved(self): # Used different session, responses should be different self.assertEqual(response_1.content, 'response_1') self.assertEqual(response_2.content, 'response_2') + + +class MyVersion(Version): + def __init__(self, domain): + super(MyVersion, self).__init__(domain) + self.version = 'v1' + self._credentials = None diff --git a/twilio/base/exceptions.py b/twilio/base/exceptions.py index 8e2cf20b48..fdf9903d8d 100644 --- a/twilio/base/exceptions.py +++ b/twilio/base/exceptions.py @@ -17,14 +17,16 @@ class TwilioRestException(TwilioException): :param str method: The HTTP method used to make the request :param int|None code: A Twilio-specific error code for the error. This is not available for all errors. + :param dictionary|None details: Additional error details returned for the exception """ - def __init__(self, status, uri, msg="", code=None, method='GET'): + def __init__(self, status, uri, msg="", code=None, method='GET', details=None): self.uri = uri self.status = status self.msg = msg self.code = code self.method = method + self.details = details def __str__(self): """ Try to pretty-print the exception, if this is going on screen. """ diff --git a/twilio/base/version.py b/twilio/base/version.py index 51c1bd5da9..5b4429b6fd 100644 --- a/twilio/base/version.py +++ b/twilio/base/version.py @@ -57,8 +57,9 @@ def exception(cls, method, uri, response, message): error_payload = json.loads(response.text) if 'message' in error_payload: message = '{}: {}'.format(message, error_payload['message']) + details = error_payload.get('details') code = error_payload.get('code', response.status_code) - return TwilioRestException(response.status_code, uri, message, code, method) + return TwilioRestException(response.status_code, uri, message, code, method, details) except Exception: return TwilioRestException(response.status_code, uri, message, response.status_code, method)