1212from builtins import *
1313from past .builtins import basestring
1414
15- import json
15+ import sys
16+ import textwrap
1617
1718import requests
1819
19- from collections import OrderedDict
20-
2120from ciscosparkapi .responsecodes import SPARK_RESPONSE_CODES
2221
2322
2726__license__ = "MIT"
2827
2928
30- class ciscosparkapiException (Exception ):
31- """Base class for all ciscosparkapi package exceptions."""
29+ # Helper functions
30+ def sanitize (header_tuple ):
31+ """Sanitize request headers.
3232
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>"
5141
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
5844
59- return self .__class__ .__name__ + "(" + arg_string + ")"
6045
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
65113
66114
67115class SparkApiError (ciscosparkapiException ):
@@ -70,47 +118,22 @@ class SparkApiError(ciscosparkapiException):
70118 def __init__ (self , response ):
71119 assert isinstance (response , requests .Response )
72120
73- super (SparkApiError , self ).__init__ ()
74-
75- # Convenience data attributes
76- self .request = response .request
121+ # Extended exception data attributes
77122 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
104124
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 )
107130
108- super (SparkRateLimitError , self ).__init__ (response )
131+ super (SparkApiError , self ).__init__ ("Response Code [{}] - {}\n {}"
132+ "" .format (response_code ,
133+ description ,
134+ detail ))
109135
110- retry_after = response .headers .get ('Retry-After' )
111- if retry_after :
112- # Convenience data attributes
113- self .retry_after = float (retry_after )
114136
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