blob: 532aa3a63904141353d0924baf3a486a6080f206 [file] [log] [blame]
Zachary Ware2b0a6102014-07-16 14:26:09 -05001"""Tests for the unparse.py script in the Tools/parser directory."""
2
Mark Dickinsonae100052010-06-28 19:44:20 +00003import unittest
4import test.support
Pablo Galindo27fc3b62019-11-24 23:02:40 +00005import pathlib
Mark Dickinsonbe4fb692012-06-23 09:27:47 +01006import random
Mark Dickinsond751c2e2010-06-29 14:08:23 +00007import tokenize
Mark Dickinsonbe4fb692012-06-23 09:27:47 +01008import ast
Mark Dickinsonae100052010-06-28 19:44:20 +00009
Zachary Ware2b0a6102014-07-16 14:26:09 -050010
Mark Dickinsond751c2e2010-06-29 14:08:23 +000011def read_pyfile(filename):
12 """Read and return the contents of a Python source file (as a
13 string), taking into account the file encoding."""
Hakan Çelik6a5bf152020-04-16 13:11:55 +030014 with tokenize.open(filename) as stream:
15 return stream.read()
Mark Dickinsond751c2e2010-06-29 14:08:23 +000016
Pablo Galindo27fc3b62019-11-24 23:02:40 +000017
Mark Dickinsonfa2e4e92010-06-28 21:14:17 +000018for_else = """\
Mark Dickinsonae100052010-06-28 19:44:20 +000019def f():
20 for x in range(10):
21 break
22 else:
23 y = 2
24 z = 3
25"""
26
Mark Dickinsonfa2e4e92010-06-28 21:14:17 +000027while_else = """\
Mark Dickinsonae100052010-06-28 19:44:20 +000028def g():
29 while True:
30 break
31 else:
32 y = 2
33 z = 3
34"""
35
Mark Dickinsonfa2e4e92010-06-28 21:14:17 +000036relative_import = """\
37from . import fred
38from .. import barney
39from .australia import shrimp as prawns
40"""
41
42nonlocal_ex = """\
43def f():
44 x = 1
45 def g():
46 nonlocal x
47 x = 2
48 y = 7
49 def h():
50 nonlocal x, y
51"""
52
53# also acts as test for 'except ... as ...'
54raise_from = """\
55try:
56 1 / 0
57except ZeroDivisionError as e:
58 raise ArithmeticError from e
59"""
60
61class_decorator = """\
62@f1(arg)
63@f2
64class Foo: pass
65"""
66
Mark Dickinson8d6d7602010-06-30 08:32:11 +000067elif1 = """\
68if cond1:
69 suite1
70elif cond2:
71 suite2
72else:
73 suite3
74"""
75
76elif2 = """\
77if cond1:
78 suite1
79elif cond2:
80 suite2
81"""
82
Mark Dickinson81ad8cc2010-06-30 08:46:53 +000083try_except_finally = """\
84try:
85 suite1
86except ex1:
87 suite2
88except ex2:
89 suite3
90else:
91 suite4
92finally:
93 suite5
94"""
Mark Dickinson8d6d7602010-06-30 08:32:11 +000095
Mark Dickinsonfe8440a2012-05-06 17:35:19 +010096with_simple = """\
97with f():
98 suite1
99"""
100
101with_as = """\
102with f() as x:
103 suite1
104"""
105
106with_two_items = """\
107with f() as x, g() as y:
108 suite1
109"""
110
Batuhan Taskayadff92bb2020-05-17 02:04:12 +0300111docstring_prefixes = (
Batuhan Taşkaya89aa4692020-03-02 21:59:01 +0300112 "",
Batuhan Taskaya25160cd2020-05-17 00:53:25 +0300113 "class foo:\n ",
Batuhan Taşkaya89aa4692020-03-02 21:59:01 +0300114 "def foo():\n ",
115 "async def foo():\n ",
Batuhan Taskayadff92bb2020-05-17 02:04:12 +0300116)
Pablo Galindo27fc3b62019-11-24 23:02:40 +0000117
Mark Dickinsond751c2e2010-06-29 14:08:23 +0000118class ASTTestCase(unittest.TestCase):
119 def assertASTEqual(self, ast1, ast2):
120 self.assertEqual(ast.dump(ast1), ast.dump(ast2))
Mark Dickinsonae100052010-06-28 19:44:20 +0000121
Batuhan Taşkaya5b66ec12020-03-15 22:56:57 +0300122 def check_ast_roundtrip(self, code1, **kwargs):
Pablo Galindo6341fc72020-05-17 03:53:57 +0100123 with self.subTest(code1=code1, ast_parse_kwargs=kwargs):
124 ast1 = ast.parse(code1, **kwargs)
125 code2 = ast.unparse(ast1)
126 ast2 = ast.parse(code2, **kwargs)
127 self.assertASTEqual(ast1, ast2)
Mark Dickinsond751c2e2010-06-29 14:08:23 +0000128
Pablo Galindo27fc3b62019-11-24 23:02:40 +0000129 def check_invalid(self, node, raises=ValueError):
Pablo Galindo6341fc72020-05-17 03:53:57 +0100130 with self.subTest(node=node):
131 self.assertRaises(raises, ast.unparse, node)
Pablo Galindo27fc3b62019-11-24 23:02:40 +0000132
Batuhan Taskaya493bf1c2020-05-03 20:11:51 +0300133 def get_source(self, code1, code2=None):
Batuhan Taşkaya397b96f2020-03-01 23:12:17 +0300134 code2 = code2 or code1
135 code1 = ast.unparse(ast.parse(code1))
Batuhan Taşkaya89aa4692020-03-02 21:59:01 +0300136 return code1, code2
137
Batuhan Taskaya493bf1c2020-05-03 20:11:51 +0300138 def check_src_roundtrip(self, code1, code2=None):
139 code1, code2 = self.get_source(code1, code2)
Pablo Galindo6341fc72020-05-17 03:53:57 +0100140 with self.subTest(code1=code1, code2=code2):
141 self.assertEqual(code2, code1)
Batuhan Taşkaya397b96f2020-03-01 23:12:17 +0300142
Batuhan Taskaya493bf1c2020-05-03 20:11:51 +0300143 def check_src_dont_roundtrip(self, code1, code2=None):
144 code1, code2 = self.get_source(code1, code2)
Pablo Galindo6341fc72020-05-17 03:53:57 +0100145 with self.subTest(code1=code1, code2=code2):
146 self.assertNotEqual(code2, code1)
Pablo Galindo27fc3b62019-11-24 23:02:40 +0000147
Mark Dickinsond751c2e2010-06-29 14:08:23 +0000148class UnparseTestCase(ASTTestCase):
149 # Tests for specific bugs found in earlier versions of unparse
Mark Dickinsonae100052010-06-28 19:44:20 +0000150
Eric V. Smith608adf92015-09-20 15:09:15 -0400151 def test_fstrings(self):
152 # See issue 25180
Batuhan Taşkaya89aa4692020-03-02 21:59:01 +0300153 self.check_ast_roundtrip(r"""f'{f"{0}"*3}'""")
154 self.check_ast_roundtrip(r"""f'{f"{y}"*3}'""")
Eric V. Smith608adf92015-09-20 15:09:15 -0400155
Chih-Hsuan Yenaaf47ca2019-05-27 01:08:20 +0800156 def test_strings(self):
Batuhan Taşkaya89aa4692020-03-02 21:59:01 +0300157 self.check_ast_roundtrip("u'foo'")
158 self.check_ast_roundtrip("r'foo'")
159 self.check_ast_roundtrip("b'foo'")
Chih-Hsuan Yenaaf47ca2019-05-27 01:08:20 +0800160
Mark Dickinsonae100052010-06-28 19:44:20 +0000161 def test_del_statement(self):
Batuhan Taşkaya89aa4692020-03-02 21:59:01 +0300162 self.check_ast_roundtrip("del x, y, z")
Mark Dickinsonae100052010-06-28 19:44:20 +0000163
164 def test_shifts(self):
Batuhan Taşkaya89aa4692020-03-02 21:59:01 +0300165 self.check_ast_roundtrip("45 << 2")
166 self.check_ast_roundtrip("13 >> 7")
Mark Dickinsonae100052010-06-28 19:44:20 +0000167
168 def test_for_else(self):
Batuhan Taşkaya89aa4692020-03-02 21:59:01 +0300169 self.check_ast_roundtrip(for_else)
Mark Dickinsonae100052010-06-28 19:44:20 +0000170
171 def test_while_else(self):
Batuhan Taşkaya89aa4692020-03-02 21:59:01 +0300172 self.check_ast_roundtrip(while_else)
Mark Dickinsonae100052010-06-28 19:44:20 +0000173
174 def test_unary_parens(self):
Batuhan Taşkaya89aa4692020-03-02 21:59:01 +0300175 self.check_ast_roundtrip("(-1)**7")
176 self.check_ast_roundtrip("(-1.)**8")
177 self.check_ast_roundtrip("(-1j)**6")
178 self.check_ast_roundtrip("not True or False")
179 self.check_ast_roundtrip("True or not False")
Mark Dickinsonae100052010-06-28 19:44:20 +0000180
Mark Dickinson3eb02902010-06-29 08:52:36 +0000181 def test_integer_parens(self):
Batuhan Taşkaya89aa4692020-03-02 21:59:01 +0300182 self.check_ast_roundtrip("3 .__abs__()")
Mark Dickinson3eb02902010-06-29 08:52:36 +0000183
Mark Dickinson8042e282010-06-29 10:01:48 +0000184 def test_huge_float(self):
Batuhan Taşkaya89aa4692020-03-02 21:59:01 +0300185 self.check_ast_roundtrip("1e1000")
186 self.check_ast_roundtrip("-1e1000")
187 self.check_ast_roundtrip("1e1000j")
188 self.check_ast_roundtrip("-1e1000j")
Mark Dickinsoncba8c102010-06-30 11:45:53 +0000189
190 def test_min_int(self):
Batuhan Taşkaya89aa4692020-03-02 21:59:01 +0300191 self.check_ast_roundtrip(str(-(2 ** 31)))
192 self.check_ast_roundtrip(str(-(2 ** 63)))
Mark Dickinsoncba8c102010-06-30 11:45:53 +0000193
194 def test_imaginary_literals(self):
Batuhan Taşkaya89aa4692020-03-02 21:59:01 +0300195 self.check_ast_roundtrip("7j")
196 self.check_ast_roundtrip("-7j")
197 self.check_ast_roundtrip("0j")
198 self.check_ast_roundtrip("-0j")
Mark Dickinson8042e282010-06-29 10:01:48 +0000199
200 def test_lambda_parentheses(self):
Batuhan Taşkaya89aa4692020-03-02 21:59:01 +0300201 self.check_ast_roundtrip("(lambda: int)()")
Mark Dickinson8042e282010-06-29 10:01:48 +0000202
Mark Dickinsonf5451e52010-06-28 20:09:18 +0000203 def test_chained_comparisons(self):
Batuhan Taşkaya89aa4692020-03-02 21:59:01 +0300204 self.check_ast_roundtrip("1 < 4 <= 5")
205 self.check_ast_roundtrip("a is b is c is not d")
Mark Dickinsonf5451e52010-06-28 20:09:18 +0000206
Mark Dickinsonfa2e4e92010-06-28 21:14:17 +0000207 def test_function_arguments(self):
Batuhan Taşkaya89aa4692020-03-02 21:59:01 +0300208 self.check_ast_roundtrip("def f(): pass")
209 self.check_ast_roundtrip("def f(a): pass")
210 self.check_ast_roundtrip("def f(b = 2): pass")
211 self.check_ast_roundtrip("def f(a, b): pass")
212 self.check_ast_roundtrip("def f(a, b = 2): pass")
213 self.check_ast_roundtrip("def f(a = 5, b = 2): pass")
214 self.check_ast_roundtrip("def f(*, a = 1, b = 2): pass")
215 self.check_ast_roundtrip("def f(*, a = 1, b): pass")
216 self.check_ast_roundtrip("def f(*, a, b = 2): pass")
217 self.check_ast_roundtrip("def f(a, b = None, *, c, **kwds): pass")
218 self.check_ast_roundtrip("def f(a=2, *args, c=5, d, **kwds): pass")
219 self.check_ast_roundtrip("def f(*args, **kwargs): pass")
Mark Dickinsonfa2e4e92010-06-28 21:14:17 +0000220
221 def test_relative_import(self):
Batuhan Taşkaya89aa4692020-03-02 21:59:01 +0300222 self.check_ast_roundtrip(relative_import)
Mark Dickinsonfa2e4e92010-06-28 21:14:17 +0000223
224 def test_nonlocal(self):
Batuhan Taşkaya89aa4692020-03-02 21:59:01 +0300225 self.check_ast_roundtrip(nonlocal_ex)
Mark Dickinsonfa2e4e92010-06-28 21:14:17 +0000226
227 def test_raise_from(self):
Batuhan Taşkaya89aa4692020-03-02 21:59:01 +0300228 self.check_ast_roundtrip(raise_from)
Mark Dickinsonfa2e4e92010-06-28 21:14:17 +0000229
230 def test_bytes(self):
Batuhan Taşkaya89aa4692020-03-02 21:59:01 +0300231 self.check_ast_roundtrip("b'123'")
Mark Dickinsonfa2e4e92010-06-28 21:14:17 +0000232
233 def test_annotations(self):
Batuhan Taşkaya89aa4692020-03-02 21:59:01 +0300234 self.check_ast_roundtrip("def f(a : int): pass")
235 self.check_ast_roundtrip("def f(a: int = 5): pass")
236 self.check_ast_roundtrip("def f(*args: [int]): pass")
237 self.check_ast_roundtrip("def f(**kwargs: dict): pass")
238 self.check_ast_roundtrip("def f() -> None: pass")
Mark Dickinsonfa2e4e92010-06-28 21:14:17 +0000239
240 def test_set_literal(self):
Batuhan Taşkaya89aa4692020-03-02 21:59:01 +0300241 self.check_ast_roundtrip("{'a', 'b', 'c'}")
Mark Dickinsonfa2e4e92010-06-28 21:14:17 +0000242
243 def test_set_comprehension(self):
Batuhan Taşkaya89aa4692020-03-02 21:59:01 +0300244 self.check_ast_roundtrip("{x for x in range(5)}")
Mark Dickinsonfa2e4e92010-06-28 21:14:17 +0000245
246 def test_dict_comprehension(self):
Batuhan Taşkaya89aa4692020-03-02 21:59:01 +0300247 self.check_ast_roundtrip("{x: x*x for x in range(10)}")
Mark Dickinsonfa2e4e92010-06-28 21:14:17 +0000248
249 def test_class_decorators(self):
Batuhan Taşkaya89aa4692020-03-02 21:59:01 +0300250 self.check_ast_roundtrip(class_decorator)
Mark Dickinsonae100052010-06-28 19:44:20 +0000251
Mark Dickinson578aa562010-06-29 18:38:59 +0000252 def test_class_definition(self):
Batuhan Taşkaya89aa4692020-03-02 21:59:01 +0300253 self.check_ast_roundtrip("class A(metaclass=type, *[], **{}): pass")
Mark Dickinsond751c2e2010-06-29 14:08:23 +0000254
Mark Dickinson8d6d7602010-06-30 08:32:11 +0000255 def test_elifs(self):
Batuhan Taşkaya89aa4692020-03-02 21:59:01 +0300256 self.check_ast_roundtrip(elif1)
257 self.check_ast_roundtrip(elif2)
Mark Dickinson8d6d7602010-06-30 08:32:11 +0000258
Mark Dickinson81ad8cc2010-06-30 08:46:53 +0000259 def test_try_except_finally(self):
Batuhan Taşkaya89aa4692020-03-02 21:59:01 +0300260 self.check_ast_roundtrip(try_except_finally)
Mark Dickinson81ad8cc2010-06-30 08:46:53 +0000261
Mark Dickinson1b2e9442012-05-06 17:27:39 +0100262 def test_starred_assignment(self):
Batuhan Taşkaya89aa4692020-03-02 21:59:01 +0300263 self.check_ast_roundtrip("a, *b, c = seq")
264 self.check_ast_roundtrip("a, (*b, c) = seq")
265 self.check_ast_roundtrip("a, *b[0], c = seq")
266 self.check_ast_roundtrip("a, *(b, c) = seq")
Mark Dickinson1b2e9442012-05-06 17:27:39 +0100267
Mark Dickinsonfe8440a2012-05-06 17:35:19 +0100268 def test_with_simple(self):
Batuhan Taşkaya89aa4692020-03-02 21:59:01 +0300269 self.check_ast_roundtrip(with_simple)
Mark Dickinsonfe8440a2012-05-06 17:35:19 +0100270
271 def test_with_as(self):
Batuhan Taşkaya89aa4692020-03-02 21:59:01 +0300272 self.check_ast_roundtrip(with_as)
Mark Dickinsonfe8440a2012-05-06 17:35:19 +0100273
274 def test_with_two_items(self):
Batuhan Taşkaya89aa4692020-03-02 21:59:01 +0300275 self.check_ast_roundtrip(with_two_items)
Mark Dickinsonfe8440a2012-05-06 17:35:19 +0100276
Berker Peksagd66dd5c2016-03-06 16:50:15 +0200277 def test_dict_unpacking_in_dict(self):
278 # See issue 26489
Batuhan Taşkaya89aa4692020-03-02 21:59:01 +0300279 self.check_ast_roundtrip(r"""{**{'y': 2}, 'x': 1}""")
280 self.check_ast_roundtrip(r"""{**{'y': 2}, **{'x': 1}}""")
Berker Peksagd66dd5c2016-03-06 16:50:15 +0200281
Batuhan Taskayac102a142020-05-18 23:48:49 +0300282 def test_slices(self):
Batuhan Taşkayae7cab7f2020-03-09 23:27:03 +0300283 self.check_ast_roundtrip("a[i]")
284 self.check_ast_roundtrip("a[i,]")
285 self.check_ast_roundtrip("a[i, j]")
Batuhan Taskayac102a142020-05-18 23:48:49 +0300286 self.check_ast_roundtrip("a[(*a,)]")
287 self.check_ast_roundtrip("a[(a:=b)]")
288 self.check_ast_roundtrip("a[(a:=b,c)]")
Batuhan Taşkayae7cab7f2020-03-09 23:27:03 +0300289 self.check_ast_roundtrip("a[()]")
290 self.check_ast_roundtrip("a[i:j]")
291 self.check_ast_roundtrip("a[:j]")
292 self.check_ast_roundtrip("a[i:]")
293 self.check_ast_roundtrip("a[i:j:k]")
294 self.check_ast_roundtrip("a[:j:k]")
295 self.check_ast_roundtrip("a[i::k]")
296 self.check_ast_roundtrip("a[i:j,]")
297 self.check_ast_roundtrip("a[i:j, k]")
298
Pablo Galindo27fc3b62019-11-24 23:02:40 +0000299 def test_invalid_raise(self):
300 self.check_invalid(ast.Raise(exc=None, cause=ast.Name(id="X")))
301
302 def test_invalid_fstring_constant(self):
303 self.check_invalid(ast.JoinedStr(values=[ast.Constant(value=100)]))
304
305 def test_invalid_fstring_conversion(self):
306 self.check_invalid(
307 ast.FormattedValue(
308 value=ast.Constant(value="a", kind=None),
309 conversion=ord("Y"), # random character
310 format_spec=None,
311 )
312 )
313
314 def test_invalid_set(self):
315 self.check_invalid(ast.Set(elts=[]))
316
Batuhan Taşkaya7b35bef2020-01-02 21:20:04 +0300317 def test_invalid_yield_from(self):
318 self.check_invalid(ast.YieldFrom(value=None))
Mark Dickinson1b2e9442012-05-06 17:27:39 +0100319
Batuhan Taşkaya89aa4692020-03-02 21:59:01 +0300320 def test_docstrings(self):
321 docstrings = (
322 'this ends with double quote"',
Batuhan Taskayae966af72020-05-17 01:49:07 +0300323 'this includes a """triple quote"""',
324 '\r',
325 '\\r',
326 '\t',
327 '\\t',
328 '\n',
329 '\\n',
CyberSaxosTiGERd71a6492020-05-18 21:41:35 +0300330 '\r\\r\t\\t\n\\n',
331 '""">>> content = \"\"\"blabla\"\"\" <<<"""',
332 r'foo\n\x00',
Batuhan Taskayadd74b6f2020-05-20 01:14:14 +0300333 '🐍⛎𩸽üéş^\N{LONG RIGHTWARDS SQUIGGLE ARROW}'
CyberSaxosTiGERd71a6492020-05-18 21:41:35 +0300334
Batuhan Taşkaya89aa4692020-03-02 21:59:01 +0300335 )
336 for docstring in docstrings:
337 # check as Module docstrings for easy testing
Batuhan Taskayae966af72020-05-17 01:49:07 +0300338 self.check_ast_roundtrip(f"'''{docstring}'''")
Batuhan Taşkaya89aa4692020-03-02 21:59:01 +0300339
Batuhan Taşkayae7cab7f2020-03-09 23:27:03 +0300340 def test_constant_tuples(self):
341 self.check_src_roundtrip(ast.Constant(value=(1,), kind=None), "(1,)")
342 self.check_src_roundtrip(
343 ast.Constant(value=(1, 2, 3), kind=None), "(1, 2, 3)"
344 )
345
Batuhan Taşkaya5b66ec12020-03-15 22:56:57 +0300346 def test_function_type(self):
347 for function_type in (
348 "() -> int",
349 "(int, int) -> int",
350 "(Callable[complex], More[Complex(call.to_typevar())]) -> None"
351 ):
352 self.check_ast_roundtrip(function_type, mode="func_type")
353
Batuhan Taskayadff92bb2020-05-17 02:04:12 +0300354 def test_type_comments(self):
355 for statement in (
356 "a = 5 # type:",
357 "a = 5 # type: int",
358 "a = 5 # type: int and more",
359 "def x(): # type: () -> None\n\tpass",
360 "def x(y): # type: (int) -> None and more\n\tpass",
361 "async def x(): # type: () -> None\n\tpass",
362 "async def x(y): # type: (int) -> None and more\n\tpass",
363 "for x in y: # type: int\n\tpass",
364 "async for x in y: # type: int\n\tpass",
365 "with x(): # type: int\n\tpass",
366 "async with x(): # type: int\n\tpass"
367 ):
368 self.check_ast_roundtrip(statement, type_comments=True)
369
370 def test_type_ignore(self):
371 for statement in (
372 "a = 5 # type: ignore",
373 "a = 5 # type: ignore and more",
374 "def x(): # type: ignore\n\tpass",
375 "def x(y): # type: ignore and more\n\tpass",
376 "async def x(): # type: ignore\n\tpass",
377 "async def x(y): # type: ignore and more\n\tpass",
378 "for x in y: # type: ignore\n\tpass",
379 "async for x in y: # type: ignore\n\tpass",
380 "with x(): # type: ignore\n\tpass",
381 "async with x(): # type: ignore\n\tpass"
382 ):
383 self.check_ast_roundtrip(statement, type_comments=True)
384
Batuhan Taşkaya89aa4692020-03-02 21:59:01 +0300385
Batuhan Taşkaya397b96f2020-03-01 23:12:17 +0300386class CosmeticTestCase(ASTTestCase):
387 """Test if there are cosmetic issues caused by unnecesary additions"""
388
389 def test_simple_expressions_parens(self):
390 self.check_src_roundtrip("(a := b)")
391 self.check_src_roundtrip("await x")
392 self.check_src_roundtrip("x if x else y")
393 self.check_src_roundtrip("lambda x: x")
394 self.check_src_roundtrip("1 + 1")
395 self.check_src_roundtrip("1 + 2 / 3")
396 self.check_src_roundtrip("(1 + 2) / 3")
397 self.check_src_roundtrip("(1 + 2) * 3 + 4 * (5 + 2)")
398 self.check_src_roundtrip("(1 + 2) * 3 + 4 * (5 + 2) ** 2")
Batuhan Taskayace4a7532020-05-17 00:46:11 +0300399 self.check_src_roundtrip("~x")
Batuhan Taşkaya397b96f2020-03-01 23:12:17 +0300400 self.check_src_roundtrip("x and y")
401 self.check_src_roundtrip("x and y and z")
402 self.check_src_roundtrip("x and (y and x)")
403 self.check_src_roundtrip("(x and y) and z")
404 self.check_src_roundtrip("(x ** y) ** z ** q")
405 self.check_src_roundtrip("x >> y")
406 self.check_src_roundtrip("x << y")
407 self.check_src_roundtrip("x >> y and x >> z")
408 self.check_src_roundtrip("x + y - z * q ^ t ** k")
409 self.check_src_roundtrip("P * V if P and V else n * R * T")
410 self.check_src_roundtrip("lambda P, V, n: P * V == n * R * T")
411 self.check_src_roundtrip("flag & (other | foo)")
412 self.check_src_roundtrip("not x == y")
413 self.check_src_roundtrip("x == (not y)")
414 self.check_src_roundtrip("yield x")
415 self.check_src_roundtrip("yield from x")
416 self.check_src_roundtrip("call((yield x))")
417 self.check_src_roundtrip("return x + (yield x)")
418
Batuhan Taskaya25160cd2020-05-17 00:53:25 +0300419
420 def test_class_bases_and_keywords(self):
421 self.check_src_roundtrip("class X:\n pass")
422 self.check_src_roundtrip("class X(A):\n pass")
423 self.check_src_roundtrip("class X(A, B, C, D):\n pass")
424 self.check_src_roundtrip("class X(x=y):\n pass")
425 self.check_src_roundtrip("class X(metaclass=z):\n pass")
426 self.check_src_roundtrip("class X(x=y, z=d):\n pass")
427 self.check_src_roundtrip("class X(A, x=y):\n pass")
428 self.check_src_roundtrip("class X(A, **kw):\n pass")
429 self.check_src_roundtrip("class X(*args):\n pass")
430 self.check_src_roundtrip("class X(*args, **kwargs):\n pass")
431
Batuhan Taşkaya89aa4692020-03-02 21:59:01 +0300432 def test_docstrings(self):
433 docstrings = (
434 '"""simple doc string"""',
435 '''"""A more complex one
436 with some newlines"""''',
437 '''"""Foo bar baz
438
439 empty newline"""''',
440 '"""With some \t"""',
441 '"""Foo "bar" baz """',
Batuhan Taskayae966af72020-05-17 01:49:07 +0300442 '"""\\r"""',
443 '""""""',
444 '"""\'\'\'"""',
445 '"""\'\'\'\'\'\'"""',
Batuhan Taşkaya89aa4692020-03-02 21:59:01 +0300446 )
447
448 for prefix in docstring_prefixes:
449 for docstring in docstrings:
450 self.check_src_roundtrip(f"{prefix}{docstring}")
451
452 def test_docstrings_negative_cases(self):
453 # Test some cases that involve strings in the children of the
454 # first node but aren't docstrings to make sure we don't have
455 # False positives.
456 docstrings_negative = (
457 'a = """false"""',
458 '"""false""" + """unless its optimized"""',
459 '1 + 1\n"""false"""',
460 'f"""no, top level but f-fstring"""'
461 )
462 for prefix in docstring_prefixes:
463 for negative in docstrings_negative:
464 # this cases should be result with single quote
465 # rather then triple quoted docstring
466 src = f"{prefix}{negative}"
467 self.check_ast_roundtrip(src)
468 self.check_src_dont_roundtrip(src)
Batuhan Taşkaya397b96f2020-03-01 23:12:17 +0300469
Batuhan Taskayace4a7532020-05-17 00:46:11 +0300470 def test_unary_op_factor(self):
471 for prefix in ("+", "-", "~"):
472 self.check_src_roundtrip(f"{prefix}1")
473 for prefix in ("not",):
474 self.check_src_roundtrip(f"{prefix} 1")
475
Batuhan Taskayac102a142020-05-18 23:48:49 +0300476 def test_slices(self):
477 self.check_src_roundtrip("a[1]")
478 self.check_src_roundtrip("a[1, 2]")
479 self.check_src_roundtrip("a[(1, *a)]")
480
Mark Dickinsond751c2e2010-06-29 14:08:23 +0000481class DirectoryTestCase(ASTTestCase):
482 """Test roundtrip behaviour on all files in Lib and Lib/test."""
483
Pablo Galindo27fc3b62019-11-24 23:02:40 +0000484 lib_dir = pathlib.Path(__file__).parent / ".."
485 test_directories = (lib_dir, lib_dir / "test")
486 skip_files = {"test_fstring.py"}
Pablo Galindo23a226b2019-12-29 19:20:55 +0000487 run_always_files = {"test_grammar.py", "test_syntax.py", "test_compile.py",
488 "test_ast.py", "test_asdl_parser.py"}
Mark Dickinsond751c2e2010-06-29 14:08:23 +0000489
Pablo Galindoac229112019-12-09 17:57:50 +0000490 _files_to_test = None
491
492 @classmethod
493 def files_to_test(cls):
494
495 if cls._files_to_test is not None:
496 return cls._files_to_test
Mark Dickinsond751c2e2010-06-29 14:08:23 +0000497
Pablo Galindo27fc3b62019-11-24 23:02:40 +0000498 items = [
499 item.resolve()
Pablo Galindoac229112019-12-09 17:57:50 +0000500 for directory in cls.test_directories
Pablo Galindo27fc3b62019-11-24 23:02:40 +0000501 for item in directory.glob("*.py")
502 if not item.name.startswith("bad")
503 ]
Mark Dickinsond751c2e2010-06-29 14:08:23 +0000504
Mark Dickinsonbe4fb692012-06-23 09:27:47 +0100505 # Test limited subset of files unless the 'cpu' resource is specified.
506 if not test.support.is_resource_enabled("cpu"):
Pablo Galindobe287c32019-12-29 20:18:36 +0000507
508 tests_to_run_always = {item for item in items if
509 item.name in cls.run_always_files}
510
Pablo Galindo23a226b2019-12-29 19:20:55 +0000511 items = set(random.sample(items, 10))
512
Pablo Galindobe287c32019-12-29 20:18:36 +0000513 # Make sure that at least tests that heavily use grammar features are
514 # always considered in order to reduce the chance of missing something.
515 items = list(items | tests_to_run_always)
Pablo Galindoac229112019-12-09 17:57:50 +0000516
517 # bpo-31174: Store the names sample to always test the same files.
518 # It prevents false alarms when hunting reference leaks.
519 cls._files_to_test = items
520
Pablo Galindo27fc3b62019-11-24 23:02:40 +0000521 return items
Victor Stinner8e482be2017-10-24 03:33:36 -0700522
523 def test_files(self):
Pablo Galindoac229112019-12-09 17:57:50 +0000524 for item in self.files_to_test():
Mark Dickinsond751c2e2010-06-29 14:08:23 +0000525 if test.support.verbose:
Pablo Galindo27fc3b62019-11-24 23:02:40 +0000526 print(f"Testing {item.absolute()}")
Eric V. Smith06cf6012016-09-03 12:33:38 -0400527
Eric V. Smith451d0e32016-09-09 21:56:20 -0400528 # Some f-strings are not correctly round-tripped by
Pablo Galindo27fc3b62019-11-24 23:02:40 +0000529 # Tools/parser/unparse.py. See issue 28002 for details.
530 # We need to skip files that contain such f-strings.
531 if item.name in self.skip_files:
Eric V. Smith06cf6012016-09-03 12:33:38 -0400532 if test.support.verbose:
Pablo Galindo27fc3b62019-11-24 23:02:40 +0000533 print(f"Skipping {item.absolute()}: see issue 28002")
Eric V. Smith06cf6012016-09-03 12:33:38 -0400534 continue
535
Pablo Galindo27fc3b62019-11-24 23:02:40 +0000536 with self.subTest(filename=item):
537 source = read_pyfile(item)
Batuhan Taşkaya89aa4692020-03-02 21:59:01 +0300538 self.check_ast_roundtrip(source)
Mark Dickinsond751c2e2010-06-29 14:08:23 +0000539
540
Pablo Galindo27fc3b62019-11-24 23:02:40 +0000541if __name__ == "__main__":
Zachary Ware2b0a6102014-07-16 14:26:09 -0500542 unittest.main()