blob: 67dcb1dae79ff20eb6cf5e7c2c0a46eff8deb049 [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',
327 '\r\\r\t\\t\n\\n'
Batuhan Taşkaya89aa4692020-03-02 21:59:01 +0300328 )
329 for docstring in docstrings:
330 # check as Module docstrings for easy testing
Batuhan Taskayae966af72020-05-17 01:49:07 +0300331 self.check_ast_roundtrip(f"'''{docstring}'''")
Batuhan Taşkaya89aa4692020-03-02 21:59:01 +0300332
Batuhan Taşkayae7cab7f2020-03-09 23:27:03 +0300333 def test_constant_tuples(self):
334 self.check_src_roundtrip(ast.Constant(value=(1,), kind=None), "(1,)")
335 self.check_src_roundtrip(
336 ast.Constant(value=(1, 2, 3), kind=None), "(1, 2, 3)"
337 )
338
Batuhan Taşkaya5b66ec12020-03-15 22:56:57 +0300339 def test_function_type(self):
340 for function_type in (
341 "() -> int",
342 "(int, int) -> int",
343 "(Callable[complex], More[Complex(call.to_typevar())]) -> None"
344 ):
345 self.check_ast_roundtrip(function_type, mode="func_type")
346
Batuhan Taskayadff92bb2020-05-17 02:04:12 +0300347 def test_type_comments(self):
348 for statement in (
349 "a = 5 # type:",
350 "a = 5 # type: int",
351 "a = 5 # type: int and more",
352 "def x(): # type: () -> None\n\tpass",
353 "def x(y): # type: (int) -> None and more\n\tpass",
354 "async def x(): # type: () -> None\n\tpass",
355 "async def x(y): # type: (int) -> None and more\n\tpass",
356 "for x in y: # type: int\n\tpass",
357 "async for x in y: # type: int\n\tpass",
358 "with x(): # type: int\n\tpass",
359 "async with x(): # type: int\n\tpass"
360 ):
361 self.check_ast_roundtrip(statement, type_comments=True)
362
363 def test_type_ignore(self):
364 for statement in (
365 "a = 5 # type: ignore",
366 "a = 5 # type: ignore and more",
367 "def x(): # type: ignore\n\tpass",
368 "def x(y): # type: ignore and more\n\tpass",
369 "async def x(): # type: ignore\n\tpass",
370 "async def x(y): # type: ignore and more\n\tpass",
371 "for x in y: # type: ignore\n\tpass",
372 "async for x in y: # type: ignore\n\tpass",
373 "with x(): # type: ignore\n\tpass",
374 "async with x(): # type: ignore\n\tpass"
375 ):
376 self.check_ast_roundtrip(statement, type_comments=True)
377
Batuhan Taşkaya89aa4692020-03-02 21:59:01 +0300378
Batuhan Taşkaya397b96f2020-03-01 23:12:17 +0300379class CosmeticTestCase(ASTTestCase):
380 """Test if there are cosmetic issues caused by unnecesary additions"""
381
382 def test_simple_expressions_parens(self):
383 self.check_src_roundtrip("(a := b)")
384 self.check_src_roundtrip("await x")
385 self.check_src_roundtrip("x if x else y")
386 self.check_src_roundtrip("lambda x: x")
387 self.check_src_roundtrip("1 + 1")
388 self.check_src_roundtrip("1 + 2 / 3")
389 self.check_src_roundtrip("(1 + 2) / 3")
390 self.check_src_roundtrip("(1 + 2) * 3 + 4 * (5 + 2)")
391 self.check_src_roundtrip("(1 + 2) * 3 + 4 * (5 + 2) ** 2")
Batuhan Taskayace4a7532020-05-17 00:46:11 +0300392 self.check_src_roundtrip("~x")
Batuhan Taşkaya397b96f2020-03-01 23:12:17 +0300393 self.check_src_roundtrip("x and y")
394 self.check_src_roundtrip("x and y and z")
395 self.check_src_roundtrip("x and (y and x)")
396 self.check_src_roundtrip("(x and y) and z")
397 self.check_src_roundtrip("(x ** y) ** z ** q")
398 self.check_src_roundtrip("x >> y")
399 self.check_src_roundtrip("x << y")
400 self.check_src_roundtrip("x >> y and x >> z")
401 self.check_src_roundtrip("x + y - z * q ^ t ** k")
402 self.check_src_roundtrip("P * V if P and V else n * R * T")
403 self.check_src_roundtrip("lambda P, V, n: P * V == n * R * T")
404 self.check_src_roundtrip("flag & (other | foo)")
405 self.check_src_roundtrip("not x == y")
406 self.check_src_roundtrip("x == (not y)")
407 self.check_src_roundtrip("yield x")
408 self.check_src_roundtrip("yield from x")
409 self.check_src_roundtrip("call((yield x))")
410 self.check_src_roundtrip("return x + (yield x)")
411
Batuhan Taskaya25160cd2020-05-17 00:53:25 +0300412
413 def test_class_bases_and_keywords(self):
414 self.check_src_roundtrip("class X:\n pass")
415 self.check_src_roundtrip("class X(A):\n pass")
416 self.check_src_roundtrip("class X(A, B, C, D):\n pass")
417 self.check_src_roundtrip("class X(x=y):\n pass")
418 self.check_src_roundtrip("class X(metaclass=z):\n pass")
419 self.check_src_roundtrip("class X(x=y, z=d):\n pass")
420 self.check_src_roundtrip("class X(A, x=y):\n pass")
421 self.check_src_roundtrip("class X(A, **kw):\n pass")
422 self.check_src_roundtrip("class X(*args):\n pass")
423 self.check_src_roundtrip("class X(*args, **kwargs):\n pass")
424
Batuhan Taşkaya89aa4692020-03-02 21:59:01 +0300425 def test_docstrings(self):
426 docstrings = (
427 '"""simple doc string"""',
428 '''"""A more complex one
429 with some newlines"""''',
430 '''"""Foo bar baz
431
432 empty newline"""''',
433 '"""With some \t"""',
434 '"""Foo "bar" baz """',
Batuhan Taskayae966af72020-05-17 01:49:07 +0300435 '"""\\r"""',
436 '""""""',
437 '"""\'\'\'"""',
438 '"""\'\'\'\'\'\'"""',
Batuhan Taşkaya89aa4692020-03-02 21:59:01 +0300439 )
440
441 for prefix in docstring_prefixes:
442 for docstring in docstrings:
443 self.check_src_roundtrip(f"{prefix}{docstring}")
444
445 def test_docstrings_negative_cases(self):
446 # Test some cases that involve strings in the children of the
447 # first node but aren't docstrings to make sure we don't have
448 # False positives.
449 docstrings_negative = (
450 'a = """false"""',
451 '"""false""" + """unless its optimized"""',
452 '1 + 1\n"""false"""',
453 'f"""no, top level but f-fstring"""'
454 )
455 for prefix in docstring_prefixes:
456 for negative in docstrings_negative:
457 # this cases should be result with single quote
458 # rather then triple quoted docstring
459 src = f"{prefix}{negative}"
460 self.check_ast_roundtrip(src)
461 self.check_src_dont_roundtrip(src)
Batuhan Taşkaya397b96f2020-03-01 23:12:17 +0300462
Batuhan Taskayace4a7532020-05-17 00:46:11 +0300463 def test_unary_op_factor(self):
464 for prefix in ("+", "-", "~"):
465 self.check_src_roundtrip(f"{prefix}1")
466 for prefix in ("not",):
467 self.check_src_roundtrip(f"{prefix} 1")
468
Mark Dickinsond751c2e2010-06-29 14:08:23 +0000469class DirectoryTestCase(ASTTestCase):
470 """Test roundtrip behaviour on all files in Lib and Lib/test."""
471
Pablo Galindo27fc3b62019-11-24 23:02:40 +0000472 lib_dir = pathlib.Path(__file__).parent / ".."
473 test_directories = (lib_dir, lib_dir / "test")
474 skip_files = {"test_fstring.py"}
Pablo Galindo23a226b2019-12-29 19:20:55 +0000475 run_always_files = {"test_grammar.py", "test_syntax.py", "test_compile.py",
476 "test_ast.py", "test_asdl_parser.py"}
Mark Dickinsond751c2e2010-06-29 14:08:23 +0000477
Pablo Galindoac229112019-12-09 17:57:50 +0000478 _files_to_test = None
479
480 @classmethod
481 def files_to_test(cls):
482
483 if cls._files_to_test is not None:
484 return cls._files_to_test
Mark Dickinsond751c2e2010-06-29 14:08:23 +0000485
Pablo Galindo27fc3b62019-11-24 23:02:40 +0000486 items = [
487 item.resolve()
Pablo Galindoac229112019-12-09 17:57:50 +0000488 for directory in cls.test_directories
Pablo Galindo27fc3b62019-11-24 23:02:40 +0000489 for item in directory.glob("*.py")
490 if not item.name.startswith("bad")
491 ]
Mark Dickinsond751c2e2010-06-29 14:08:23 +0000492
Mark Dickinsonbe4fb692012-06-23 09:27:47 +0100493 # Test limited subset of files unless the 'cpu' resource is specified.
494 if not test.support.is_resource_enabled("cpu"):
Pablo Galindobe287c32019-12-29 20:18:36 +0000495
496 tests_to_run_always = {item for item in items if
497 item.name in cls.run_always_files}
498
Pablo Galindo23a226b2019-12-29 19:20:55 +0000499 items = set(random.sample(items, 10))
500
Pablo Galindobe287c32019-12-29 20:18:36 +0000501 # Make sure that at least tests that heavily use grammar features are
502 # always considered in order to reduce the chance of missing something.
503 items = list(items | tests_to_run_always)
Pablo Galindoac229112019-12-09 17:57:50 +0000504
505 # bpo-31174: Store the names sample to always test the same files.
506 # It prevents false alarms when hunting reference leaks.
507 cls._files_to_test = items
508
Pablo Galindo27fc3b62019-11-24 23:02:40 +0000509 return items
Victor Stinner8e482be2017-10-24 03:33:36 -0700510
511 def test_files(self):
Pablo Galindoac229112019-12-09 17:57:50 +0000512 for item in self.files_to_test():
Mark Dickinsond751c2e2010-06-29 14:08:23 +0000513 if test.support.verbose:
Pablo Galindo27fc3b62019-11-24 23:02:40 +0000514 print(f"Testing {item.absolute()}")
Eric V. Smith06cf6012016-09-03 12:33:38 -0400515
Eric V. Smith451d0e32016-09-09 21:56:20 -0400516 # Some f-strings are not correctly round-tripped by
Pablo Galindo27fc3b62019-11-24 23:02:40 +0000517 # Tools/parser/unparse.py. See issue 28002 for details.
518 # We need to skip files that contain such f-strings.
519 if item.name in self.skip_files:
Eric V. Smith06cf6012016-09-03 12:33:38 -0400520 if test.support.verbose:
Pablo Galindo27fc3b62019-11-24 23:02:40 +0000521 print(f"Skipping {item.absolute()}: see issue 28002")
Eric V. Smith06cf6012016-09-03 12:33:38 -0400522 continue
523
Pablo Galindo27fc3b62019-11-24 23:02:40 +0000524 with self.subTest(filename=item):
525 source = read_pyfile(item)
Batuhan Taşkaya89aa4692020-03-02 21:59:01 +0300526 self.check_ast_roundtrip(source)
Mark Dickinsond751c2e2010-06-29 14:08:23 +0000527
528
Pablo Galindo27fc3b62019-11-24 23:02:40 +0000529if __name__ == "__main__":
Zachary Ware2b0a6102014-07-16 14:26:09 -0500530 unittest.main()