@@ -45,9 +45,30 @@ def load_from_vcap_services(service_name):
4545
4646
4747class WatsonException (Exception ):
48+ """
49+ Custom exception class for Watson Services.
50+ """
4851 pass
4952
5053
54+ class WatsonApiException (WatsonException ):
55+ """
56+ Custom exception class for errors returned from Watson APIs.
57+
58+ :param int code: The HTTP status code returned.
59+ :param str message: A message describing the error.
60+ :param dict info: A dictionary of additional information about the error.
61+ """
62+ def __init__ (self , code , message , info = None ):
63+ # Call the base class constructor with the parameters it needs
64+ super (WatsonApiException , self ).__init__ (message )
65+ self .code = code
66+ self .info = info
67+
68+ def __str__ (self ):
69+ return 'Error: ' + self .message + ', Code: ' + str (self .code )
70+
71+
5172class WatsonInvalidArgument (WatsonException ):
5273 pass
5374
@@ -115,7 +136,7 @@ def __init__(self, vcap_services_name, url, username=None, password=None,
115136
116137 if api_key is not None :
117138 if username is not None or password is not None :
118- raise WatsonInvalidArgument (
139+ raise ValueError (
119140 'Cannot set api_key and username and password together' )
120141 self .set_api_key (api_key )
121142 else :
@@ -138,10 +159,9 @@ def __init__(self, vcap_services_name, url, username=None, password=None,
138159
139160 if (self .username is None or self .password is None )\
140161 and self .api_key is None :
141- raise WatsonException (
162+ raise ValueError (
142163 'You must specify your username and password service '
143- 'credentials ' +
144- '(Note: these are different from your Bluemix id)' )
164+ 'credentials (Note: these are different from your Bluemix id)' )
145165
146166 def set_username_and_password (self , username = None , password = None ):
147167 if username == 'YOUR SERVICE USERNAME' :
@@ -171,7 +191,7 @@ def set_default_headers(self, headers):
171191 if isinstance (headers , dict ):
172192 self .default_headers = headers
173193 else :
174- raise WatsonException ("headers parameter must be a dictionary" )
194+ raise TypeError ("headers parameter must be a dictionary" )
175195
176196 # Could make this compute the label_id based on the variable name of the
177197 # dictionary passed in (using **kwargs), but
@@ -192,33 +212,45 @@ def _convert_model(val):
192212 def _get_error_message (response ):
193213 """
194214 Gets the error message from a JSON response.
195- {
196- code: 400
197- error: 'Bad request'
198- }
215+ :return: the error message
216+ :rtype: string
199217 """
200218 error_message = 'Unknown error'
201219 try :
202220 error_json = response .json ()
203221 if 'error' in error_json :
204222 if isinstance (error_json ['error' ], dict ) and 'description' in \
205223 error_json ['error' ]:
206- error_message = 'Error: ' + error_json ['error' ][
207- 'description' ]
224+ error_message = error_json ['error' ]['description' ]
208225 else :
209- error_message = 'Error: ' + error_json ['error' ]
226+ error_message = error_json ['error' ]
210227 elif 'error_message' in error_json :
211- error_message = 'Error: ' + error_json ['error_message' ]
228+ error_message = error_json ['error_message' ]
212229 elif 'msg' in error_json :
213- error_message = 'Error: ' + error_json ['msg' ]
230+ error_message = error_json ['msg' ]
214231 elif 'statusInfo' in error_json :
215- error_message = 'Error: ' + error_json ['statusInfo' ]
216- if 'description' in error_json :
217- error_message += ', Description: ' + error_json ['description' ]
218- error_message += ', Code: ' + str (response .status_code )
232+ error_message = error_json ['statusInfo' ]
219233 return error_message
220234 except :
221- return {'error' : response .text or error_message , 'code' : str (response .status_code )}
235+ return (response .text or error_message )
236+
237+
238+ @staticmethod
239+ def _get_error_info (response ):
240+ """
241+ Gets the error info (if any) from a JSON response.
242+ :return: A `dict` containing additional information about the error.
243+ :rtype: dict
244+ """
245+ info_keys = ['code_description' , 'description' , 'errors' , 'help' ,
246+ 'sub_code' , 'warnings' ]
247+ error_info = {}
248+ try :
249+ error_json = response .json ()
250+ error_info = {k :v for k , v in error_json .items () if k in info_keys }
251+ except :
252+ pass
253+ return error_info if any (error_info ) else None
222254
223255
224256 def _alchemy_html_request (self , method_name = None , url = None , html = None ,
@@ -333,13 +365,14 @@ def request(self, method, url, accept_json=False, headers=None,
333365 response_json = response .json ()
334366 if 'status' in response_json and response_json ['status' ] \
335367 == 'ERROR' :
336- response . status_code = 400
368+ status_code = 400
337369 error_message = 'Unknown error'
370+
338371 if 'statusInfo' in response_json :
339372 error_message = response_json ['statusInfo' ]
340373 if error_message == 'invalid-api-key' :
341- response . status_code = 401
342- raise WatsonException ( 'Error: ' + error_message )
374+ status_code = 401
375+ raise WatsonApiException ( status_code , error_message )
343376 return response_json
344377 return response
345378 else :
@@ -348,4 +381,6 @@ def request(self, method, url, accept_json=False, headers=None,
348381 'invalid credentials '
349382 else :
350383 error_message = self ._get_error_message (response )
351- raise WatsonException (error_message )
384+ error_info = self ._get_error_info (response )
385+ raise WatsonApiException (response .status_code , error_message ,
386+ error_info )
0 commit comments