(root)/
Python-3.11.7/
Lib/
test/
test_unparse.py
       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()