Reputation: 2279
Somewhere I'm being an idiot, but I can't find where.
I'm running a Python script using a PostgreSQL database through ODBC. I am trying to extract the meaningful piece from a database exception message. Here is the raw message, with line breaks added for readability:
(-2147352567, 'Exception occurred.', (0, 'Microsoft OLE DB Provider for ODBC Drivers',
'ERROR: Charge not in a correct status to delete;\nError while executing the query',
None, 0, -2147467259), None)
Note that there are two sets of parentheses in this string. First, I find the locations of the outer ones and slice them off. This gives the expected result:
-2147352567, 'Exception occurred.', (0, 'Microsoft OLE DB Provider for ODBC Drivers',
'ERROR: Charge not in a correct status to delete;\nError while executing the query',
None, 0, -2147467259), None
Then, using as far as I can tell identical code, I strip off the other set of parentheses and everything outside them. This gives this result:
(0, 'Microsoft OLE DB Provider for ODBC Drivers',
'ERROR: Charge not in a correct status to delete;\nError while executing the query',
None, 0, -214746725
The open parenthesis is still here, even though I am using the result of the find() method the same way, adding one to the open parenthesis location as the start of the slice, both times.
Here is the code:
print (errorString)
openParenLocation = errorString.find('(')
closeParenLocation = errorString.rfind(')')
strippedString = errorString[openParenLocation + 1:closeParenLocation]
openParenLocation = strippedString.find('(')
closeParenLocation = strippedString.rfind(')')
dbErrorString = errorString[openParenLocation + 1:closeParenLocation]
print (strippedString)
print ("{}, {}".format(openParenLocation, closeParenLocation))
print (dbErrorString)
And here is the raw output, with no added line breaks:
(-2147352567, 'Exception occurred.', (0, 'Microsoft OLE DB Provider for ODBC Drivers', 'ERROR: Charge not in a correct status to delete;\nError while executing the query', None, 0, -2147467259), None)
-2147352567, 'Exception occurred.', (0, 'Microsoft OLE DB Provider for ODBC Drivers', 'ERROR: Charge not in a correct status to delete;\nError while executing the query', None, 0, -2147467259), None
36, 191
(0, 'Microsoft OLE DB Provider for ODBC Drivers', 'ERROR: Charge not in a correct status to delete;\nError while executing the query', None, 0, -214746725
Test code using a much smaller string works as expected:
testString = "(abc(def)ghij)"
openParenLocation = testString.find('(')
closeParenLocation = testString.rfind(')')
strippedTestString = testString[openParenLocation + 1:closeParenLocation]
openParenLocation = strippedTestString.find('(')
closeParenLocation = strippedTestString.rfind(')')
finalTestString = strippedTestString[openParenLocation + 1:closeParenLocation]
Thank you very much.
Upvotes: 0
Views: 101
Reputation: 15349
Given that your string looks like Python syntax, have you considered using the standard ast
library module to do all this work for you?
>>> errorString =r"""\
(-2147352567, 'Exception occurred.', (0, 'Microsoft OLE DB Provider for ODBC Drivers',
'ERROR: Charge not in a correct status to delete;\nError while executing the query',
None, 0, -2147467259), None)"""
>>> import ast
>>> a = ast.parse(errorString).body[0].value
>>> a
<_ast.Tuple at 0x10802d3d0>
>>> a.elts[0]
<_ast.Num at 0x10802d410>
>>> a.elts[0].n
-2147352567
>>> a.elts[1]
<_ast.Str at 0x10802d450>
>>> a.elts[1].s
'Exception occurred.'
>>> a.elts[2]
<_ast.Tuple at 0x10802d490>
>>> # so now lather/rinse repeat: iterate over a.elts[2].elts
>>> a.elts[3]
<_ast.Name at 0x10802d650>
>>> a.elts[3].id
'None'
An even simpler way would be to use ast.literal_eval
to turn the string directly into the Python object that it describes. It's like the builtin eval
, but safe from the security perspective because it will not evaluate anything that isn't a literal (so, any malicious errorString
content will not be executed).
>>> a = ast.literal_eval(errorString)
>>> a[0]
-2147352567
>>> a[1]
'Exception occurred.'
>>> a[2][0]
0
etc.
Upvotes: 0
Reputation: 336
It looks like this line:
dbErrorString = errorString[openParenLocation + 1:closeParenLocation]
should instead be:
dbErrorString = strippedString[openParenLocation + 1:closeParenLocation]
Upvotes: 1