|
1 | 1 | import ast |
2 | 2 | import builtins |
| 3 | +import copy |
3 | 4 | import dis |
4 | 5 | import enum |
5 | 6 | import os |
|
23 | 24 | from test.support.ast_helper import ASTTestMixin |
24 | 25 |
|
25 | 26 | def to_tuple(t): |
26 | | - if t is None or isinstance(t, (str, int, complex)) or t is Ellipsis: |
| 27 | + if t is None or isinstance(t, (str, int, complex, float, bytes)) or t is Ellipsis: |
27 | 28 | return t |
28 | 29 | elif isinstance(t, list): |
29 | 30 | return [to_tuple(e) for e in t] |
@@ -971,15 +972,6 @@ def test_no_fields(self): |
971 | 972 | x = ast.Sub() |
972 | 973 | self.assertEqual(x._fields, ()) |
973 | 974 |
|
974 | | - def test_pickling(self): |
975 | | - import pickle |
976 | | - |
977 | | - for protocol in range(pickle.HIGHEST_PROTOCOL + 1): |
978 | | - for ast in (compile(i, "?", "exec", 0x400) for i in exec_tests): |
979 | | - with self.subTest(ast=ast, protocol=protocol): |
980 | | - ast2 = pickle.loads(pickle.dumps(ast, protocol)) |
981 | | - self.assertEqual(to_tuple(ast2), to_tuple(ast)) |
982 | | - |
983 | 975 | def test_invalid_sum(self): |
984 | 976 | pos = dict(lineno=2, col_offset=3) |
985 | 977 | m = ast.Module([ast.Expr(ast.expr(**pos), **pos)], []) |
@@ -1222,6 +1214,80 @@ def test_none_checks(self) -> None: |
1222 | 1214 | for node, attr, source in tests: |
1223 | 1215 | self.assert_none_check(node, attr, source) |
1224 | 1216 |
|
| 1217 | + |
| 1218 | +class CopyTests(unittest.TestCase): |
| 1219 | + """Test copying and pickling AST nodes.""" |
| 1220 | + |
| 1221 | + def test_pickling(self): |
| 1222 | + import pickle |
| 1223 | + |
| 1224 | + for protocol in range(pickle.HIGHEST_PROTOCOL + 1): |
| 1225 | + for code in exec_tests: |
| 1226 | + with self.subTest(code=code, protocol=protocol): |
| 1227 | + tree = compile(code, "?", "exec", 0x400) |
| 1228 | + ast2 = pickle.loads(pickle.dumps(tree, protocol)) |
| 1229 | + self.assertEqual(to_tuple(ast2), to_tuple(tree)) |
| 1230 | + |
| 1231 | + def test_copy_with_parents(self): |
| 1232 | + # gh-120108 |
| 1233 | + code = """ |
| 1234 | + ('',) |
| 1235 | + while i < n: |
| 1236 | + if ch == '': |
| 1237 | + ch = format[i] |
| 1238 | + if ch == '': |
| 1239 | + if freplace is None: |
| 1240 | + '' % getattr(object) |
| 1241 | + elif ch == '': |
| 1242 | + if zreplace is None: |
| 1243 | + if hasattr: |
| 1244 | + offset = object.utcoffset() |
| 1245 | + if offset is not None: |
| 1246 | + if offset.days < 0: |
| 1247 | + offset = -offset |
| 1248 | + h = divmod(timedelta(hours=0)) |
| 1249 | + if u: |
| 1250 | + zreplace = '' % (sign,) |
| 1251 | + elif s: |
| 1252 | + zreplace = '' % (sign,) |
| 1253 | + else: |
| 1254 | + zreplace = '' % (sign,) |
| 1255 | + elif ch == '': |
| 1256 | + if Zreplace is None: |
| 1257 | + Zreplace = '' |
| 1258 | + if hasattr(object): |
| 1259 | + s = object.tzname() |
| 1260 | + if s is not None: |
| 1261 | + Zreplace = s.replace('') |
| 1262 | + newformat.append(Zreplace) |
| 1263 | + else: |
| 1264 | + push('') |
| 1265 | + else: |
| 1266 | + push(ch) |
| 1267 | +
|
| 1268 | + """ |
| 1269 | + tree = ast.parse(textwrap.dedent(code)) |
| 1270 | + for node in ast.walk(tree): |
| 1271 | + for child in ast.iter_child_nodes(node): |
| 1272 | + child.parent = node |
| 1273 | + try: |
| 1274 | + with support.infinite_recursion(200): |
| 1275 | + tree2 = copy.deepcopy(tree) |
| 1276 | + finally: |
| 1277 | + # Singletons like ast.Load() are shared; make sure we don't |
| 1278 | + # leave them mutated after this test. |
| 1279 | + for node in ast.walk(tree): |
| 1280 | + if hasattr(node, "parent"): |
| 1281 | + del node.parent |
| 1282 | + |
| 1283 | + for node in ast.walk(tree2): |
| 1284 | + for child in ast.iter_child_nodes(node): |
| 1285 | + if hasattr(child, "parent") and not isinstance(child, ( |
| 1286 | + ast.expr_context, ast.boolop, ast.unaryop, ast.cmpop, ast.operator, |
| 1287 | + )): |
| 1288 | + self.assertEqual(to_tuple(child.parent), to_tuple(node)) |
| 1289 | + |
| 1290 | + |
1225 | 1291 | class ASTHelpers_Test(unittest.TestCase): |
1226 | 1292 | maxDiff = None |
1227 | 1293 |
|
|
0 commit comments