Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 11 additions & 2 deletions Lib/ast.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,17 +59,26 @@ def literal_eval(node_or_string):
"""
if isinstance(node_or_string, str):
node_or_string = parse(node_or_string.lstrip(" \t"), mode='eval').body
return _convert_literal(node_or_string, True)
elif isinstance(node_or_string, Expression):
node_or_string = node_or_string.body
return _convert_literal(node_or_string)


def _convert_literal(node):
_type_None = type(None)
_type_Ellipsis = type(...)


def _convert_literal(node, omit_validation=False):
"""
Used by `literal_eval` to convert an AST node into a value.
"""
if isinstance(node, Constant):
return node.value
if omit_validation:
return node.value
if type(value := node.value) in (str, bytes, int, float, complex,
bool, _type_None, _type_Ellipsis):
return value
if isinstance(node, Dict) and len(node.keys) == len(node.values):
return dict(zip(
map(_convert_literal, node.keys),
Expand Down
3 changes: 2 additions & 1 deletion Lib/inspect.py
Original file line number Diff line number Diff line change
Expand Up @@ -2216,7 +2216,8 @@ def wrap_value(s):
except NameError:
raise ValueError

if isinstance(value, (str, int, float, bytes, bool, type(None))):
if type(value) in (str, int, float, bytes, bool, complex,
type(None), type(...)):
return ast.Constant(value)
raise ValueError

Expand Down
4 changes: 4 additions & 0 deletions Lib/test/test_ast/test_ast.py
Original file line number Diff line number Diff line change
Expand Up @@ -1890,6 +1890,10 @@ def test_literal_eval(self):
self.assertRaises(ValueError, ast.literal_eval, '++6')
self.assertRaises(ValueError, ast.literal_eval, '+True')
self.assertRaises(ValueError, ast.literal_eval, '2+3')
# gh-141778: reject values of invalid types
node = ast.Expression(body=ast.Constant(object()))
ast.fix_missing_locations(node)
self.assertRaises(ValueError, ast.literal_eval, node)

def test_literal_eval_str_int_limit(self):
with support.adjust_int_max_str_digits(4000):
Expand Down
4 changes: 3 additions & 1 deletion Lib/test/test_inspect/test_inspect.py
Original file line number Diff line number Diff line change
Expand Up @@ -6286,7 +6286,9 @@ def test_threading_module_has_signatures(self):
def test_thread_module_has_signatures(self):
import _thread
no_signature = {'RLock'}
self._test_module_has_signatures(_thread, no_signature)
unsupported_signature = {'interrupt_main'}
self._test_module_has_signatures(_thread, no_signature,
unsupported_signature)

def test_time_module_has_signatures(self):
no_signature = {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Validate value types of :class:`ast.Constant` nodes in the
:func:`ast.literal_eval`. Patch by Sergey B Kirpichev.
Loading