Skip to content

Commit 5927385

Browse files
committed
Support sentinel and ast.Compare in ast.literal_eval()
1 parent 7c09f9f commit 5927385

2 files changed

Lines changed: 41 additions & 2 deletions

File tree

Lib/ast.py

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,9 +91,16 @@ def _convert_literal(node, omit_validation=False):
9191
return set(map(_convert_literal, node.elts))
9292
if (
9393
isinstance(node, Call) and isinstance(node.func, Name)
94-
and node.func.id == 'set' and node.args == node.keywords == []
9594
):
96-
return set()
95+
if node.func.id == 'set' and node.args == node.keywords == []:
96+
return set()
97+
elif (
98+
node.func.id == 'sentinel' and len(node.args) == 1
99+
and node.keywords == []
100+
and isinstance(arg := node.args[0], Constant)
101+
and isinstance(name := arg.value, str)
102+
):
103+
return sentinel(name)
97104
if (
98105
isinstance(node, UnaryOp)
99106
and isinstance(node.op, (UAdd, USub))
@@ -116,6 +123,29 @@ def _convert_literal(node, omit_validation=False):
116123
return left + right
117124
else:
118125
return left - right
126+
if (isinstance(node, Compare)
127+
and isinstance(node.left, Constant)
128+
and type(left := _convert_literal(node.left)) in (int, float, str)
129+
and len(node.ops) == 1
130+
and isinstance(op := node.ops[0], (Eq, NotEq, Lt, LtE, Gt, GtE))
131+
and len(node.comparators) == 1
132+
and isinstance(node.comparators[0], Constant)
133+
and type(right := node.comparators[0].value) in (int, float, str)
134+
and (type(left) == type(right) or str not in [type(left), type(right)])
135+
):
136+
if isinstance(op, Eq):
137+
return left == right
138+
elif isinstance(op, NotEq):
139+
return left != right
140+
elif isinstance(op, Lt):
141+
return left < right
142+
elif isinstance(op, LtE):
143+
return left <= right
144+
elif isinstance(op, Gt):
145+
return left > right
146+
else:
147+
return left >= right
148+
119149
msg = "malformed node or string"
120150
if lno := getattr(node, 'lineno', None):
121151
msg += f' on line {lno}'

Lib/test/test_ast/test_ast.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2032,6 +2032,9 @@ def test_literal_eval(self):
20322032
self.assertEqual(ast.literal_eval('{1, 2, 3}'), {1, 2, 3})
20332033
self.assertEqual(ast.literal_eval('b"hi"'), b"hi")
20342034
self.assertEqual(ast.literal_eval('set()'), set())
2035+
val = ast.literal_eval('sentinel("xyz")')
2036+
self.assertTrue(isinstance(val, sentinel))
2037+
self.assertEqual(val.__name__, "xyz")
20352038
self.assertRaises(ValueError, ast.literal_eval, 'foo()')
20362039
self.assertEqual(ast.literal_eval('6'), 6)
20372040
self.assertEqual(ast.literal_eval('+6'), 6)
@@ -2040,6 +2043,12 @@ def test_literal_eval(self):
20402043
self.assertEqual(ast.literal_eval('+3.25'), 3.25)
20412044
self.assertEqual(ast.literal_eval('-3.25'), -3.25)
20422045
self.assertEqual(repr(ast.literal_eval('-0.0')), '-0.0')
2046+
self.assertEqual(ast.literal_eval('1 == 2'), False)
2047+
self.assertEqual(ast.literal_eval('1 != 2'), True)
2048+
self.assertEqual(ast.literal_eval('1 < 2'), True)
2049+
self.assertEqual(ast.literal_eval('1 <= 2'), True)
2050+
self.assertEqual(ast.literal_eval('1 >= 2'), False)
2051+
self.assertEqual(ast.literal_eval('1 > 2'), False)
20432052
self.assertRaises(ValueError, ast.literal_eval, '++6')
20442053
self.assertRaises(ValueError, ast.literal_eval, '+True')
20452054
self.assertRaises(ValueError, ast.literal_eval, '2+3')

0 commit comments

Comments
 (0)