1"""Tests for the unparse.py script in the Tools/parser directory."""
2
3import unittest
4import test.support
5import pathlib
6import random
7import tokenize
8import ast
9
10
11def 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
18for_else = """\
19def f():
20    for x in range(10):
21        break
22    else:
23        y = 2
24    z = 3
25"""
26
27while_else = """\
28def g():
29    while True:
30        break
31    else:
32        y = 2
33    z = 3
34"""
35
36relative_import = """\
37from . import fred
38from .. import barney
39from .australia import shrimp as prawns
40"""
41
42nonlocal_ex = """\
43def 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 ...'
54raise_from = """\
55try:
56    1 / 0
57except ZeroDivisionError as e:
58    raise ArithmeticError from e
59"""
60
61class_decorator = """\
62@f1(arg)
63@f2
64class Foo: pass
65"""
66
67elif1 = """\
68if cond1:
69    suite1
70elif cond2:
71    suite2
72else:
73    suite3
74"""
75
76elif2 = """\
77if cond1:
78    suite1
79elif cond2:
80    suite2
81"""
82
83try_except_finally = """\
84try:
85    suite1
86except ex1:
87    suite2
88except ex2:
89    suite3
90else:
91    suite4
92finally:
93    suite5
94"""
95
96try_except_star_finally = """\
97try:
98    suite1
99except* ex1:
100    suite2
101except* ex2:
102    suite3
103else:
104    suite4
105finally:
106    suite5
107"""
108
109with_simple = """\
110with f():
111    suite1
112"""
113
114with_as = """\
115with f() as x:
116    suite1
117"""
118
119with_two_items = """\
120with f() as x, g() as y:
121    suite1
122"""
123
124docstring_prefixes = (
125    "",
126    "class foo:\n    ",
127    "def foo():\n    ",
128    "async def foo():\n    ",
129)
130
131class ASTTestCase(unittest.TestCase):
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
197class UnparseTestCase(ASTTestCase):
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
497class CosmeticTestCase(ASTTestCase):
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
666
667class DirectoryTestCase(ASTTestCase):
668    """Test roundtrip behaviour on all files in Lib and Lib/test."""
669
670    lib_dir = pathlib.Path(__file__).parent / ".."
671    test_directories = (lib_dir, lib_dir / "test")
672    run_always_files = {"test_grammar.py", "test_syntax.py", "test_compile.py",
673                        "test_ast.py", "test_asdl_parser.py", "test_fstring.py",
674                        "test_patma.py"}
675
676    _files_to_test = None
677
678    @classmethod
679    def files_to_test(cls):
680
681        if cls._files_to_test is not None:
682            return cls._files_to_test
683
684        items = [
685            item.resolve()
686            for directory in cls.test_directories
687            for item in directory.glob("*.py")
688            if not item.name.startswith("bad")
689        ]
690
691        # Test limited subset of files unless the 'cpu' resource is specified.
692        if not test.support.is_resource_enabled("cpu"):
693
694            tests_to_run_always = {item for item in items if
695                                   item.name in cls.run_always_files}
696
697            items = set(random.sample(items, 10))
698
699            # Make sure that at least tests that heavily use grammar features are
700            # always considered in order to reduce the chance of missing something.
701            items = list(items | tests_to_run_always)
702
703        # bpo-31174: Store the names sample to always test the same files.
704        # It prevents false alarms when hunting reference leaks.
705        cls._files_to_test = items
706
707        return items
708
709    def test_files(self):
710        for item in self.files_to_test():
711            if test.support.verbose:
712                print(f"Testing {item.absolute()}")
713
714            with self.subTest(filename=item):
715                source = read_pyfile(item)
716                self.check_ast_roundtrip(source)
717
718
719if __name__ == "__main__":
720    unittest.main()
721