|
12 | 12 | from builtins import *
|
13 | 13 | from past.builtins import basestring
|
14 | 14 |
|
| 15 | +import json |
| 16 | + |
| 17 | +import requests |
| 18 | + |
| 19 | +from collections import OrderedDict |
| 20 | + |
| 21 | +from ciscosparkapi.responsecodes import SPARK_RESPONSE_CODES |
| 22 | + |
15 | 23 |
|
16 | 24 | __author__ = "Chris Lunsford"
|
17 | 25 | __author_email__ = "[email protected]"
|
18 | 26 | __copyright__ = "Copyright (c) 2016 Cisco Systems, Inc."
|
19 | 27 | __license__ = "MIT"
|
20 | 28 |
|
21 | 29 |
|
22 |
| -SPARK_RESPONSE_CODES = { |
23 |
| - 200: "OK", |
24 |
| - 204: "Member deleted.", |
25 |
| - 400: "The request was invalid or cannot be otherwise served. An " |
26 |
| - "accompanying error message will explain further.", |
27 |
| - 401: "Authentication credentials were missing or incorrect.", |
28 |
| - 403: "The request is understood, but it has been refused or access is not " |
29 |
| - "allowed.", |
30 |
| - 404: "The URI requested is invalid or the resource requested, such as a " |
31 |
| - "user, does not exist. Also returned when the requested format is " |
32 |
| - "not supported by the requested method.", |
33 |
| - 409: "The request could not be processed because it conflicts with some " |
34 |
| - "established rule of the system. For example, a person may not be " |
35 |
| - "added to a room more than once.", |
36 |
| - 429: "Too many requests have been sent in a given amount of time and the " |
37 |
| - "request has been rate limited. A Retry-After header should be " |
38 |
| - "present that specifies how many seconds you need to wait before a " |
39 |
| - "successful request can be made.", |
40 |
| - 500: "Something went wrong on the server.", |
41 |
| - 503: "Server is overloaded with requests. Try again later." |
42 |
| -} |
43 |
| - |
44 |
| - |
45 | 30 | class ciscosparkapiException(Exception):
|
46 | 31 | """Base class for all ciscosparkapi package exceptions."""
|
47 | 32 |
|
48 |
| - def __init__(self, *args, **kwargs): |
49 |
| - super(ciscosparkapiException, self).__init__(*args, **kwargs) |
| 33 | + def __init__(self, *error_message_args, **error_data): |
| 34 | + super(ciscosparkapiException, self).__init__() |
| 35 | + |
| 36 | + self.error_message_args = error_message_args |
| 37 | + self.error_data = OrderedDict(error_data) |
| 38 | + |
| 39 | + @property |
| 40 | + def error_message(self): |
| 41 | + """The error message created from the error message arguments.""" |
| 42 | + if not self.error_message_args: |
| 43 | + return "" |
| 44 | + elif len(self.error_message_args) == 1: |
| 45 | + return str(self.error_message_args[0]) |
| 46 | + elif len(self.error_message_args) > 1 \ |
| 47 | + and isinstance(self.error_message_args[0], basestring): |
| 48 | + return self.error_message_args[0] % self.error_message_args[1:] |
| 49 | + else: |
| 50 | + return "; ".join(self.error_message_args) |
| 51 | + |
| 52 | + def __repr__(self): |
| 53 | + """String representation of the exception.""" |
| 54 | + arg_list = self.error_message_args |
| 55 | + kwarg_list = [str(key) + "=" + repr(value) |
| 56 | + for key, value in self.error_data.items()] |
| 57 | + arg_string = ", ".join(arg_list + kwarg_list) |
| 58 | + |
| 59 | + return self.__class__.__name__ + "(" + arg_string + ")" |
| 60 | + |
| 61 | + def __str__(self): |
| 62 | + """Human readable string representation of the exception.""" |
| 63 | + return self.error_message + '\n' + \ |
| 64 | + json.dumps(self.error_data, indent=4) |
50 | 65 |
|
51 | 66 |
|
52 | 67 | class SparkApiError(ciscosparkapiException):
|
53 | 68 | """Errors returned by requests to the Cisco Spark cloud APIs."""
|
54 | 69 |
|
55 |
| - def __init__(self, response_code, request=None, response=None): |
56 |
| - assert isinstance(response_code, int) |
57 |
| - self.response_code = response_code |
58 |
| - self.request = request |
| 70 | + def __init__(self, response): |
| 71 | + assert isinstance(response, requests.Response) |
| 72 | + |
| 73 | + super(SparkApiError, self).__init__() |
| 74 | + |
| 75 | + # Convenience data attributes |
| 76 | + self.request = response.request |
59 | 77 | self.response = response
|
60 |
| - response_text = SPARK_RESPONSE_CODES.get(response_code) |
61 |
| - if response_text: |
62 |
| - self.response_text = response_text |
63 |
| - error_message = "Response Code [{!s}] - {}".format(response_code, |
64 |
| - response_text) |
65 |
| - else: |
66 |
| - error_message = "Response Code [{!s}] - " \ |
67 |
| - "Unknown Response Code".format(response_code) |
68 |
| - super(SparkApiError, self).__init__(error_message) |
| 78 | + self.response_code = response.status_code |
| 79 | + self.response_text = SPARK_RESPONSE_CODES.get(self.response_code, |
| 80 | + "Unknown Response Code") |
| 81 | + |
| 82 | + # Error message and parameters |
| 83 | + self.error_message_args = [ |
| 84 | + "Response Code [%s] - %s", |
| 85 | + self.response_code, |
| 86 | + self.response_text |
| 87 | + ] |
| 88 | + |
| 89 | + # Error Data |
| 90 | + self.error_data["response_code"] = self.response_code |
| 91 | + self.error_data["description"] = self.response_text |
| 92 | + if response.text: |
| 93 | + try: |
| 94 | + response_data = json.loads(response.text, |
| 95 | + object_pairs_hook=OrderedDict) |
| 96 | + except ValueError: |
| 97 | + self.error_data["response_body"] = response.text |
| 98 | + else: |
| 99 | + self.error_data["response_body"] = response_data |
| 100 | + |
| 101 | + |
| 102 | +class SparkRateLimitError(SparkApiError): |
| 103 | + """Cisco Spark Rate-Limit exceeded Error.""" |
| 104 | + |
| 105 | + def __init__(self, response): |
| 106 | + assert isinstance(response, requests.Response) |
| 107 | + |
| 108 | + super(SparkRateLimitError, self).__init__(response) |
| 109 | + |
| 110 | + retry_after = response.headers.get('Retry-After') |
| 111 | + if retry_after: |
| 112 | + # Convenience data attributes |
| 113 | + self.retry_after = float(retry_after) |
| 114 | + |
| 115 | + # Error Data |
| 116 | + self.error_data["retry_after"] = self.retry_after |
0 commit comments