22
22
)
23
23
import backoff
24
24
import humps
25
+ from .action_error_exception_handler import ActionErrorHandler
25
26
26
27
from .const import (
27
28
API_ENDPOINT ,
28
29
DEFAULT_TIMEOUT ,
29
30
DEFAULT_USER_AGENT ,
30
31
UINT_MAX ,
31
- XMO_ACCESS_RESTRICTION_ERR ,
32
- XMO_AUTHENTICATION_ERR ,
33
32
XMO_INVALID_SESSION_ERR ,
34
- XMO_LOGIN_RETRY_ERR ,
35
- XMO_MAX_SESSION_COUNT_ERR ,
36
33
XMO_NO_ERR ,
37
- XMO_NON_WRITABLE_PARAMETER_ERR ,
38
34
XMO_REQUEST_ACTION_ERR ,
39
35
XMO_REQUEST_NO_ERR ,
40
- XMO_UNKNOWN_PATH_ERR ,
41
36
)
42
37
from .enums import EncryptionMethod
43
38
from .exceptions import (
44
- AccessRestrictionException ,
45
39
AuthenticationException ,
46
40
BadRequestException ,
47
41
InvalidSessionException ,
48
42
LoginRetryErrorException ,
49
43
LoginTimeoutException ,
50
- MaximumSessionCountException ,
51
- NonWritableParameterException ,
52
44
UnauthorizedException ,
53
45
UnknownException ,
54
46
UnknownPathException ,
@@ -201,8 +193,19 @@ def __get_response(self, response, index=0):
201
193
202
194
return value
203
195
204
- def __get_response_value (self , response , index = 0 ):
196
+ def __get_response_value (self , response , index = 0 , throw_on_action_error = False ):
205
197
"""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 error is not None :
205
+ error_description = error ["description" ]
206
+ if error_description != XMO_NO_ERR :
207
+ raise ActionErrorHandler .from_error_description (error , error_description )
208
+
206
209
try :
207
210
value = self .__get_response (response , index )["value" ]
208
211
except KeyError :
@@ -251,37 +254,10 @@ async def __post(self, url, data):
251
254
self ._request_id = - 1
252
255
raise InvalidSessionException (error )
253
256
254
- # Error in one of the actions
257
+ # Unknown error in one of the actions
255
258
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
285
261
286
262
return result
287
263
@@ -344,6 +320,8 @@ async def login(self):
344
320
345
321
try :
346
322
response = await self .__api_request_async ([actions ], True )
323
+ ActionErrorHandler .throw_if (response )
324
+
347
325
except asyncio .TimeoutError as exception :
348
326
raise LoginTimeoutException (
349
327
"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):
362
340
"""Log out of the Sagemcom F@st device."""
363
341
actions = {"id" : 0 , "method" : "logOut" }
364
342
365
- await self .__api_request_async ([actions ], False )
343
+ response = await self .__api_request_async ([actions ], False )
344
+ ActionErrorHandler .throw_if (response )
366
345
367
346
self ._session_id = - 1
368
347
self ._server_nonce = ""
@@ -404,7 +383,7 @@ async def get_encryption_method(self):
404
383
max_tries = 1 ,
405
384
on_backoff = retry_login ,
406
385
)
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 :
408
387
"""
409
388
Retrieve raw value from router using XPath.
410
389
@@ -419,6 +398,9 @@ async def get_value_by_xpath(self, xpath: str, options: dict | None = None) -> d
419
398
}
420
399
421
400
response = await self .__api_request_async ([actions ], False )
401
+ if not suppress_action_errors :
402
+ ActionErrorHandler .throw_if (response )
403
+
422
404
data = self .__get_response_value (response )
423
405
424
406
return data
@@ -434,7 +416,7 @@ async def get_value_by_xpath(self, xpath: str, options: dict | None = None) -> d
434
416
max_tries = 1 ,
435
417
on_backoff = retry_login ,
436
418
)
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 :
438
420
"""
439
421
Retrieve raw values from router using XPath.
440
422
@@ -452,6 +434,9 @@ async def get_values_by_xpaths(self, xpaths, options: dict | None = None) -> dic
452
434
]
453
435
454
436
response = await self .__api_request_async (actions , False )
437
+ if not suppress_action_errors :
438
+ ActionErrorHandler .throw_if (response )
439
+
455
440
values = [self .__get_response_value (response , i ) for i in range (len (xpaths ))]
456
441
data = dict (zip (xpaths .keys (), values ))
457
442
@@ -487,6 +472,7 @@ async def set_value_by_xpath(
487
472
}
488
473
489
474
response = await self .__api_request_async ([actions ], False )
475
+ ActionErrorHandler .throw_if (response )
490
476
491
477
return response
492
478
@@ -515,7 +501,9 @@ async def get_device_info(self) -> DeviceInfo:
515
501
"product_class" : "Device/DeviceInfo/ProductClass" ,
516
502
"serial_number" : "Device/DeviceInfo/SerialNumber" ,
517
503
"software_version" : "Device/DeviceInfo/SoftwareVersion" ,
518
- }
504
+ },
505
+ # missing values converted to empty string
506
+ suppress_action_errors = True
519
507
)
520
508
data ["manufacturer" ] = "Sagemcom"
521
509
@@ -584,6 +572,8 @@ async def reboot(self):
584
572
}
585
573
586
574
response = await self .__api_request_async ([action ], False )
575
+ ActionErrorHandler .throw_if (response )
576
+
587
577
data = self .__get_response_value (response )
588
578
589
579
return data
0 commit comments