python (3.12.0)

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