blob: 6d828721b7740e9e09ca86c047373778246927ce [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 Taşkayae7cab7f2020-03-09 23:27:03 +0300282 def test_ext_slices(self):
283 self.check_ast_roundtrip("a[i]")
284 self.check_ast_roundtrip("a[i,]")
285 self.check_ast_roundtrip("a[i, j]")
286 self.check_ast_roundtrip("a[()]")
287 self.check_ast_roundtrip("a[i:j]")
288 self.check_ast_roundtrip("a[:j]")
289 self.check_ast_roundtrip("a[i:]")
290 self.check_ast_roundtrip("a[i:j:k]")
291 self.check_ast_roundtrip("a[:j:k]")
292 self.check_ast_roundtrip("a[i::k]")
293 self.check_ast_roundtrip("a[i:j,]")
294 self.check_ast_roundtrip("a[i:j, k]")
295
Pablo Galindo27fc3b62019-11-24 23:02:40 +0000296 def test_invalid_raise(self):
297 self.check_invalid(ast.Raise(exc=None, cause=ast.Name(id="X")))
298
299 def test_invalid_fstring_constant(self):
300 self.check_invalid(ast.JoinedStr(values=[ast.Constant(value=100)]))
301
302 def test_invalid_fstring_conversion(self):
303 self.check_invalid(
304 ast.FormattedValue(
305 value=ast.Constant(value="a", kind=None),
306 conversion=ord("Y"), # random character
307 format_spec=None,
308 )
309 )
310
311 def test_invalid_set(self):
312 self.check_invalid(ast.Set(elts=[]))
313
Batuhan Taşkaya7b35bef2020-01-02 21:20:04 +0300314 def test_invalid_yield_from(self):
315 self.check_invalid(ast.YieldFrom(value=None))
Mark Dickinson1b2e9442012-05-06 17:27:39 +0100316
Batuhan Taşkaya89aa4692020-03-02 21:59:01 +0300317 def test_docstrings(self):
318 docstrings = (
319 'this ends with double quote"',
Batuhan Taskayae966af72020-05-17 01:49:07 +0300320 'this includes a """triple quote"""',
321 '\r',
322 '\\r',
323 '\t',
324 '\\t',
325 '\n',
326 '\\n',
CyberSaxosTiGERd71a6492020-05-18 21:41:35 +0300327 '\r\\r\t\\t\n\\n',
328 '""">>> content = \"\"\"blabla\"\"\" <<<"""',
329 r'foo\n\x00',
330 '🐍⛎𩸽üéş^\X\BB\N{LONG RIGHTWARDS SQUIGGLE ARROW}'
331
Batuhan Taşkaya89aa4692020-03-02 21:59:01 +0300332 )
333 for docstring in docstrings:
334 # check as Module docstrings for easy testing
Batuhan Taskayae966af72020-05-17 01:49:07 +0300335 self.check_ast_roundtrip(f"'''{docstring}'''")
Batuhan Taşkaya89aa4692020-03-02 21:59:01 +0300336
Batuhan Taşkayae7cab7f2020-03-09 23:27:03 +0300337 def test_constant_tuples(self):
338 self.check_src_roundtrip(ast.Constant(value=(1,), kind=None), "(1,)")
339 self.check_src_roundtrip(
340 ast.Constant(value=(1, 2, 3), kind=None), "(1, 2, 3)"
341 )
342
Batuhan Taşkaya5b66ec12020-03-15 22:56:57 +0300343 def test_function_type(self):
344 for function_type in (
345 "() -> int",
346 "(int, int) -> int",
347 "(Callable[complex], More[Complex(call.to_typevar())]) -> None"
348 ):
349 self.check_ast_roundtrip(function_type, mode="func_type")
350
Batuhan Taskayadff92bb2020-05-17 02:04:12 +0300351 def test_type_comments(self):
352 for statement in (
353 "a = 5 # type:",
354 "a = 5 # type: int",
355 "a = 5 # type: int and more",
356 "def x(): # type: () -> None\n\tpass",
357 "def x(y): # type: (int) -> None and more\n\tpass",
358 "async def x(): # type: () -> None\n\tpass",
359 "async def x(y): # type: (int) -> None and more\n\tpass",
360 "for x in y: # type: int\n\tpass",
361 "async for x in y: # type: int\n\tpass",
362 "with x(): # type: int\n\tpass",
363 "async with x(): # type: int\n\tpass"
364 ):
365 self.check_ast_roundtrip(statement, type_comments=True)
366
367 def test_type_ignore(self):
368 for statement in (
369 "a = 5 # type: ignore",
370 "a = 5 # type: ignore and more",
371 "def x(): # type: ignore\n\tpass",
372 "def x(y): # type: ignore and more\n\tpass",
373 "async def x(): # type: ignore\n\tpass",
374 "async def x(y): # type: ignore and more\n\tpass",
375 "for x in y: # type: ignore\n\tpass",
376 "async for x in y: # type: ignore\n\tpass",
377 "with x(): # type: ignore\n\tpass",
378 "async with x(): # type: ignore\n\tpass"
379 ):
380 self.check_ast_roundtrip(statement, type_comments=True)
381
Batuhan Taşkaya89aa4692020-03-02 21:59:01 +0300382
Batuhan Taşkaya397b96f2020-03-01 23:12:17 +0300383class CosmeticTestCase(ASTTestCase):
384 """Test if there are cosmetic issues caused by unnecesary additions"""
385
386 def test_simple_expressions_parens(self):
387 self.check_src_roundtrip("(a := b)")
388 self.check_src_roundtrip("await x")
389 self.check_src_roundtrip("x if x else y")
390 self.check_src_roundtrip("lambda x: x")
391 self.check_src_roundtrip("1 + 1")
392 self.check_src_roundtrip("1 + 2 / 3")
393 self.check_src_roundtrip("(1 + 2) / 3")
394 self.check_src_roundtrip("(1 + 2) * 3 + 4 * (5 + 2)")
395 self.check_src_roundtrip("(1 + 2) * 3 + 4 * (5 + 2) ** 2")
Batuhan Taskayace4a7532020-05-17 00:46:11 +0300396 self.check_src_roundtrip("~x")
Batuhan Taşkaya397b96f2020-03-01 23:12:17 +0300397 self.check_src_roundtrip("x and y")
398 self.check_src_roundtrip("x and y and z")
399 self.check_src_roundtrip("x and (y and x)")
400 self.check_src_roundtrip("(x and y) and z")
401 self.check_src_roundtrip("(x ** y) ** z ** q")
402 self.check_src_roundtrip("x >> y")
403 self.check_src_roundtrip("x << y")
404 self.check_src_roundtrip("x >> y and x >> z")
405 self.check_src_roundtrip("x + y - z * q ^ t ** k")
406 self.check_src_roundtrip("P * V if P and V else n * R * T")
407 self.check_src_roundtrip("lambda P, V, n: P * V == n * R * T")
408 self.check_src_roundtrip("flag & (other | foo)")
409 self.check_src_roundtrip("not x == y")
410 self.check_src_roundtrip("x == (not y)")
411 self.check_src_roundtrip("yield x")
412 self.check_src_roundtrip("yield from x")
413 self.check_src_roundtrip("call((yield x))")
414 self.check_src_roundtrip("return x + (yield x)")
415
Batuhan Taskaya25160cd2020-05-17 00:53:25 +0300416
417 def test_class_bases_and_keywords(self):
418 self.check_src_roundtrip("class X:\n pass")
419 self.check_src_roundtrip("class X(A):\n pass")
420 self.check_src_roundtrip("class X(A, B, C, D):\n pass")
421 self.check_src_roundtrip("class X(x=y):\n pass")
422 self.check_src_roundtrip("class X(metaclass=z):\n pass")
423 self.check_src_roundtrip("class X(x=y, z=d):\n pass")
424 self.check_src_roundtrip("class X(A, x=y):\n pass")
425 self.check_src_roundtrip("class X(A, **kw):\n pass")
426 self.check_src_roundtrip("class X(*args):\n pass")
427 self.check_src_roundtrip("class X(*args, **kwargs):\n pass")
428
Batuhan Taşkaya89aa4692020-03-02 21:59:01 +0300429 def test_docstrings(self):
430 docstrings = (
431 '"""simple doc string"""',
432 '''"""A more complex one
433 with some newlines"""''',
434 '''"""Foo bar baz
435
436 empty newline"""''',
437 '"""With some \t"""',
438 '"""Foo "bar" baz """',
Batuhan Taskayae966af72020-05-17 01:49:07 +0300439 '"""\\r"""',
440 '""""""',
441 '"""\'\'\'"""',
442 '"""\'\'\'\'\'\'"""',
Batuhan Taşkaya89aa4692020-03-02 21:59:01 +0300443 )
444
445 for prefix in docstring_prefixes:
446 for docstring in docstrings:
447 self.check_src_roundtrip(f"{prefix}{docstring}")
448
449 def test_docstrings_negative_cases(self):
450 # Test some cases that involve strings in the children of the
451 # first node but aren't docstrings to make sure we don't have
452 # False positives.
453 docstrings_negative = (
454 'a = """false"""',
455 '"""false""" + """unless its optimized"""',
456 '1 + 1\n"""false"""',
457 'f"""no, top level but f-fstring"""'
458 )
459 for prefix in docstring_prefixes:
460 for negative in docstrings_negative:
461 # this cases should be result with single quote
462 # rather then triple quoted docstring
463 src = f"{prefix}{negative}"
464 self.check_ast_roundtrip(src)
465 self.check_src_dont_roundtrip(src)
Batuhan Taşkaya397b96f2020-03-01 23:12:17 +0300466
Batuhan Taskayace4a7532020-05-17 00:46:11 +0300467 def test_unary_op_factor(self):
468 for prefix in ("+", "-", "~"):
469 self.check_src_roundtrip(f"{prefix}1")
470 for prefix in ("not",):
471 self.check_src_roundtrip(f"{prefix} 1")
472
Mark Dickinsond751c2e2010-06-29 14:08:23 +0000473class DirectoryTestCase(ASTTestCase):
474 """Test roundtrip behaviour on all files in Lib and Lib/test."""
475
Pablo Galindo27fc3b62019-11-24 23:02:40 +0000476 lib_dir = pathlib.Path(__file__).parent / ".."
477 test_directories = (lib_dir, lib_dir / "test")
478 skip_files = {"test_fstring.py"}
Pablo Galindo23a226b2019-12-29 19:20:55 +0000479 run_always_files = {"test_grammar.py", "test_syntax.py", "test_compile.py",
480 "test_ast.py", "test_asdl_parser.py"}
Mark Dickinsond751c2e2010-06-29 14:08:23 +0000481
Pablo Galindoac229112019-12-09 17:57:50 +0000482 _files_to_test = None
483
484 @classmethod
485 def files_to_test(cls):
486
487 if cls._files_to_test is not None:
488 return cls._files_to_test
Mark Dickinsond751c2e2010-06-29 14:08:23 +0000489
Pablo Galindo27fc3b62019-11-24 23:02:40 +0000490 items = [
491 item.resolve()
Pablo Galindoac229112019-12-09 17:57:50 +0000492 for directory in cls.test_directories
Pablo Galindo27fc3b62019-11-24 23:02:40 +0000493 for item in directory.glob("*.py")
494 if not item.name.startswith("bad")
495 ]
Mark Dickinsond751c2e2010-06-29 14:08:23 +0000496
Mark Dickinsonbe4fb692012-06-23 09:27:47 +0100497 # Test limited subset of files unless the 'cpu' resource is specified.
498 if not test.support.is_resource_enabled("cpu"):
Pablo Galindobe287c32019-12-29 20:18:36 +0000499
500 tests_to_run_always = {item for item in items if
501 item.name in cls.run_always_files}
502
Pablo Galindo23a226b2019-12-29 19:20:55 +0000503 items = set(random.sample(items, 10))
504
Pablo Galindobe287c32019-12-29 20:18:36 +0000505 # Make sure that at least tests that heavily use grammar features are
506 # always considered in order to reduce the chance of missing something.
507 items = list(items | tests_to_run_always)
Pablo Galindoac229112019-12-09 17:57:50 +0000508
509 # bpo-31174: Store the names sample to always test the same files.
510 # It prevents false alarms when hunting reference leaks.
511 cls._files_to_test = items
512
Pablo Galindo27fc3b62019-11-24 23:02:40 +0000513 return items
Victor Stinner8e482be2017-10-24 03:33:36 -0700514
515 def test_files(self):
Pablo Galindoac229112019-12-09 17:57:50 +0000516 for item in self.files_to_test():
Mark Dickinsond751c2e2010-06-29 14:08:23 +0000517 if test.support.verbose:
Pablo Galindo27fc3b62019-11-24 23:02:40 +0000518 print(f"Testing {item.absolute()}")
Eric V. Smith06cf6012016-09-03 12:33:38 -0400519
Eric V. Smith451d0e32016-09-09 21:56:20 -0400520 # Some f-strings are not correctly round-tripped by
Pablo Galindo27fc3b62019-11-24 23:02:40 +0000521 # Tools/parser/unparse.py. See issue 28002 for details.
522 # We need to skip files that contain such f-strings.
523 if item.name in self.skip_files:
Eric V. Smith06cf6012016-09-03 12:33:38 -0400524 if test.support.verbose:
Pablo Galindo27fc3b62019-11-24 23:02:40 +0000525 print(f"Skipping {item.absolute()}: see issue 28002")
Eric V. Smith06cf6012016-09-03 12:33:38 -0400526 continue
527
Pablo Galindo27fc3b62019-11-24 23:02:40 +0000528 with self.subTest(filename=item):
529 source = read_pyfile(item)
Batuhan Taşkaya89aa4692020-03-02 21:59:01 +0300530 self.check_ast_roundtrip(source)
Mark Dickinsond751c2e2010-06-29 14:08:23 +0000531
532
Pablo Galindo27fc3b62019-11-24 23:02:40 +0000533if __name__ == "__main__":
Zachary Ware2b0a6102014-07-16 14:26:09 -0500534 unittest.main()