Explicitly return api code when parsing error
authortjphopkins <tomjphopkins@gmail.com>
Tue, 3 Nov 2015 11:40:18 +0000 (11:40 +0000)
committertjphopkins <tomjphopkins@gmail.com>
Mon, 9 Nov 2015 18:25:41 +0000 (13:25 -0500)
cassettes/testfailure.json [new file with mode: 0644]
tests/test_api.py
tweepy/binder.py
tweepy/error.py
tweepy/parsers.py

diff --git a/cassettes/testfailure.json b/cassettes/testfailure.json
new file mode 100644 (file)
index 0000000..96e29e5
--- /dev/null
@@ -0,0 +1,287 @@
+{
+    "version": 1,
+    "interactions": [
+        {
+            "request": {
+                "method": "GET",
+                "uri": "https://api.twitter.com:443/1.1/direct_messages.json",
+                "headers": {
+                    "Host": [
+                        "api.twitter.com"
+                    ]
+                },
+                "body": null
+            },
+            "response": {
+                "status": {
+                    "message": "Bad Request",
+                    "code": 400
+                },
+                "headers": {
+                    "x-response-time": [
+                        "6"
+                    ],
+                    "content-type": [
+                        "application/json; charset=utf-8"
+                    ],
+                    "server": [
+                        "tsa_b"
+                    ],
+                    "strict-transport-security": [
+                        "max-age=631138519"
+                    ],
+                    "set-cookie": [
+                        "guest_id=v1%3A144655290597218733; Domain=.twitter.com; Path=/; Expires=Thu, 02-Nov-2017 12:15:05 UTC"
+                    ],
+                    "date": [
+                        "Tue, 03 Nov 2015 12:15:05 GMT"
+                    ],
+                    "x-connection-hash": [
+                        "bbad9c628533f023920a78c282b82a2e"
+                    ],
+                    "content-length": [
+                        "62"
+                    ]
+                },
+                "body": {
+                    "string": "{\"errors\":[{\"code\":215,\"message\":\"Bad Authentication data.\"}]}"
+                }
+            }
+        },
+        {
+            "request": {
+                "method": "GET",
+                "uri": "https://api.twitter.com:443/1.1/direct_messages.json",
+                "headers": {
+                    "Cookie": [
+                        "guest_id=v1%3A144655290597218733"
+                    ],
+                    "Host": [
+                        "api.twitter.com"
+                    ]
+                },
+                "body": null
+            },
+            "response": {
+                "status": {
+                    "message": "Bad Request",
+                    "code": 400
+                },
+                "headers": {
+                    "x-response-time": [
+                        "5"
+                    ],
+                    "content-type": [
+                        "application/json; charset=utf-8"
+                    ],
+                    "server": [
+                        "tsa_b"
+                    ],
+                    "strict-transport-security": [
+                        "max-age=631138519"
+                    ],
+                    "date": [
+                        "Tue, 03 Nov 2015 12:15:11 GMT"
+                    ],
+                    "x-connection-hash": [
+                        "bbad9c628533f023920a78c282b82a2e"
+                    ],
+                    "content-length": [
+                        "62"
+                    ]
+                },
+                "body": {
+                    "string": "{\"errors\":[{\"code\":215,\"message\":\"Bad Authentication data.\"}]}"
+                }
+            }
+        },
+        {
+            "request": {
+                "method": "GET",
+                "uri": "https://api.twitter.com:443/1.1/direct_messages.json",
+                "headers": {
+                    "Cookie": [
+                        "guest_id=v1%3A144655290597218733"
+                    ],
+                    "Host": [
+                        "api.twitter.com"
+                    ]
+                },
+                "body": null
+            },
+            "response": {
+                "status": {
+                    "message": "Bad Request",
+                    "code": 400
+                },
+                "headers": {
+                    "x-response-time": [
+                        "3"
+                    ],
+                    "content-type": [
+                        "application/json; charset=utf-8"
+                    ],
+                    "server": [
+                        "tsa_b"
+                    ],
+                    "strict-transport-security": [
+                        "max-age=631138519"
+                    ],
+                    "date": [
+                        "Tue, 03 Nov 2015 12:15:16 GMT"
+                    ],
+                    "x-connection-hash": [
+                        "bbad9c628533f023920a78c282b82a2e"
+                    ],
+                    "content-length": [
+                        "62"
+                    ]
+                },
+                "body": {
+                    "string": "{\"errors\":[{\"code\":215,\"message\":\"Bad Authentication data.\"}]}"
+                }
+            }
+        },
+        {
+            "request": {
+                "method": "GET",
+                "uri": "https://api.twitter.com:443/1.1/direct_messages.json",
+                "headers": {
+                    "Host": [
+                        "api.twitter.com"
+                    ]
+                },
+                "body": null
+            },
+            "response": {
+                "status": {
+                    "message": "Bad Request",
+                    "code": 400
+                },
+                "headers": {
+                    "x-response-time": [
+                        "4"
+                    ],
+                    "content-type": [
+                        "application/json; charset=utf-8"
+                    ],
+                    "server": [
+                        "tsa_b"
+                    ],
+                    "strict-transport-security": [
+                        "max-age=631138519"
+                    ],
+                    "set-cookie": [
+                        "guest_id=v1%3A144655293331152269; Domain=.twitter.com; Path=/; Expires=Thu, 02-Nov-2017 12:15:33 UTC"
+                    ],
+                    "date": [
+                        "Tue, 03 Nov 2015 12:15:33 GMT"
+                    ],
+                    "x-connection-hash": [
+                        "f3384743aac99980194e77031a6b9d66"
+                    ],
+                    "content-length": [
+                        "62"
+                    ]
+                },
+                "body": {
+                    "string": "{\"errors\":[{\"code\":215,\"message\":\"Bad Authentication data.\"}]}"
+                }
+            }
+        },
+        {
+            "request": {
+                "method": "GET",
+                "uri": "https://api.twitter.com:443/1.1/direct_messages.json",
+                "headers": {
+                    "Cookie": [
+                        "guest_id=v1%3A144655293331152269"
+                    ],
+                    "Host": [
+                        "api.twitter.com"
+                    ]
+                },
+                "body": null
+            },
+            "response": {
+                "status": {
+                    "message": "Bad Request",
+                    "code": 400
+                },
+                "headers": {
+                    "x-response-time": [
+                        "4"
+                    ],
+                    "content-type": [
+                        "application/json; charset=utf-8"
+                    ],
+                    "server": [
+                        "tsa_b"
+                    ],
+                    "strict-transport-security": [
+                        "max-age=631138519"
+                    ],
+                    "date": [
+                        "Tue, 03 Nov 2015 12:15:38 GMT"
+                    ],
+                    "x-connection-hash": [
+                        "f3384743aac99980194e77031a6b9d66"
+                    ],
+                    "content-length": [
+                        "62"
+                    ]
+                },
+                "body": {
+                    "string": "{\"errors\":[{\"code\":215,\"message\":\"Bad Authentication data.\"}]}"
+                }
+            }
+        },
+        {
+            "request": {
+                "method": "GET",
+                "uri": "https://api.twitter.com:443/1.1/direct_messages.json",
+                "headers": {
+                    "Cookie": [
+                        "guest_id=v1%3A144655293331152269"
+                    ],
+                    "Host": [
+                        "api.twitter.com"
+                    ]
+                },
+                "body": null
+            },
+            "response": {
+                "status": {
+                    "message": "Bad Request",
+                    "code": 400
+                },
+                "headers": {
+                    "x-response-time": [
+                        "6"
+                    ],
+                    "content-type": [
+                        "application/json; charset=utf-8"
+                    ],
+                    "server": [
+                        "tsa_b"
+                    ],
+                    "strict-transport-security": [
+                        "max-age=631138519"
+                    ],
+                    "date": [
+                        "Tue, 03 Nov 2015 12:15:43 GMT"
+                    ],
+                    "x-connection-hash": [
+                        "f3384743aac99980194e77031a6b9d66"
+                    ],
+                    "content-length": [
+                        "62"
+                    ]
+                },
+                "body": {
+                    "string": "{\"errors\":[{\"code\":215,\"message\":\"Bad Authentication data.\"}]}"
+                }
+            }
+        }
+    ]
+}
index 621602233caa47cec348e856049f6cc4557a680e..e38c4a0728ba3bc6df2d9aa98fd307186601943c 100644 (file)
@@ -3,6 +3,7 @@ import random
 import shutil
 from time import sleep
 import os
+from ast import literal_eval
 
 from nose import SkipTest
 
@@ -32,6 +33,18 @@ class TweepyErrorTests(unittest.TestCase):
 
 class TweepyAPITests(TweepyTestCase):
 
+    @tape.use_cassette('testfailure.json')
+    def testapierror(self):
+        from tweepy.error import TweepError
+
+        with self.assertRaises(TweepError) as cm:
+            self.api.direct_messages()
+
+        reason, = literal_eval(cm.exception.reason)
+        self.assertEqual(reason['message'], 'Bad Authentication data.')
+        self.assertEqual(reason['code'], 215)
+        self.assertEqual(cm.exception.api_code, 215)
+
     # TODO: Actually have some sort of better assertion
     @tape.use_cassette('testgetoembed.json')
     def testgetoembed(self):
index ba5557083b26c41778ba83b335f7302213e213f4..b96e4d3c0e61cccb907c6c80a73e1db245a3fa69 100644 (file)
@@ -217,14 +217,16 @@ def bind_api(**config):
             self.api.last_response = resp
             if resp.status_code and not 200 <= resp.status_code < 300:
                 try:
-                    error_msg = self.parser.parse_error(resp.text)
+                    error_msg, api_error_code = \
+                        self.parser.parse_error(resp.text)
                 except Exception:
                     error_msg = "Twitter error response: status code = %s" % resp.status_code
+                    api_error_code = None
 
                 if is_rate_limit_error_message(error_msg):
                     raise RateLimitError(error_msg, resp)
                 else:
-                    raise TweepError(error_msg, resp)
+                    raise TweepError(error_msg, resp, api_code=api_error_code)
 
             # Parse the response payload
             result = self.parser.parse(self, resp.text)
index 7827029a55236e7becbc4e445994934c645248c5..f7d5894454ea0f138b8084f4b65f8482dac3ba53 100644 (file)
@@ -9,14 +9,16 @@ import six
 class TweepError(Exception):
     """Tweepy exception"""
 
-    def __init__(self, reason, response=None):
+    def __init__(self, reason, response=None, api_code=None):
         self.reason = six.text_type(reason)
         self.response = response
+        self.api_code = api_code
         Exception.__init__(self, reason)
 
     def __str__(self):
         return self.reason
 
+
 def is_rate_limit_error_message(message):
     """Check if the supplied error message belongs to a rate limit error."""
     return isinstance(message, list) \
@@ -24,6 +26,7 @@ def is_rate_limit_error_message(message):
         and 'code' in message[0] \
         and message[0]['code'] == 88
 
+
 class RateLimitError(TweepError):
     """Exception for Tweepy hitting the rate limit."""
     # RateLimitError has the exact same properties and inner workings
index 869fc6230be0bec601b7d4a8aa2c06f9893cad35..6381912ecab6c1ee8b7e45a2a9d1aea3d0aec98f 100644 (file)
@@ -21,9 +21,9 @@ class Parser(object):
 
     def parse_error(self, payload):
         """
-        Parse the error message from payload.
-        If unable to parse the message, throw an exception
-        and default error message will be used.
+        Parse the error message and api error code from payload.
+        Return them as an (error_msg, error_code) tuple. If unable to parse the
+        message, throw an exception and default error message will be used.
         """
         raise NotImplementedError
 
@@ -63,11 +63,18 @@ class JSONParser(Parser):
             return json
 
     def parse_error(self, payload):
-        error = self.json_lib.loads(payload)
-        if 'error' in error:
-            return error['error']
+        error_object = self.json_lib.loads(payload)
+
+        if 'error' in error_object:
+            reason = error_object['error']
+            api_code = error_object.get('code')
         else:
-            return error['errors']
+            reason = error_object['errors']
+            api_code = [error.get('code') for error in
+                        reason if error.get('code')]
+            api_code = api_code[0] if len(api_code) == 1 else api_code
+
+        return reason, api_code
 
 
 class ModelParser(JSONParser):