I'm trying to read in a string representation of a Tuple from a file, and add the tuple to a list. Here's the relevant code.
raw_data = userfile.read().split('\n')
for a in raw_data :
print a
btc_history.append(ast.literal_eval(a))
Here is the output:
(Decimal('11.66985'), Decimal('0E-8'))
Traceback (most recent call last):
File "./goxnotify.py", line 74, in <module>
main()
File "./goxnotify.py", line 68, in main
local.load_user_file(username,btc_history)
File "/home/unix-dude/Code/GoxNotify/local_functions.py", line 53, in load_user_file
btc_history.append(ast.literal_eval(a))
File "/usr/lib/python2.7/ast.py", line 80, in literal_eval
return _convert(node_or_string)
`File "/usr/lib/python2.7/ast.py", line 58, in _convert
return tuple(map(_convert, node.elts))
File "/usr/lib/python2.7/ast.py", line 79, in _convert
raise ValueError('malformed string')
ValueError: malformed string
ast.literal_eval
(located inast.py
) parses the tree withast.parse
first, then it evaluates the code with quite an ugly recursive function, interpreting the parse tree elements and replacing them with their literal equivalents. Unfortunately the code is not at all expandable, so to addDecimal
to the code you need to copy all the code and start over.For a slightly easier approach, you can use
ast.parse
module to parse the expression, and then theast.NodeVisitor
orast.NodeTransformer
to ensure that there is no unwanted syntax or unwanted variable accesses. Then compile withcompile
andeval
to get the result.The code is a bit different from
literal_eval
in that this code actually useseval
, but in my opinion is simpler to understand and one does not need to dig too deep into AST trees. It specifically only allows some syntax, explicitly forbidding for example lambdas, attribute accesses (foo.__dict__
is very evil), or accesses to any names that are not deemed safe. It parses your expression fine, and as an extra I also addedNum
(float and integer), list and dictionary literals.Also, works the same on 2.7 and 3.3
From the documentation for
ast.literal_eval()
:Decimal
isn't on the list of things allowed byast.literal_eval()
.