bpo-40355: Improve error messages in ast.literal_eval with malformed Dict nodes (GH-19868)
Co-authored-by: Pablo Galindo <Pablogsal@gmail.com>
This commit is contained in:
parent
fb2c7c4afb
commit
c21c51235a
11
Lib/ast.py
11
Lib/ast.py
|
@ -62,11 +62,12 @@ def literal_eval(node_or_string):
|
||||||
node_or_string = parse(node_or_string, mode='eval')
|
node_or_string = parse(node_or_string, mode='eval')
|
||||||
if isinstance(node_or_string, Expression):
|
if isinstance(node_or_string, Expression):
|
||||||
node_or_string = node_or_string.body
|
node_or_string = node_or_string.body
|
||||||
|
def _raise_malformed_node(node):
|
||||||
|
raise ValueError(f'malformed node or string: {node!r}')
|
||||||
def _convert_num(node):
|
def _convert_num(node):
|
||||||
if isinstance(node, Constant):
|
if not isinstance(node, Constant) or type(node.value) not in (int, float, complex):
|
||||||
if type(node.value) in (int, float, complex):
|
_raise_malformed_node(node)
|
||||||
return node.value
|
return node.value
|
||||||
raise ValueError('malformed node or string: ' + repr(node))
|
|
||||||
def _convert_signed_num(node):
|
def _convert_signed_num(node):
|
||||||
if isinstance(node, UnaryOp) and isinstance(node.op, (UAdd, USub)):
|
if isinstance(node, UnaryOp) and isinstance(node.op, (UAdd, USub)):
|
||||||
operand = _convert_num(node.operand)
|
operand = _convert_num(node.operand)
|
||||||
|
@ -88,6 +89,8 @@ def literal_eval(node_or_string):
|
||||||
node.func.id == 'set' and node.args == node.keywords == []):
|
node.func.id == 'set' and node.args == node.keywords == []):
|
||||||
return set()
|
return set()
|
||||||
elif isinstance(node, Dict):
|
elif isinstance(node, Dict):
|
||||||
|
if len(node.keys) != len(node.values):
|
||||||
|
_raise_malformed_node(node)
|
||||||
return dict(zip(map(_convert, node.keys),
|
return dict(zip(map(_convert, node.keys),
|
||||||
map(_convert, node.values)))
|
map(_convert, node.values)))
|
||||||
elif isinstance(node, BinOp) and isinstance(node.op, (Add, Sub)):
|
elif isinstance(node, BinOp) and isinstance(node.op, (Add, Sub)):
|
||||||
|
|
|
@ -965,6 +965,12 @@ Module(
|
||||||
self.assertRaises(ValueError, ast.literal_eval, '3+(0+6j)')
|
self.assertRaises(ValueError, ast.literal_eval, '3+(0+6j)')
|
||||||
self.assertRaises(ValueError, ast.literal_eval, '-(3+6j)')
|
self.assertRaises(ValueError, ast.literal_eval, '-(3+6j)')
|
||||||
|
|
||||||
|
def test_literal_eval_malformed_dict_nodes(self):
|
||||||
|
malformed = ast.Dict(keys=[ast.Constant(1), ast.Constant(2)], values=[ast.Constant(3)])
|
||||||
|
self.assertRaises(ValueError, ast.literal_eval, malformed)
|
||||||
|
malformed = ast.Dict(keys=[ast.Constant(1)], values=[ast.Constant(2), ast.Constant(3)])
|
||||||
|
self.assertRaises(ValueError, ast.literal_eval, malformed)
|
||||||
|
|
||||||
def test_bad_integer(self):
|
def test_bad_integer(self):
|
||||||
# issue13436: Bad error message with invalid numeric values
|
# issue13436: Bad error message with invalid numeric values
|
||||||
body = [ast.ImportFrom(module='time',
|
body = [ast.ImportFrom(module='time',
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
Improve error reporting in :func:`ast.literal_eval` in the presence of malformed :class:`ast.Dict`
|
||||||
|
nodes instead of silently ignoring any non-conforming elements. Patch by Curtis Bucher.
|
Loading…
Reference in New Issue