1 """Tests for the unparse.py script in the Tools/parser directory."""
2
3 import unittest
4 import test.support
5 import pathlib
6 import random
7 import tokenize
8 import ast
9
10
11 def read_pyfile(filename):
12 """Read and return the contents of a Python source file (as a
13 string), taking into account the file encoding."""
14 with tokenize.open(filename) as stream:
15 return stream.read()
16
17
18 for_else = """\
19 def f():
20 for x in range(10):
21 break
22 else:
23 y = 2
24 z = 3
25 """
26
27 while_else = """\
28 def g():
29 while True:
30 break
31 else:
32 y = 2
33 z = 3
34 """
35
36 relative_import = """\
37 from . import fred
38 from .. import barney
39 from .australia import shrimp as prawns
40 """
41
42 nonlocal_ex = """\
43 def f():
44 x = 1
45 def g():
46 nonlocal x
47 x = 2
48 y = 7
49 def h():
50 nonlocal x, y
51 """
52
53 # also acts as test for 'except ... as ...'
54 raise_from = """\
55 try:
56 1 / 0
57 except ZeroDivisionError as e:
58 raise ArithmeticError from e
59 """
60
61 class_decorator = """\
62 @f1(arg)
63 @f2
64 class Foo: pass
65 """
66
67 elif1 = """\
68 if cond1:
69 suite1
70 elif cond2:
71 suite2
72 else:
73 suite3
74 """
75
76 elif2 = """\
77 if cond1:
78 suite1
79 elif cond2:
80 suite2
81 """
82
83 try_except_finally = """\
84 try:
85 suite1
86 except ex1:
87 suite2
88 except ex2:
89 suite3
90 else:
91 suite4
92 finally:
93 suite5
94 """
95
96 try_except_star_finally = """\
97 try:
98 suite1
99 except* ex1:
100 suite2
101 except* ex2:
102 suite3
103 else:
104 suite4
105 finally:
106 suite5
107 """
108
109 with_simple = """\
110 with f():
111 suite1
112 """
113
114 with_as = """\
115 with f() as x:
116 suite1
117 """
118
119 with_two_items = """\
120 with f() as x, g() as y:
121 suite1
122 """
123
124 docstring_prefixes = (
125 "",
126 "class foo:\n ",
127 "def foo():\n ",
128 "async def foo():\n ",
129 )
130
131 class ESC[4;38;5;81mASTTestCase(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
132 def assertASTEqual(self, ast1, ast2):
133 # Ensure the comparisons start at an AST node
134 self.assertIsInstance(ast1, ast.AST)
135 self.assertIsInstance(ast2, ast.AST)
136
137 # An AST comparison routine modeled after ast.dump(), but
138 # instead of string building, it traverses the two trees
139 # in lock-step.
140 def traverse_compare(a, b, missing=object()):
141 if type(a) is not type(b):
142 self.fail(f"{type(a)!r} is not {type(b)!r}")
143 if isinstance(a, ast.AST):
144 for field in a._fields:
145 value1 = getattr(a, field, missing)
146 value2 = getattr(b, field, missing)
147 # Singletons are equal by definition, so further
148 # testing can be skipped.
149 if value1 is not value2:
150 traverse_compare(value1, value2)
151 elif isinstance(a, list):
152 try:
153 for node1, node2 in zip(a, b, strict=True):
154 traverse_compare(node1, node2)
155 except ValueError:
156 # Attempt a "pretty" error ala assertSequenceEqual()
157 len1 = len(a)
158 len2 = len(b)
159 if len1 > len2:
160 what = "First"
161 diff = len1 - len2
162 else:
163 what = "Second"
164 diff = len2 - len1
165 msg = f"{what} list contains {diff} additional elements."
166 raise self.failureException(msg) from None
167 elif a != b:
168 self.fail(f"{a!r} != {b!r}")
169 traverse_compare(ast1, ast2)
170
171 def check_ast_roundtrip(self, code1, **kwargs):
172 with self.subTest(code1=code1, ast_parse_kwargs=kwargs):
173 ast1 = ast.parse(code1, **kwargs)
174 code2 = ast.unparse(ast1)
175 ast2 = ast.parse(code2, **kwargs)
176 self.assertASTEqual(ast1, ast2)
177
178 def check_invalid(self, node, raises=ValueError):
179 with self.subTest(node=node):
180 self.assertRaises(raises, ast.unparse, node)
181
182 def get_source(self, code1, code2=None):
183 code2 = code2 or code1
184 code1 = ast.unparse(ast.parse(code1))
185 return code1, code2
186
187 def check_src_roundtrip(self, code1, code2=None):
188 code1, code2 = self.get_source(code1, code2)
189 with self.subTest(code1=code1, code2=code2):
190 self.assertEqual(code2, code1)
191
192 def check_src_dont_roundtrip(self, code1, code2=None):
193 code1, code2 = self.get_source(code1, code2)
194 with self.subTest(code1=code1, code2=code2):
195 self.assertNotEqual(code2, code1)
196
197 class ESC[4;38;5;81mUnparseTestCase(ESC[4;38;5;149mASTTestCase):
198 # Tests for specific bugs found in earlier versions of unparse
199
200 def test_fstrings(self):
201 self.check_ast_roundtrip("f'a'")
202 self.check_ast_roundtrip("f'{{}}'")
203 self.check_ast_roundtrip("f'{{5}}'")
204 self.check_ast_roundtrip("f'{{5}}5'")
205 self.check_ast_roundtrip("f'X{{}}X'")
206 self.check_ast_roundtrip("f'{a}'")
207 self.check_ast_roundtrip("f'{ {1:2}}'")
208 self.check_ast_roundtrip("f'a{a}a'")
209 self.check_ast_roundtrip("f'a{a}{a}a'")
210 self.check_ast_roundtrip("f'a{a}a{a}a'")
211 self.check_ast_roundtrip("f'{a!r}x{a!s}12{{}}{a!a}'")
212 self.check_ast_roundtrip("f'{a:10}'")
213 self.check_ast_roundtrip("f'{a:100_000{10}}'")
214 self.check_ast_roundtrip("f'{a!r:10}'")
215 self.check_ast_roundtrip("f'{a:a{b}10}'")
216 self.check_ast_roundtrip(
217 "f'a{b}{c!s}{d!r}{e!a}{f:a}{g:a{b}}{h!s:a}"
218 "{j!s:{a}b}{k!s:a{b}c}{l!a:{b}c{d}}{x+y=}'"
219 )
220
221 def test_fstrings_special_chars(self):
222 # See issue 25180
223 self.check_ast_roundtrip(r"""f'{f"{0}"*3}'""")
224 self.check_ast_roundtrip(r"""f'{f"{y}"*3}'""")
225 self.check_ast_roundtrip("""f''""")
226 self.check_ast_roundtrip('''f"""'end' "quote\\""""''')
227
228 def test_fstrings_complicated(self):
229 # See issue 28002
230 self.check_ast_roundtrip("""f'''{"'"}'''""")
231 self.check_ast_roundtrip('''f\'\'\'-{f"""*{f"+{f'.{x}.'}+"}*"""}-\'\'\'''')
232 self.check_ast_roundtrip('''f\'\'\'-{f"""*{f"+{f'.{x}.'}+"}*"""}-'single quote\\'\'\'\'''')
233 self.check_ast_roundtrip('f"""{\'\'\'\n\'\'\'}"""')
234 self.check_ast_roundtrip('f"""{g(\'\'\'\n\'\'\')}"""')
235 self.check_ast_roundtrip('''f"a\\r\\nb"''')
236 self.check_ast_roundtrip('''f"\\u2028{'x'}"''')
237
238 def test_strings(self):
239 self.check_ast_roundtrip("u'foo'")
240 self.check_ast_roundtrip("r'foo'")
241 self.check_ast_roundtrip("b'foo'")
242
243 def test_del_statement(self):
244 self.check_ast_roundtrip("del x, y, z")
245
246 def test_shifts(self):
247 self.check_ast_roundtrip("45 << 2")
248 self.check_ast_roundtrip("13 >> 7")
249
250 def test_for_else(self):
251 self.check_ast_roundtrip(for_else)
252
253 def test_while_else(self):
254 self.check_ast_roundtrip(while_else)
255
256 def test_unary_parens(self):
257 self.check_ast_roundtrip("(-1)**7")
258 self.check_ast_roundtrip("(-1.)**8")
259 self.check_ast_roundtrip("(-1j)**6")
260 self.check_ast_roundtrip("not True or False")
261 self.check_ast_roundtrip("True or not False")
262
263 def test_integer_parens(self):
264 self.check_ast_roundtrip("3 .__abs__()")
265
266 def test_huge_float(self):
267 self.check_ast_roundtrip("1e1000")
268 self.check_ast_roundtrip("-1e1000")
269 self.check_ast_roundtrip("1e1000j")
270 self.check_ast_roundtrip("-1e1000j")
271
272 def test_nan(self):
273 self.assertASTEqual(
274 ast.parse(ast.unparse(ast.Constant(value=float('nan')))),
275 ast.parse('1e1000 - 1e1000')
276 )
277
278 def test_min_int(self):
279 self.check_ast_roundtrip(str(-(2 ** 31)))
280 self.check_ast_roundtrip(str(-(2 ** 63)))
281
282 def test_imaginary_literals(self):
283 self.check_ast_roundtrip("7j")
284 self.check_ast_roundtrip("-7j")
285 self.check_ast_roundtrip("0j")
286 self.check_ast_roundtrip("-0j")
287
288 def test_lambda_parentheses(self):
289 self.check_ast_roundtrip("(lambda: int)()")
290
291 def test_chained_comparisons(self):
292 self.check_ast_roundtrip("1 < 4 <= 5")
293 self.check_ast_roundtrip("a is b is c is not d")
294
295 def test_function_arguments(self):
296 self.check_ast_roundtrip("def f(): pass")
297 self.check_ast_roundtrip("def f(a): pass")
298 self.check_ast_roundtrip("def f(b = 2): pass")
299 self.check_ast_roundtrip("def f(a, b): pass")
300 self.check_ast_roundtrip("def f(a, b = 2): pass")
301 self.check_ast_roundtrip("def f(a = 5, b = 2): pass")
302 self.check_ast_roundtrip("def f(*, a = 1, b = 2): pass")
303 self.check_ast_roundtrip("def f(*, a = 1, b): pass")
304 self.check_ast_roundtrip("def f(*, a, b = 2): pass")
305 self.check_ast_roundtrip("def f(a, b = None, *, c, **kwds): pass")
306 self.check_ast_roundtrip("def f(a=2, *args, c=5, d, **kwds): pass")
307 self.check_ast_roundtrip("def f(*args, **kwargs): pass")
308
309 def test_relative_import(self):
310 self.check_ast_roundtrip(relative_import)
311
312 def test_nonlocal(self):
313 self.check_ast_roundtrip(nonlocal_ex)
314
315 def test_raise_from(self):
316 self.check_ast_roundtrip(raise_from)
317
318 def test_bytes(self):
319 self.check_ast_roundtrip("b'123'")
320
321 def test_annotations(self):
322 self.check_ast_roundtrip("def f(a : int): pass")
323 self.check_ast_roundtrip("def f(a: int = 5): pass")
324 self.check_ast_roundtrip("def f(*args: [int]): pass")
325 self.check_ast_roundtrip("def f(**kwargs: dict): pass")
326 self.check_ast_roundtrip("def f() -> None: pass")
327
328 def test_set_literal(self):
329 self.check_ast_roundtrip("{'a', 'b', 'c'}")
330
331 def test_empty_set(self):
332 self.assertASTEqual(
333 ast.parse(ast.unparse(ast.Set(elts=[]))),
334 ast.parse('{*()}')
335 )
336
337 def test_set_comprehension(self):
338 self.check_ast_roundtrip("{x for x in range(5)}")
339
340 def test_dict_comprehension(self):
341 self.check_ast_roundtrip("{x: x*x for x in range(10)}")
342
343 def test_class_decorators(self):
344 self.check_ast_roundtrip(class_decorator)
345
346 def test_class_definition(self):
347 self.check_ast_roundtrip("class A(metaclass=type, *[], **{}): pass")
348
349 def test_elifs(self):
350 self.check_ast_roundtrip(elif1)
351 self.check_ast_roundtrip(elif2)
352
353 def test_try_except_finally(self):
354 self.check_ast_roundtrip(try_except_finally)
355
356 def test_try_except_star_finally(self):
357 self.check_ast_roundtrip(try_except_star_finally)
358
359 def test_starred_assignment(self):
360 self.check_ast_roundtrip("a, *b, c = seq")
361 self.check_ast_roundtrip("a, (*b, c) = seq")
362 self.check_ast_roundtrip("a, *b[0], c = seq")
363 self.check_ast_roundtrip("a, *(b, c) = seq")
364
365 def test_with_simple(self):
366 self.check_ast_roundtrip(with_simple)
367
368 def test_with_as(self):
369 self.check_ast_roundtrip(with_as)
370
371 def test_with_two_items(self):
372 self.check_ast_roundtrip(with_two_items)
373
374 def test_dict_unpacking_in_dict(self):
375 # See issue 26489
376 self.check_ast_roundtrip(r"""{**{'y': 2}, 'x': 1}""")
377 self.check_ast_roundtrip(r"""{**{'y': 2}, **{'x': 1}}""")
378
379 def test_slices(self):
380 self.check_ast_roundtrip("a[i]")
381 self.check_ast_roundtrip("a[i,]")
382 self.check_ast_roundtrip("a[i, j]")
383 # The AST for these next two both look like `a[(*a,)]`
384 self.check_ast_roundtrip("a[(*a,)]")
385 self.check_ast_roundtrip("a[*a]")
386 self.check_ast_roundtrip("a[b, *a]")
387 self.check_ast_roundtrip("a[*a, c]")
388 self.check_ast_roundtrip("a[b, *a, c]")
389 self.check_ast_roundtrip("a[*a, *a]")
390 self.check_ast_roundtrip("a[b, *a, *a]")
391 self.check_ast_roundtrip("a[*a, b, *a]")
392 self.check_ast_roundtrip("a[*a, *a, b]")
393 self.check_ast_roundtrip("a[b, *a, *a, c]")
394 self.check_ast_roundtrip("a[(a:=b)]")
395 self.check_ast_roundtrip("a[(a:=b,c)]")
396 self.check_ast_roundtrip("a[()]")
397 self.check_ast_roundtrip("a[i:j]")
398 self.check_ast_roundtrip("a[:j]")
399 self.check_ast_roundtrip("a[i:]")
400 self.check_ast_roundtrip("a[i:j:k]")
401 self.check_ast_roundtrip("a[:j:k]")
402 self.check_ast_roundtrip("a[i::k]")
403 self.check_ast_roundtrip("a[i:j,]")
404 self.check_ast_roundtrip("a[i:j, k]")
405
406 def test_invalid_raise(self):
407 self.check_invalid(ast.Raise(exc=None, cause=ast.Name(id="X")))
408
409 def test_invalid_fstring_value(self):
410 self.check_invalid(
411 ast.JoinedStr(
412 values=[
413 ast.Name(id="test"),
414 ast.Constant(value="test")
415 ]
416 )
417 )
418
419 def test_invalid_fstring_backslash(self):
420 self.check_invalid(ast.FormattedValue(value=ast.Constant(value="\\\\")))
421
422 def test_invalid_yield_from(self):
423 self.check_invalid(ast.YieldFrom(value=None))
424
425 def test_import_from_level_none(self):
426 tree = ast.ImportFrom(module='mod', names=[ast.alias(name='x')])
427 self.assertEqual(ast.unparse(tree), "from mod import x")
428 tree = ast.ImportFrom(module='mod', names=[ast.alias(name='x')], level=None)
429 self.assertEqual(ast.unparse(tree), "from mod import x")
430
431 def test_docstrings(self):
432 docstrings = (
433 'this ends with double quote"',
434 'this includes a """triple quote"""',
435 '\r',
436 '\\r',
437 '\t',
438 '\\t',
439 '\n',
440 '\\n',
441 '\r\\r\t\\t\n\\n',
442 '""">>> content = \"\"\"blabla\"\"\" <<<"""',
443 r'foo\n\x00',
444 "' \\'\\'\\'\"\"\" \"\"\\'\\' \\'",
445 '🐍⛎𩸽üéş^\\\\X\\\\BB\N{LONG RIGHTWARDS SQUIGGLE ARROW}'
446 )
447 for docstring in docstrings:
448 # check as Module docstrings for easy testing
449 self.check_ast_roundtrip(f"'''{docstring}'''")
450
451 def test_constant_tuples(self):
452 self.check_src_roundtrip(ast.Constant(value=(1,), kind=None), "(1,)")
453 self.check_src_roundtrip(
454 ast.Constant(value=(1, 2, 3), kind=None), "(1, 2, 3)"
455 )
456
457 def test_function_type(self):
458 for function_type in (
459 "() -> int",
460 "(int, int) -> int",
461 "(Callable[complex], More[Complex(call.to_typevar())]) -> None"
462 ):
463 self.check_ast_roundtrip(function_type, mode="func_type")
464
465 def test_type_comments(self):
466 for statement in (
467 "a = 5 # type:",
468 "a = 5 # type: int",
469 "a = 5 # type: int and more",
470 "def x(): # type: () -> None\n\tpass",
471 "def x(y): # type: (int) -> None and more\n\tpass",
472 "async def x(): # type: () -> None\n\tpass",
473 "async def x(y): # type: (int) -> None and more\n\tpass",
474 "for x in y: # type: int\n\tpass",
475 "async for x in y: # type: int\n\tpass",
476 "with x(): # type: int\n\tpass",
477 "async with x(): # type: int\n\tpass"
478 ):
479 self.check_ast_roundtrip(statement, type_comments=True)
480
481 def test_type_ignore(self):
482 for statement in (
483 "a = 5 # type: ignore",
484 "a = 5 # type: ignore and more",
485 "def x(): # type: ignore\n\tpass",
486 "def x(y): # type: ignore and more\n\tpass",
487 "async def x(): # type: ignore\n\tpass",
488 "async def x(y): # type: ignore and more\n\tpass",
489 "for x in y: # type: ignore\n\tpass",
490 "async for x in y: # type: ignore\n\tpass",
491 "with x(): # type: ignore\n\tpass",
492 "async with x(): # type: ignore\n\tpass"
493 ):
494 self.check_ast_roundtrip(statement, type_comments=True)
495
496
497 class ESC[4;38;5;81mCosmeticTestCase(ESC[4;38;5;149mASTTestCase):
498 """Test if there are cosmetic issues caused by unnecessary additions"""
499
500 def test_simple_expressions_parens(self):
501 self.check_src_roundtrip("(a := b)")
502 self.check_src_roundtrip("await x")
503 self.check_src_roundtrip("x if x else y")
504 self.check_src_roundtrip("lambda x: x")
505 self.check_src_roundtrip("1 + 1")
506 self.check_src_roundtrip("1 + 2 / 3")
507 self.check_src_roundtrip("(1 + 2) / 3")
508 self.check_src_roundtrip("(1 + 2) * 3 + 4 * (5 + 2)")
509 self.check_src_roundtrip("(1 + 2) * 3 + 4 * (5 + 2) ** 2")
510 self.check_src_roundtrip("~x")
511 self.check_src_roundtrip("x and y")
512 self.check_src_roundtrip("x and y and z")
513 self.check_src_roundtrip("x and (y and x)")
514 self.check_src_roundtrip("(x and y) and z")
515 self.check_src_roundtrip("(x ** y) ** z ** q")
516 self.check_src_roundtrip("x >> y")
517 self.check_src_roundtrip("x << y")
518 self.check_src_roundtrip("x >> y and x >> z")
519 self.check_src_roundtrip("x + y - z * q ^ t ** k")
520 self.check_src_roundtrip("P * V if P and V else n * R * T")
521 self.check_src_roundtrip("lambda P, V, n: P * V == n * R * T")
522 self.check_src_roundtrip("flag & (other | foo)")
523 self.check_src_roundtrip("not x == y")
524 self.check_src_roundtrip("x == (not y)")
525 self.check_src_roundtrip("yield x")
526 self.check_src_roundtrip("yield from x")
527 self.check_src_roundtrip("call((yield x))")
528 self.check_src_roundtrip("return x + (yield x)")
529
530 def test_class_bases_and_keywords(self):
531 self.check_src_roundtrip("class X:\n pass")
532 self.check_src_roundtrip("class X(A):\n pass")
533 self.check_src_roundtrip("class X(A, B, C, D):\n pass")
534 self.check_src_roundtrip("class X(x=y):\n pass")
535 self.check_src_roundtrip("class X(metaclass=z):\n pass")
536 self.check_src_roundtrip("class X(x=y, z=d):\n pass")
537 self.check_src_roundtrip("class X(A, x=y):\n pass")
538 self.check_src_roundtrip("class X(A, **kw):\n pass")
539 self.check_src_roundtrip("class X(*args):\n pass")
540 self.check_src_roundtrip("class X(*args, **kwargs):\n pass")
541
542 def test_fstrings(self):
543 self.check_src_roundtrip('''f\'\'\'-{f"""*{f"+{f'.{x}.'}+"}*"""}-\'\'\'''')
544 self.check_src_roundtrip('''f"\\u2028{'x'}"''')
545 self.check_src_roundtrip(r"f'{x}\n'")
546 self.check_src_roundtrip('''f''\'{"""\n"""}\\n''\'''')
547 self.check_src_roundtrip('''f''\'{f"""{x}\n"""}\\n''\'''')
548
549 def test_docstrings(self):
550 docstrings = (
551 '"""simple doc string"""',
552 '''"""A more complex one
553 with some newlines"""''',
554 '''"""Foo bar baz
555
556 empty newline"""''',
557 '"""With some \t"""',
558 '"""Foo "bar" baz """',
559 '"""\\r"""',
560 '""""""',
561 '"""\'\'\'"""',
562 '"""\'\'\'\'\'\'"""',
563 '"""🐍⛎𩸽üéş^\\\\X\\\\BB⟿"""',
564 '"""end in single \'quote\'"""',
565 "'''end in double \"quote\"'''",
566 '"""almost end in double "quote"."""',
567 )
568
569 for prefix in docstring_prefixes:
570 for docstring in docstrings:
571 self.check_src_roundtrip(f"{prefix}{docstring}")
572
573 def test_docstrings_negative_cases(self):
574 # Test some cases that involve strings in the children of the
575 # first node but aren't docstrings to make sure we don't have
576 # False positives.
577 docstrings_negative = (
578 'a = """false"""',
579 '"""false""" + """unless its optimized"""',
580 '1 + 1\n"""false"""',
581 'f"""no, top level but f-fstring"""'
582 )
583 for prefix in docstring_prefixes:
584 for negative in docstrings_negative:
585 # this cases should be result with single quote
586 # rather then triple quoted docstring
587 src = f"{prefix}{negative}"
588 self.check_ast_roundtrip(src)
589 self.check_src_dont_roundtrip(src)
590
591 def test_unary_op_factor(self):
592 for prefix in ("+", "-", "~"):
593 self.check_src_roundtrip(f"{prefix}1")
594 for prefix in ("not",):
595 self.check_src_roundtrip(f"{prefix} 1")
596
597 def test_slices(self):
598 self.check_src_roundtrip("a[()]")
599 self.check_src_roundtrip("a[1]")
600 self.check_src_roundtrip("a[1, 2]")
601 # Note that `a[*a]`, `a[*a,]`, and `a[(*a,)]` all evaluate to the same
602 # thing at runtime and have the same AST, but only `a[*a,]` passes
603 # this test, because that's what `ast.unparse` produces.
604 self.check_src_roundtrip("a[*a,]")
605 self.check_src_roundtrip("a[1, *a]")
606 self.check_src_roundtrip("a[*a, 2]")
607 self.check_src_roundtrip("a[1, *a, 2]")
608 self.check_src_roundtrip("a[*a, *a]")
609 self.check_src_roundtrip("a[1, *a, *a]")
610 self.check_src_roundtrip("a[*a, 1, *a]")
611 self.check_src_roundtrip("a[*a, *a, 1]")
612 self.check_src_roundtrip("a[1, *a, *a, 2]")
613 self.check_src_roundtrip("a[1:2, *a]")
614 self.check_src_roundtrip("a[*a, 1:2]")
615
616 def test_lambda_parameters(self):
617 self.check_src_roundtrip("lambda: something")
618 self.check_src_roundtrip("four = lambda: 2 + 2")
619 self.check_src_roundtrip("lambda x: x * 2")
620 self.check_src_roundtrip("square = lambda n: n ** 2")
621 self.check_src_roundtrip("lambda x, y: x + y")
622 self.check_src_roundtrip("add = lambda x, y: x + y")
623 self.check_src_roundtrip("lambda x, y, /, z, q, *, u: None")
624 self.check_src_roundtrip("lambda x, *y, **z: None")
625
626 def test_star_expr_assign_target(self):
627 for source_type, source in [
628 ("single assignment", "{target} = foo"),
629 ("multiple assignment", "{target} = {target} = bar"),
630 ("for loop", "for {target} in foo:\n pass"),
631 ("async for loop", "async for {target} in foo:\n pass")
632 ]:
633 for target in [
634 "a",
635 "a,",
636 "a, b",
637 "a, *b, c",
638 "a, (b, c), d",
639 "a, (b, c, d), *e",
640 "a, (b, *c, d), e",
641 "a, (b, *c, (d, e), f), g",
642 "[a]",
643 "[a, b]",
644 "[a, *b, c]",
645 "[a, [b, c], d]",
646 "[a, [b, c, d], *e]",
647 "[a, [b, *c, d], e]",
648 "[a, [b, *c, [d, e], f], g]",
649 "a, [b, c], d",
650 "[a, b, (c, d), (e, f)]",
651 "a, b, [*c], d, e"
652 ]:
653 with self.subTest(source_type=source_type, target=target):
654 self.check_src_roundtrip(source.format(target=target))
655
656 def test_star_expr_assign_target_multiple(self):
657 self.check_src_roundtrip("() = []")
658 self.check_src_roundtrip("[] = ()")
659 self.check_src_roundtrip("() = [a] = c, = [d] = e, f = () = g = h")
660 self.check_src_roundtrip("a = b = c = d")
661 self.check_src_roundtrip("a, b = c, d = e, f = g")
662 self.check_src_roundtrip("[a, b] = [c, d] = [e, f] = g")
663 self.check_src_roundtrip("a, b = [c, d] = e, f = g")
664
665 def test_multiquote_joined_string(self):
666 self.check_ast_roundtrip("f\"'''{1}\\\"\\\"\\\"\" ")
667 self.check_ast_roundtrip("""f"'''{1}""\\"" """)
668 self.check_ast_roundtrip("""f'""\"{1}''' """)
669 self.check_ast_roundtrip("""f'""\"{1}""\\"' """)
670
671
672 class ESC[4;38;5;81mDirectoryTestCase(ESC[4;38;5;149mASTTestCase):
673 """Test roundtrip behaviour on all files in Lib and Lib/test."""
674
675 lib_dir = pathlib.Path(__file__).parent / ".."
676 test_directories = (lib_dir, lib_dir / "test")
677 run_always_files = {"test_grammar.py", "test_syntax.py", "test_compile.py",
678 "test_ast.py", "test_asdl_parser.py", "test_fstring.py",
679 "test_patma.py"}
680
681 _files_to_test = None
682
683 @classmethod
684 def files_to_test(cls):
685
686 if cls._files_to_test is not None:
687 return cls._files_to_test
688
689 items = [
690 item.resolve()
691 for directory in cls.test_directories
692 for item in directory.glob("*.py")
693 if not item.name.startswith("bad")
694 ]
695
696 # Test limited subset of files unless the 'cpu' resource is specified.
697 if not test.support.is_resource_enabled("cpu"):
698
699 tests_to_run_always = {item for item in items if
700 item.name in cls.run_always_files}
701
702 items = set(random.sample(items, 10))
703
704 # Make sure that at least tests that heavily use grammar features are
705 # always considered in order to reduce the chance of missing something.
706 items = list(items | tests_to_run_always)
707
708 # bpo-31174: Store the names sample to always test the same files.
709 # It prevents false alarms when hunting reference leaks.
710 cls._files_to_test = items
711
712 return items
713
714 def test_files(self):
715 for item in self.files_to_test():
716 if test.support.verbose:
717 print(f"Testing {item.absolute()}")
718
719 with self.subTest(filename=item):
720 source = read_pyfile(item)
721 self.check_ast_roundtrip(source)
722
723
724 if __name__ == "__main__":
725 unittest.main()