Skip to content

ast.literal_eval does not execute addition correclty #94749

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Rik-de-Kort opened this issue Jul 11, 2022 · 3 comments
Closed

ast.literal_eval does not execute addition correclty #94749

Rik-de-Kort opened this issue Jul 11, 2022 · 3 comments
Assignees
Labels
stdlib Python modules in the Lib dir type-bug An unexpected behavior, bug, or error

Comments

@Rik-de-Kort
Copy link

Bug report
The following script fails to produce the answer 3 in the REPL (or anywhere else).

import ast

tree = ast.BinOp(left=ast.Constant(1), op=ast.Add(), right=ast.Constant(2))
print(ast.literal_eval(tree))

Instead I get

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python3.10/ast.py", line 108, in literal_eval
    return _convert(node_or_string)
  File "/usr/lib/python3.10/ast.py", line 100, in _convert
    left = _convert_signed_num(node.left)
  File "/usr/lib/python3.10/ast.py", line 81, in _convert_signed_num
    return _convert_num(node)
  File "/usr/lib/python3.10/ast.py", line 72, in _convert_num
    _raise_malformed_node(node)
  File "/usr/lib/python3.10/ast.py", line 69, in _raise_malformed_node
    raise ValueError(msg + f': {node!r}')
ValueError: malformed node or string: 1

Your environment
Tested on Python 3.10.5 on ArchLinux and 3.10.4 on Windows 10.

Root cause
On line 102 in ast.py, in literal_eval (link), the argument right is checked to be of type complex. This check will fail if right is of type int or float, and the whole control flow will kick through to line 107, which rightly rejects the BinOp as a malformed number.

Discussion
To be honest, I'm not sure why literal_eval even exists in the first place. It has (in addition to this one) many issues, see #83340. The functionality can be acquired by executing eval(ast.unparse(tree)), without any of the downsides of having an extra codepath reimplementing standard cpython functionality.
As it stands, it's an unnecessary complication that has cost me ~30 minutes to debug and submit a bug report for. I hope this helps other people avoid the same trap.

@Rik-de-Kort Rik-de-Kort added the type-bug An unexpected behavior, bug, or error label Jul 11, 2022
@hugovk hugovk added the stdlib Python modules in the Lib dir label Jul 11, 2022
@isidentical
Copy link
Member

isidentical commented Jul 11, 2022

ast.literal_eval is not supposed to evaluate binary operations, as it is clearly stated in the documentation:

It is not capable of evaluating arbitrarily complex expressions, for example involving operators or indexing.

On line 102 in ast.py, in literal_eval (link), the argument right is checked to be of type complex. This check will fail if right is of type int or float, and the whole control flow will kick through to line 107, which rightly rejects the BinOp as a malformed number.

The code path you have shared is only for complex numbers, like 1+5j. Not for common binary operations.

@isidentical isidentical closed this as not planned Won't fix, can't repro, duplicate, stale Jul 11, 2022
@Rik-de-Kort
Copy link
Author

ast.literal_eval is not supposed to evaluate binary operations, as it is clearly stated in the documentation:

Ah, I misunderstood this sentence. I thought simple expressions were supported, but upon second reading it's only for evaluating expression that directly represent a Python value, and the hint is in the name. The code path is necessary for evaluating a complex number literal rather than complex number addition.

Thanks for the reply!

@pochmann
Copy link
Contributor

pochmann commented Jul 12, 2022

Regarding why literal_eval exists when eval can do more: Because eval can do more. Dangerously more. If you carelessly eval untrustworthy data (like user input), it might for example delete all your files. Even eval's own documentation says "See ast.literal_eval() for a function that can safely evaluate strings with expressions containing only literals".

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
stdlib Python modules in the Lib dir type-bug An unexpected behavior, bug, or error
Projects
None yet
Development

No branches or pull requests

5 participants