I work with a module that handles errors like this:
class APIError(BetfairError):
"""
Exception raised if error is found.
"""
def __init__(
self,
response: Optional[dict],
method: str = None,
params: dict = None,
exception: Exception = None,
):
super(APIError, self).__init__(response, method, params, exception)
self.response = response
self.method = method
self.params = params
self.exception = exception
def __str__(self):
if self.response:
error_data = self.response.get("error")
return "%s \nParams: %s \nException: %s \nError: %s \nFull Response: %s" % (
self.method,
self.params,
self.exception,
error_data,
self.response,
)
else:
return "%s \nParams: %s \nException: %s" % (
self.method,
self.params,
self.exception,
)
The error output has this multiline pattern of stringvalue already separated by a colon:
betfairlightweight.exceptions.APIError: SportsAPING/v1.0/listMarketBook
Params: {'marketIds': ['1.200293211'], 'priceProjection': {'priceData': ['EX_TRADED'], 'exBestOffersOverrides': {}, 'virtualise': True, 'rolloverStakes': False}}
Exception: None
Error: {'code': -32099, 'message': 'ANGX-0006', 'data': {'APINGException': {'requestUUID': '...........', 'errorCode': 'UNEXPECTED_ERROR', 'errorDetails': ''}, 'exceptionname': 'APINGException'}}
Full Response: {'jsonrpc': '2.0', 'error': {'code': -32099, 'message': 'ANGX-0006', 'data': {'APINGException': {'requestUUID': '..........', 'errorCode': 'UNEXPECTED_ERROR', 'errorDetails': ''}, 'exceptionname': 'APINGException'}}, 'id': 1}
So that I can access the values regardless of their position, I'm converting the string into a dictionary like this:
# except Exception as e:
# e.__str__()
e = """betfairlightweight.exceptions.APIError: SportsAPING/v1.0/listMarketBook
Params: {'marketIds': ['1.200293211'], 'priceProjection': {'priceData': ['EX_TRADED'], 'exBestOffersOverrides': {}, 'virtualise': True, 'rolloverStakes': False}}
Exception: None
Error: {'code': -32099, 'message': 'ANGX-0006', 'data': {'APINGException': {'requestUUID': '...........', 'errorCode': 'UNEXPECTED_ERROR', 'errorDetails': ''}, 'exceptionname': 'APINGException'}}
Full Response: {'jsonrpc': '2.0', 'error': {'code': -32099, 'message': 'ANGX-0006', 'data': {'APINGException': {'requestUUID': '..........', 'errorCode': 'UNEXPECTED_ERROR', 'errorDetails': ''}, 'exceptionname': 'APINGException'}}, 'id': 1}"""
fs = []
nfs = []
for row in e.split('\n'):
fs.append(row[:row.find(':')] ':')
nfs.append('\'' row[:row.find(':')] '\'' ':')
for x, y in zip(fs, nfs):
e = e.replace(x, y)
for z in e.split('\n'):
if (': {' not in z) and (': None' not in z):
e = e.replace(z, z.replace(': ', ': \'').strip() '\'')
for_dict = eval('{' e.replace('\n', ',') '}')
print(for_dict)
# Get SportsAPING/v1.0/listMarketBook value
print(for_dict['betfairlightweight.exceptions.APIError'])
# Get ABC-0025 value
print(for_dict['Error']['message'])
# Get 2.0 value
print(for_dict['Full Response']['jsonrpc'])
# Get ['EX_TRADED'] value
print(for_dict['Params']['priceProjection']['priceData'])
Is there a more pythonic method or a module that handles this type of multiline string to be able to generate this dictionary in a cleaner and more professional way?
CodePudding user response:
this feels slightly subjective but here is how I would implement it (after spending all of a minute or two on it)
import ast
def line_to_dict_entry(line):
key,value = line.strip().split(":",1)
try:
# try and parse it to a base pyobject
value = ast.literal_eval(value.strip())
except Exception as e:
# just let it be a string
value = value.strip()
return key,value
data = dict(line_to_dict_entry(l) for l in e.splitlines(False))
print(data)
CodePudding user response:
import re
from ast import literal_eval
e = """betfairlightweight.exceptions.APIError: SportsAPING/v1.0/listMarketBook
Params: {'marketIds': ['1.200293211'], 'priceProjection': {'priceData': ['EX_TRADED'], 'exBestOffersOverrides': {}, 'virtualise': True, 'rolloverStakes': False}}
Exception: None
Error: {'code': -32099, 'message': 'ANGX-0006', 'data': {'APINGException': {'requestUUID': '...........', 'errorCode': 'UNEXPECTED_ERROR', 'errorDetails': ''}, 'exceptionname': 'APINGException'}}
Full Response: {'jsonrpc': '2.0', 'error': {'code': -32099, 'message': 'ANGX-0006', 'data': {'APINGException': {'requestUUID': '..........', 'errorCode': 'UNEXPECTED_ERROR', 'errorDetails': ''}, 'exceptionname': 'APINGException'}}, 'id': 1}"""
data = dict(x.split(':', 1) for x in e.splitlines())
data = {k.strip():literal_eval(v) if '{' in v else v.strip() for k,v in data.items()}
print(data)
Output:
{'betfairlightweight.exceptions.APIError': 'SportsAPING/v1.0/listMarketBook', 'Params': {'marketIds': ['1.200293211'], 'priceProjection': {'priceData': ['EX_TRADED'], 'exBestOffersOverrides': {}, 'virtualise': True, 'rolloverStakes': False}}, 'Exception': 'None', 'Error': {'code': -32099, 'message': 'ANGX-0006', 'data': {'APINGException': {'requestUUID': '...........', 'errorCode': 'UNEXPECTED_ERROR', 'errorDetails': ''}, 'exceptionname': 'APINGException'}}, 'Full Response': {'jsonrpc': '2.0', 'error': {'code': -32099, 'message': 'ANGX-0006', 'data': {'APINGException': {'requestUUID': '..........', 'errorCode': 'UNEXPECTED_ERROR', 'errorDetails': ''}, 'exceptionname': 'APINGException'}}, 'id': 1}}
Pretty Output:
import json
print(json.dumps(data, indent=3))
...
{
"betfairlightweight.exceptions.APIError": "SportsAPING/v1.0/listMarketBook",
"Params": {
"marketIds": [
"1.200293211"
],
"priceProjection": {
"priceData": [
"EX_TRADED"
],
"exBestOffersOverrides": {},
"virtualise": true,
"rolloverStakes": false
}
},
"Exception": "None",
"Error": {
"code": -32099,
"message": "ANGX-0006",
"data": {
"APINGException": {
"requestUUID": "...........",
"errorCode": "UNEXPECTED_ERROR",
"errorDetails": ""
},
"exceptionname": "APINGException"
}
},
"Full Response": {
"jsonrpc": "2.0",
"error": {
"code": -32099,
"message": "ANGX-0006",
"data": {
"APINGException": {
"requestUUID": "..........",
"errorCode": "UNEXPECTED_ERROR",
"errorDetails": ""
},
"exceptionname": "APINGException"
}
},
"id": 1
}
}