2222)
2323import backoff
2424import humps
25+ from .action_error_exception_handler import ActionErrorHandler
2526
2627from .const import (
2728 API_ENDPOINT ,
2829 DEFAULT_TIMEOUT ,
2930 DEFAULT_USER_AGENT ,
3031 UINT_MAX ,
31- XMO_ACCESS_RESTRICTION_ERR ,
32- XMO_AUTHENTICATION_ERR ,
3332 XMO_INVALID_SESSION_ERR ,
34- XMO_LOGIN_RETRY_ERR ,
35- XMO_MAX_SESSION_COUNT_ERR ,
3633 XMO_NO_ERR ,
37- XMO_NON_WRITABLE_PARAMETER_ERR ,
3834 XMO_REQUEST_ACTION_ERR ,
3935 XMO_REQUEST_NO_ERR ,
40- XMO_UNKNOWN_PATH_ERR ,
4136)
4237from .enums import EncryptionMethod
4338from .exceptions import (
44- AccessRestrictionException ,
4539 AuthenticationException ,
4640 BadRequestException ,
4741 InvalidSessionException ,
4842 LoginRetryErrorException ,
4943 LoginTimeoutException ,
50- MaximumSessionCountException ,
51- NonWritableParameterException ,
5244 UnauthorizedException ,
5345 UnknownException ,
5446 UnknownPathException ,
@@ -201,8 +193,19 @@ def __get_response(self, response, index=0):
201193
202194 return value
203195
204- def __get_response_value (self , response , index = 0 ):
196+ def __get_response_value (self , response , index = 0 , throw_on_action_error = False ):
205197 """Retrieve response value from value."""
198+ if throw_on_action_error :
199+ try :
200+ error = response ["reply" ]["actions" ][index ]["error" ]
201+ except (KeyError , IndexError ):
202+ error = None
203+
204+ if not error is None :
205+ error_description = error ["description" ]
206+ if error_description != XMO_NO_ERR :
207+ raise ActionErrorHandler .FromErrorDescription (error , error_description )
208+
206209 try :
207210 value = self .__get_response (response , index )["value" ]
208211 except KeyError :
@@ -251,37 +254,10 @@ async def __post(self, url, data):
251254 self ._request_id = - 1
252255 raise InvalidSessionException (error )
253256
254- # Error in one of the actions
257+ # Unknown error in one of the actions
255258 if error ["description" ] == XMO_REQUEST_ACTION_ERR :
256- # pylint:disable=fixme
257- # TODO How to support multiple actions + error handling?
258- actions = result ["reply" ]["actions" ]
259- for action in actions :
260- action_error = action ["error" ]
261- action_error_desc = action_error ["description" ]
262-
263- if action_error_desc == XMO_NO_ERR :
264- continue
265-
266- if action_error_desc == XMO_AUTHENTICATION_ERR :
267- raise AuthenticationException (action_error )
268-
269- if action_error_desc == XMO_ACCESS_RESTRICTION_ERR :
270- raise AccessRestrictionException (action_error )
271-
272- if action_error_desc == XMO_NON_WRITABLE_PARAMETER_ERR :
273- raise NonWritableParameterException (action_error )
274-
275- if action_error_desc == XMO_UNKNOWN_PATH_ERR :
276- raise UnknownPathException (action_error )
277-
278- if action_error_desc == XMO_MAX_SESSION_COUNT_ERR :
279- raise MaximumSessionCountException (action_error )
280-
281- if action_error_desc == XMO_LOGIN_RETRY_ERR :
282- raise LoginRetryErrorException (action_error )
283-
284- raise UnknownException (action_error )
259+ # leave this to the layer above as there may be multiple actions
260+ pass
285261
286262 return result
287263
@@ -344,6 +320,8 @@ async def login(self):
344320
345321 try :
346322 response = await self .__api_request_async ([actions ], True )
323+ ActionErrorHandler .ThrowIf (response )
324+
347325 except asyncio .TimeoutError as exception :
348326 raise LoginTimeoutException (
349327 "Login request timed-out. This could be caused by using the wrong encryption method, or using a (non) SSL connection."
@@ -362,7 +340,8 @@ async def logout(self):
362340 """Log out of the Sagemcom F@st device."""
363341 actions = {"id" : 0 , "method" : "logOut" }
364342
365- await self .__api_request_async ([actions ], False )
343+ response = await self .__api_request_async ([actions ], False )
344+ ActionErrorHandler .ThrowIf (response )
366345
367346 self ._session_id = - 1
368347 self ._server_nonce = ""
@@ -404,7 +383,7 @@ async def get_encryption_method(self):
404383 max_tries = 1 ,
405384 on_backoff = retry_login ,
406385 )
407- async def get_value_by_xpath (self , xpath : str , options : dict | None = None ) -> dict :
386+ async def get_value_by_xpath (self , xpath : str , options : dict | None = None , suppress_action_errors = False ) -> dict :
408387 """
409388 Retrieve raw value from router using XPath.
410389
@@ -419,6 +398,9 @@ async def get_value_by_xpath(self, xpath: str, options: dict | None = None) -> d
419398 }
420399
421400 response = await self .__api_request_async ([actions ], False )
401+ if not suppress_action_errors :
402+ ActionErrorHandler .ThrowIf (response )
403+
422404 data = self .__get_response_value (response )
423405
424406 return data
@@ -434,7 +416,7 @@ async def get_value_by_xpath(self, xpath: str, options: dict | None = None) -> d
434416 max_tries = 1 ,
435417 on_backoff = retry_login ,
436418 )
437- async def get_values_by_xpaths (self , xpaths , options : dict | None = None ) -> dict :
419+ async def get_values_by_xpaths (self , xpaths , options : dict | None = None , suppress_action_errors = False ) -> dict :
438420 """
439421 Retrieve raw values from router using XPath.
440422
@@ -452,6 +434,9 @@ async def get_values_by_xpaths(self, xpaths, options: dict | None = None) -> dic
452434 ]
453435
454436 response = await self .__api_request_async (actions , False )
437+ if not suppress_action_errors :
438+ ActionErrorHandler .ThrowIf (response )
439+
455440 values = [self .__get_response_value (response , i ) for i in range (len (xpaths ))]
456441 data = dict (zip (xpaths .keys (), values ))
457442
@@ -487,6 +472,7 @@ async def set_value_by_xpath(
487472 }
488473
489474 response = await self .__api_request_async ([actions ], False )
475+ ActionErrorHandler .ThrowIf (response )
490476
491477 return response
492478
@@ -515,7 +501,9 @@ async def get_device_info(self) -> DeviceInfo:
515501 "product_class" : "Device/DeviceInfo/ProductClass" ,
516502 "serial_number" : "Device/DeviceInfo/SerialNumber" ,
517503 "software_version" : "Device/DeviceInfo/SoftwareVersion" ,
518- }
504+ },
505+ # missing values converted to empty string
506+ suppress_action_errors = True
519507 )
520508 data ["manufacturer" ] = "Sagemcom"
521509
@@ -584,6 +572,8 @@ async def reboot(self):
584572 }
585573
586574 response = await self .__api_request_async ([action ], False )
575+ ActionErrorHandler .ThrowIf (response )
576+
587577 data = self .__get_response_value (response )
588578
589579 return data
0 commit comments