test_unparse.py 24 KB

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