12
12
from builtins import *
13
13
from past .builtins import basestring
14
14
15
- import json
15
+ import sys
16
+ import textwrap
16
17
17
18
import requests
18
19
19
- from collections import OrderedDict
20
-
21
20
from ciscosparkapi .responsecodes import SPARK_RESPONSE_CODES
22
21
23
22
27
26
__license__ = "MIT"
28
27
29
28
30
- class ciscosparkapiException (Exception ):
31
- """Base class for all ciscosparkapi package exceptions."""
29
+ # Helper functions
30
+ def sanitize (header_tuple ):
31
+ """Sanitize request headers.
32
32
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 )
33
+ Remove Spark authentication token.
34
+
35
+ """
36
+ header , value = header_tuple
37
+
38
+ if (header .lower ().strip () == "Authorization" .lower ().strip ()
39
+ and "Bearer" .lower ().strip () in value .lower ().strip ()):
40
+ return header , "Bearer <omitted>"
51
41
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 )
42
+ else :
43
+ return header_tuple
58
44
59
- return self .__class__ .__name__ + "(" + arg_string + ")"
60
45
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 )
46
+ def to_unicode (string ):
47
+ """Convert a string (bytes, str or unicode) to unicode."""
48
+ assert isinstance (string , basestring )
49
+ if sys .version_info [0 ] >= 3 :
50
+ if isinstance (string , bytes ):
51
+ return string .decode ('utf-8' )
52
+ else :
53
+ return string
54
+ else :
55
+ if isinstance (string , str ):
56
+ return string .decode ('utf-8' )
57
+ else :
58
+ return string
59
+
60
+
61
+ def response_to_string (response ):
62
+ """Render a response object as a human readable string."""
63
+ assert isinstance (response , requests .Response )
64
+ request = response .request
65
+
66
+ section_header = "{title:-^79}"
67
+
68
+ # Prepare request components
69
+ req = textwrap .fill ("{} {}" .format (request .method , request .url ),
70
+ width = 79 ,
71
+ subsequent_indent = ' ' * (len (request .method )+ 1 ))
72
+ req_headers = [
73
+ textwrap .fill ("{}: {}" .format (* sanitize (header )),
74
+ width = 79 ,
75
+ subsequent_indent = ' ' * 4 )
76
+ for header in request .headers .items ()
77
+ ]
78
+ req_body = (textwrap .fill (to_unicode (request .body ), width = 79 )
79
+ if request .body else "" )
80
+
81
+ # Prepare response components
82
+ resp = textwrap .fill ("{} {}" .format (response .status_code ,
83
+ response .reason
84
+ if response .reason else "" ),
85
+ width = 79 ,
86
+ subsequent_indent = ' ' * (len (request .method )+ 1 ))
87
+ resp_headers = [
88
+ textwrap .fill ("{}: {}" .format (* header ), width = 79 ,
89
+ subsequent_indent = ' ' * 4 )
90
+ for header in response .headers .items ()
91
+ ]
92
+ resp_body = textwrap .fill (response .text , width = 79 ) if response .text else ""
93
+
94
+ # Return the combined string
95
+ return "\n " .join ([
96
+ section_header .format (title = "Request" ),
97
+ req ,
98
+ "\n " .join (req_headers ),
99
+ "" ,
100
+ req_body ,
101
+ "" ,
102
+ section_header .format (title = "Response" ),
103
+ resp ,
104
+ "\n " .join (resp_headers ),
105
+ "" ,
106
+ resp_body ,
107
+ ])
108
+
109
+
110
+ class ciscosparkapiException (Exception ):
111
+ """Base class for all ciscosparkapi package exceptions."""
112
+ pass
65
113
66
114
67
115
class SparkApiError (ciscosparkapiException ):
@@ -70,47 +118,22 @@ class SparkApiError(ciscosparkapiException):
70
118
def __init__ (self , response ):
71
119
assert isinstance (response , requests .Response )
72
120
73
- super (SparkApiError , self ).__init__ ()
74
-
75
- # Convenience data attributes
76
- self .request = response .request
121
+ # Extended exception data attributes
77
122
self .response = response
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."""
123
+ self .request = response .request
104
124
105
- def __init__ (self , response ):
106
- assert isinstance (response , requests .Response )
125
+ # Error message
126
+ response_code = response .status_code
127
+ description = SPARK_RESPONSE_CODES .get (response_code ,
128
+ "Unknown Response Code" )
129
+ detail = response_to_string (response )
107
130
108
- super (SparkRateLimitError , self ).__init__ (response )
131
+ super (SparkApiError , self ).__init__ ("Response Code [{}] - {}\n {}"
132
+ "" .format (response_code ,
133
+ description ,
134
+ detail ))
109
135
110
- retry_after = response .headers .get ('Retry-After' )
111
- if retry_after :
112
- # Convenience data attributes
113
- self .retry_after = float (retry_after )
114
136
115
- # Error Data
116
- self .error_data ["retry_after" ] = self .retry_after
137
+ class SparkRateLimitError (SparkApiError ):
138
+ """Cisco Spark Rate-Limit exceeded Error."""
139
+ pass
0 commit comments