|
| 1 | +import ast |
| 2 | +import dis |
1 | 3 | import os |
2 | 4 | import sys |
3 | 5 | import unittest |
4 | | -import ast |
5 | 6 | import weakref |
6 | 7 |
|
7 | 8 | from test import support |
@@ -933,6 +934,123 @@ def test_stdlib_validates(self): |
933 | 934 | compile(mod, fn, "exec") |
934 | 935 |
|
935 | 936 |
|
| 937 | +class ConstantTests(unittest.TestCase): |
| 938 | + """Tests on the ast.Constant node type.""" |
| 939 | + |
| 940 | + def compile_constant(self, value): |
| 941 | + tree = ast.parse("x = 123") |
| 942 | + |
| 943 | + node = tree.body[0].value |
| 944 | + new_node = ast.Constant(value=value) |
| 945 | + ast.copy_location(new_node, node) |
| 946 | + tree.body[0].value = new_node |
| 947 | + |
| 948 | + code = compile(tree, "<string>", "exec") |
| 949 | + |
| 950 | + ns = {} |
| 951 | + exec(code, ns) |
| 952 | + return ns['x'] |
| 953 | + |
| 954 | + def test_singletons(self): |
| 955 | + for const in (None, False, True, Ellipsis, b'', frozenset()): |
| 956 | + with self.subTest(const=const): |
| 957 | + value = self.compile_constant(const) |
| 958 | + self.assertIs(value, const) |
| 959 | + |
| 960 | + def test_values(self): |
| 961 | + nested_tuple = (1,) |
| 962 | + nested_frozenset = frozenset({1}) |
| 963 | + for level in range(3): |
| 964 | + nested_tuple = (nested_tuple, 2) |
| 965 | + nested_frozenset = frozenset({nested_frozenset, 2}) |
| 966 | + values = (123, 123.0, 123j, |
| 967 | + "unicode", b'bytes', |
| 968 | + tuple("tuple"), frozenset("frozenset"), |
| 969 | + nested_tuple, nested_frozenset) |
| 970 | + for value in values: |
| 971 | + with self.subTest(value=value): |
| 972 | + result = self.compile_constant(value) |
| 973 | + self.assertEqual(result, value) |
| 974 | + |
| 975 | + def test_assign_to_constant(self): |
| 976 | + tree = ast.parse("x = 1") |
| 977 | + |
| 978 | + target = tree.body[0].targets[0] |
| 979 | + new_target = ast.Constant(value=1) |
| 980 | + ast.copy_location(new_target, target) |
| 981 | + tree.body[0].targets[0] = new_target |
| 982 | + |
| 983 | + with self.assertRaises(ValueError) as cm: |
| 984 | + compile(tree, "string", "exec") |
| 985 | + self.assertEqual(str(cm.exception), |
| 986 | + "expression which can't be assigned " |
| 987 | + "to in Store context") |
| 988 | + |
| 989 | + def test_get_docstring(self): |
| 990 | + tree = ast.parse("'docstring'\nx = 1") |
| 991 | + self.assertEqual(ast.get_docstring(tree), 'docstring') |
| 992 | + |
| 993 | + tree.body[0].value = ast.Constant(value='constant docstring') |
| 994 | + self.assertEqual(ast.get_docstring(tree), 'constant docstring') |
| 995 | + |
| 996 | + def get_load_const(self, tree): |
| 997 | + # Compile to bytecode, disassemble and get parameter of LOAD_CONST |
| 998 | + # instructions |
| 999 | + co = compile(tree, '<string>', 'exec') |
| 1000 | + consts = [] |
| 1001 | + for instr in dis.get_instructions(co): |
| 1002 | + if instr.opname == 'LOAD_CONST': |
| 1003 | + consts.append(instr.argval) |
| 1004 | + return consts |
| 1005 | + |
| 1006 | + @support.cpython_only |
| 1007 | + def test_load_const(self): |
| 1008 | + consts = [None, |
| 1009 | + True, False, |
| 1010 | + 124, |
| 1011 | + 2.0, |
| 1012 | + 3j, |
| 1013 | + "unicode", |
| 1014 | + b'bytes', |
| 1015 | + (1, 2, 3)] |
| 1016 | + |
| 1017 | + code = '\n'.join(map(repr, consts)) |
| 1018 | + code += '\n...' |
| 1019 | + |
| 1020 | + code_consts = [const for const in consts |
| 1021 | + if (not isinstance(const, (str, int, float, complex)) |
| 1022 | + or isinstance(const, bool))] |
| 1023 | + code_consts.append(Ellipsis) |
| 1024 | + # the compiler adds a final "LOAD_CONST None" |
| 1025 | + code_consts.append(None) |
| 1026 | + |
| 1027 | + tree = ast.parse(code) |
| 1028 | + self.assertEqual(self.get_load_const(tree), code_consts) |
| 1029 | + |
| 1030 | + # Replace expression nodes with constants |
| 1031 | + for expr_node, const in zip(tree.body, consts): |
| 1032 | + assert isinstance(expr_node, ast.Expr) |
| 1033 | + new_node = ast.Constant(value=const) |
| 1034 | + ast.copy_location(new_node, expr_node.value) |
| 1035 | + expr_node.value = new_node |
| 1036 | + |
| 1037 | + self.assertEqual(self.get_load_const(tree), code_consts) |
| 1038 | + |
| 1039 | + def test_literal_eval(self): |
| 1040 | + tree = ast.parse("1 + 2") |
| 1041 | + binop = tree.body[0].value |
| 1042 | + |
| 1043 | + new_left = ast.Constant(value=10) |
| 1044 | + ast.copy_location(new_left, binop.left) |
| 1045 | + binop.left = new_left |
| 1046 | + |
| 1047 | + new_right = ast.Constant(value=20) |
| 1048 | + ast.copy_location(new_right, binop.right) |
| 1049 | + binop.right = new_right |
| 1050 | + |
| 1051 | + self.assertEqual(ast.literal_eval(binop), 30) |
| 1052 | + |
| 1053 | + |
936 | 1054 | def main(): |
937 | 1055 | if __name__ != '__main__': |
938 | 1056 | return |
|
0 commit comments