blob: c7c8613ea2793f00fce6a4de545389be654a5431 [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}'""")
Shantanua993e902020-11-20 13:16:42 -0800155 self.check_ast_roundtrip("""f''""")
156 self.check_ast_roundtrip('''f"""'end' "quote\\""""''')
157
158 def test_fstrings_complicated(self):
159 # See issue 28002
160 self.check_ast_roundtrip("""f'''{"'"}'''""")
161 self.check_ast_roundtrip('''f\'\'\'-{f"""*{f"+{f'.{x}.'}+"}*"""}-\'\'\'''')
162 self.check_ast_roundtrip('''f\'\'\'-{f"""*{f"+{f'.{x}.'}+"}*"""}-'single quote\\'\'\'\'''')
163 self.check_ast_roundtrip('f"""{\'\'\'\n\'\'\'}"""')
164 self.check_ast_roundtrip('f"""{g(\'\'\'\n\'\'\')}"""')
165 self.check_ast_roundtrip('''f"a\\r\\nb"''')
166 self.check_ast_roundtrip('''f"\\u2028{'x'}"''')
Eric V. Smith608adf92015-09-20 15:09:15 -0400167
Chih-Hsuan Yenaaf47ca2019-05-27 01:08:20 +0800168 def test_strings(self):
Batuhan Taşkaya89aa4692020-03-02 21:59:01 +0300169 self.check_ast_roundtrip("u'foo'")
170 self.check_ast_roundtrip("r'foo'")
171 self.check_ast_roundtrip("b'foo'")
Chih-Hsuan Yenaaf47ca2019-05-27 01:08:20 +0800172
Mark Dickinsonae100052010-06-28 19:44:20 +0000173 def test_del_statement(self):
Batuhan Taşkaya89aa4692020-03-02 21:59:01 +0300174 self.check_ast_roundtrip("del x, y, z")
Mark Dickinsonae100052010-06-28 19:44:20 +0000175
176 def test_shifts(self):
Batuhan Taşkaya89aa4692020-03-02 21:59:01 +0300177 self.check_ast_roundtrip("45 << 2")
178 self.check_ast_roundtrip("13 >> 7")
Mark Dickinsonae100052010-06-28 19:44:20 +0000179
180 def test_for_else(self):
Batuhan Taşkaya89aa4692020-03-02 21:59:01 +0300181 self.check_ast_roundtrip(for_else)
Mark Dickinsonae100052010-06-28 19:44:20 +0000182
183 def test_while_else(self):
Batuhan Taşkaya89aa4692020-03-02 21:59:01 +0300184 self.check_ast_roundtrip(while_else)
Mark Dickinsonae100052010-06-28 19:44:20 +0000185
186 def test_unary_parens(self):
Batuhan Taşkaya89aa4692020-03-02 21:59:01 +0300187 self.check_ast_roundtrip("(-1)**7")
188 self.check_ast_roundtrip("(-1.)**8")
189 self.check_ast_roundtrip("(-1j)**6")
190 self.check_ast_roundtrip("not True or False")
191 self.check_ast_roundtrip("True or not False")
Mark Dickinsonae100052010-06-28 19:44:20 +0000192
Mark Dickinson3eb02902010-06-29 08:52:36 +0000193 def test_integer_parens(self):
Batuhan Taşkaya89aa4692020-03-02 21:59:01 +0300194 self.check_ast_roundtrip("3 .__abs__()")
Mark Dickinson3eb02902010-06-29 08:52:36 +0000195
Mark Dickinson8042e282010-06-29 10:01:48 +0000196 def test_huge_float(self):
Batuhan Taşkaya89aa4692020-03-02 21:59:01 +0300197 self.check_ast_roundtrip("1e1000")
198 self.check_ast_roundtrip("-1e1000")
199 self.check_ast_roundtrip("1e1000j")
200 self.check_ast_roundtrip("-1e1000j")
Mark Dickinsoncba8c102010-06-30 11:45:53 +0000201
202 def test_min_int(self):
Batuhan Taşkaya89aa4692020-03-02 21:59:01 +0300203 self.check_ast_roundtrip(str(-(2 ** 31)))
204 self.check_ast_roundtrip(str(-(2 ** 63)))
Mark Dickinsoncba8c102010-06-30 11:45:53 +0000205
206 def test_imaginary_literals(self):
Batuhan Taşkaya89aa4692020-03-02 21:59:01 +0300207 self.check_ast_roundtrip("7j")
208 self.check_ast_roundtrip("-7j")
209 self.check_ast_roundtrip("0j")
210 self.check_ast_roundtrip("-0j")
Mark Dickinson8042e282010-06-29 10:01:48 +0000211
212 def test_lambda_parentheses(self):
Batuhan Taşkaya89aa4692020-03-02 21:59:01 +0300213 self.check_ast_roundtrip("(lambda: int)()")
Mark Dickinson8042e282010-06-29 10:01:48 +0000214
Mark Dickinsonf5451e52010-06-28 20:09:18 +0000215 def test_chained_comparisons(self):
Batuhan Taşkaya89aa4692020-03-02 21:59:01 +0300216 self.check_ast_roundtrip("1 < 4 <= 5")
217 self.check_ast_roundtrip("a is b is c is not d")
Mark Dickinsonf5451e52010-06-28 20:09:18 +0000218
Mark Dickinsonfa2e4e92010-06-28 21:14:17 +0000219 def test_function_arguments(self):
Batuhan Taşkaya89aa4692020-03-02 21:59:01 +0300220 self.check_ast_roundtrip("def f(): pass")
221 self.check_ast_roundtrip("def f(a): pass")
222 self.check_ast_roundtrip("def f(b = 2): pass")
223 self.check_ast_roundtrip("def f(a, b): pass")
224 self.check_ast_roundtrip("def f(a, b = 2): pass")
225 self.check_ast_roundtrip("def f(a = 5, b = 2): pass")
226 self.check_ast_roundtrip("def f(*, a = 1, b = 2): pass")
227 self.check_ast_roundtrip("def f(*, a = 1, b): pass")
228 self.check_ast_roundtrip("def f(*, a, b = 2): pass")
229 self.check_ast_roundtrip("def f(a, b = None, *, c, **kwds): pass")
230 self.check_ast_roundtrip("def f(a=2, *args, c=5, d, **kwds): pass")
231 self.check_ast_roundtrip("def f(*args, **kwargs): pass")
Mark Dickinsonfa2e4e92010-06-28 21:14:17 +0000232
233 def test_relative_import(self):
Batuhan Taşkaya89aa4692020-03-02 21:59:01 +0300234 self.check_ast_roundtrip(relative_import)
Mark Dickinsonfa2e4e92010-06-28 21:14:17 +0000235
236 def test_nonlocal(self):
Batuhan Taşkaya89aa4692020-03-02 21:59:01 +0300237 self.check_ast_roundtrip(nonlocal_ex)
Mark Dickinsonfa2e4e92010-06-28 21:14:17 +0000238
239 def test_raise_from(self):
Batuhan Taşkaya89aa4692020-03-02 21:59:01 +0300240 self.check_ast_roundtrip(raise_from)
Mark Dickinsonfa2e4e92010-06-28 21:14:17 +0000241
242 def test_bytes(self):
Batuhan Taşkaya89aa4692020-03-02 21:59:01 +0300243 self.check_ast_roundtrip("b'123'")
Mark Dickinsonfa2e4e92010-06-28 21:14:17 +0000244
245 def test_annotations(self):
Batuhan Taşkaya89aa4692020-03-02 21:59:01 +0300246 self.check_ast_roundtrip("def f(a : int): pass")
247 self.check_ast_roundtrip("def f(a: int = 5): pass")
248 self.check_ast_roundtrip("def f(*args: [int]): pass")
249 self.check_ast_roundtrip("def f(**kwargs: dict): pass")
250 self.check_ast_roundtrip("def f() -> None: pass")
Mark Dickinsonfa2e4e92010-06-28 21:14:17 +0000251
252 def test_set_literal(self):
Batuhan Taşkaya89aa4692020-03-02 21:59:01 +0300253 self.check_ast_roundtrip("{'a', 'b', 'c'}")
Mark Dickinsonfa2e4e92010-06-28 21:14:17 +0000254
255 def test_set_comprehension(self):
Batuhan Taşkaya89aa4692020-03-02 21:59:01 +0300256 self.check_ast_roundtrip("{x for x in range(5)}")
Mark Dickinsonfa2e4e92010-06-28 21:14:17 +0000257
258 def test_dict_comprehension(self):
Batuhan Taşkaya89aa4692020-03-02 21:59:01 +0300259 self.check_ast_roundtrip("{x: x*x for x in range(10)}")
Mark Dickinsonfa2e4e92010-06-28 21:14:17 +0000260
261 def test_class_decorators(self):
Batuhan Taşkaya89aa4692020-03-02 21:59:01 +0300262 self.check_ast_roundtrip(class_decorator)
Mark Dickinsonae100052010-06-28 19:44:20 +0000263
Mark Dickinson578aa562010-06-29 18:38:59 +0000264 def test_class_definition(self):
Batuhan Taşkaya89aa4692020-03-02 21:59:01 +0300265 self.check_ast_roundtrip("class A(metaclass=type, *[], **{}): pass")
Mark Dickinsond751c2e2010-06-29 14:08:23 +0000266
Mark Dickinson8d6d7602010-06-30 08:32:11 +0000267 def test_elifs(self):
Batuhan Taşkaya89aa4692020-03-02 21:59:01 +0300268 self.check_ast_roundtrip(elif1)
269 self.check_ast_roundtrip(elif2)
Mark Dickinson8d6d7602010-06-30 08:32:11 +0000270
Mark Dickinson81ad8cc2010-06-30 08:46:53 +0000271 def test_try_except_finally(self):
Batuhan Taşkaya89aa4692020-03-02 21:59:01 +0300272 self.check_ast_roundtrip(try_except_finally)
Mark Dickinson81ad8cc2010-06-30 08:46:53 +0000273
Mark Dickinson1b2e9442012-05-06 17:27:39 +0100274 def test_starred_assignment(self):
Batuhan Taşkaya89aa4692020-03-02 21:59:01 +0300275 self.check_ast_roundtrip("a, *b, c = seq")
276 self.check_ast_roundtrip("a, (*b, c) = seq")
277 self.check_ast_roundtrip("a, *b[0], c = seq")
278 self.check_ast_roundtrip("a, *(b, c) = seq")
Mark Dickinson1b2e9442012-05-06 17:27:39 +0100279
Mark Dickinsonfe8440a2012-05-06 17:35:19 +0100280 def test_with_simple(self):
Batuhan Taşkaya89aa4692020-03-02 21:59:01 +0300281 self.check_ast_roundtrip(with_simple)
Mark Dickinsonfe8440a2012-05-06 17:35:19 +0100282
283 def test_with_as(self):
Batuhan Taşkaya89aa4692020-03-02 21:59:01 +0300284 self.check_ast_roundtrip(with_as)
Mark Dickinsonfe8440a2012-05-06 17:35:19 +0100285
286 def test_with_two_items(self):
Batuhan Taşkaya89aa4692020-03-02 21:59:01 +0300287 self.check_ast_roundtrip(with_two_items)
Mark Dickinsonfe8440a2012-05-06 17:35:19 +0100288
Berker Peksagd66dd5c2016-03-06 16:50:15 +0200289 def test_dict_unpacking_in_dict(self):
290 # See issue 26489
Batuhan Taşkaya89aa4692020-03-02 21:59:01 +0300291 self.check_ast_roundtrip(r"""{**{'y': 2}, 'x': 1}""")
292 self.check_ast_roundtrip(r"""{**{'y': 2}, **{'x': 1}}""")
Berker Peksagd66dd5c2016-03-06 16:50:15 +0200293
Batuhan Taskayac102a142020-05-18 23:48:49 +0300294 def test_slices(self):
Batuhan Taşkayae7cab7f2020-03-09 23:27:03 +0300295 self.check_ast_roundtrip("a[i]")
296 self.check_ast_roundtrip("a[i,]")
297 self.check_ast_roundtrip("a[i, j]")
Batuhan Taskayac102a142020-05-18 23:48:49 +0300298 self.check_ast_roundtrip("a[(*a,)]")
299 self.check_ast_roundtrip("a[(a:=b)]")
300 self.check_ast_roundtrip("a[(a:=b,c)]")
Batuhan Taşkayae7cab7f2020-03-09 23:27:03 +0300301 self.check_ast_roundtrip("a[()]")
302 self.check_ast_roundtrip("a[i:j]")
303 self.check_ast_roundtrip("a[:j]")
304 self.check_ast_roundtrip("a[i:]")
305 self.check_ast_roundtrip("a[i:j:k]")
306 self.check_ast_roundtrip("a[:j:k]")
307 self.check_ast_roundtrip("a[i::k]")
308 self.check_ast_roundtrip("a[i:j,]")
309 self.check_ast_roundtrip("a[i:j, k]")
310
Pablo Galindo27fc3b62019-11-24 23:02:40 +0000311 def test_invalid_raise(self):
312 self.check_invalid(ast.Raise(exc=None, cause=ast.Name(id="X")))
313
314 def test_invalid_fstring_constant(self):
315 self.check_invalid(ast.JoinedStr(values=[ast.Constant(value=100)]))
316
317 def test_invalid_fstring_conversion(self):
318 self.check_invalid(
319 ast.FormattedValue(
320 value=ast.Constant(value="a", kind=None),
321 conversion=ord("Y"), # random character
322 format_spec=None,
323 )
324 )
325
Shantanua993e902020-11-20 13:16:42 -0800326 def test_invalid_fstring_backslash(self):
327 self.check_invalid(ast.FormattedValue(value=ast.Constant(value="\\\\")))
328
Pablo Galindo27fc3b62019-11-24 23:02:40 +0000329 def test_invalid_set(self):
330 self.check_invalid(ast.Set(elts=[]))
331
Batuhan Taşkaya7b35bef2020-01-02 21:20:04 +0300332 def test_invalid_yield_from(self):
333 self.check_invalid(ast.YieldFrom(value=None))
Mark Dickinson1b2e9442012-05-06 17:27:39 +0100334
Batuhan Taşkaya89aa4692020-03-02 21:59:01 +0300335 def test_docstrings(self):
336 docstrings = (
337 'this ends with double quote"',
Batuhan Taskayae966af72020-05-17 01:49:07 +0300338 'this includes a """triple quote"""',
339 '\r',
340 '\\r',
341 '\t',
342 '\\t',
343 '\n',
344 '\\n',
CyberSaxosTiGERd71a6492020-05-18 21:41:35 +0300345 '\r\\r\t\\t\n\\n',
346 '""">>> content = \"\"\"blabla\"\"\" <<<"""',
347 r'foo\n\x00',
Shantanua993e902020-11-20 13:16:42 -0800348 "' \\'\\'\\'\"\"\" \"\"\\'\\' \\'",
349 '🐍⛎𩸽üéş^\\\\X\\\\BB\N{LONG RIGHTWARDS SQUIGGLE ARROW}'
Batuhan Taşkaya89aa4692020-03-02 21:59:01 +0300350 )
351 for docstring in docstrings:
352 # check as Module docstrings for easy testing
Batuhan Taskayae966af72020-05-17 01:49:07 +0300353 self.check_ast_roundtrip(f"'''{docstring}'''")
Batuhan Taşkaya89aa4692020-03-02 21:59:01 +0300354
Batuhan Taşkayae7cab7f2020-03-09 23:27:03 +0300355 def test_constant_tuples(self):
356 self.check_src_roundtrip(ast.Constant(value=(1,), kind=None), "(1,)")
357 self.check_src_roundtrip(
358 ast.Constant(value=(1, 2, 3), kind=None), "(1, 2, 3)"
359 )
360
Batuhan Taşkaya5b66ec12020-03-15 22:56:57 +0300361 def test_function_type(self):
362 for function_type in (
363 "() -> int",
364 "(int, int) -> int",
365 "(Callable[complex], More[Complex(call.to_typevar())]) -> None"
366 ):
367 self.check_ast_roundtrip(function_type, mode="func_type")
368
Batuhan Taskayadff92bb2020-05-17 02:04:12 +0300369 def test_type_comments(self):
370 for statement in (
371 "a = 5 # type:",
372 "a = 5 # type: int",
373 "a = 5 # type: int and more",
374 "def x(): # type: () -> None\n\tpass",
375 "def x(y): # type: (int) -> None and more\n\tpass",
376 "async def x(): # type: () -> None\n\tpass",
377 "async def x(y): # type: (int) -> None and more\n\tpass",
378 "for x in y: # type: int\n\tpass",
379 "async for x in y: # type: int\n\tpass",
380 "with x(): # type: int\n\tpass",
381 "async with x(): # type: int\n\tpass"
382 ):
383 self.check_ast_roundtrip(statement, type_comments=True)
384
385 def test_type_ignore(self):
386 for statement in (
387 "a = 5 # type: ignore",
388 "a = 5 # type: ignore and more",
389 "def x(): # type: ignore\n\tpass",
390 "def x(y): # type: ignore and more\n\tpass",
391 "async def x(): # type: ignore\n\tpass",
392 "async def x(y): # type: ignore and more\n\tpass",
393 "for x in y: # type: ignore\n\tpass",
394 "async for x in y: # type: ignore\n\tpass",
395 "with x(): # type: ignore\n\tpass",
396 "async with x(): # type: ignore\n\tpass"
397 ):
398 self.check_ast_roundtrip(statement, type_comments=True)
399
Batuhan Taşkaya89aa4692020-03-02 21:59:01 +0300400
Batuhan Taşkaya397b96f2020-03-01 23:12:17 +0300401class CosmeticTestCase(ASTTestCase):
402 """Test if there are cosmetic issues caused by unnecesary additions"""
403
404 def test_simple_expressions_parens(self):
405 self.check_src_roundtrip("(a := b)")
406 self.check_src_roundtrip("await x")
407 self.check_src_roundtrip("x if x else y")
408 self.check_src_roundtrip("lambda x: x")
409 self.check_src_roundtrip("1 + 1")
410 self.check_src_roundtrip("1 + 2 / 3")
411 self.check_src_roundtrip("(1 + 2) / 3")
412 self.check_src_roundtrip("(1 + 2) * 3 + 4 * (5 + 2)")
413 self.check_src_roundtrip("(1 + 2) * 3 + 4 * (5 + 2) ** 2")
Batuhan Taskayace4a7532020-05-17 00:46:11 +0300414 self.check_src_roundtrip("~x")
Batuhan Taşkaya397b96f2020-03-01 23:12:17 +0300415 self.check_src_roundtrip("x and y")
416 self.check_src_roundtrip("x and y and z")
417 self.check_src_roundtrip("x and (y and x)")
418 self.check_src_roundtrip("(x and y) and z")
419 self.check_src_roundtrip("(x ** y) ** z ** q")
420 self.check_src_roundtrip("x >> y")
421 self.check_src_roundtrip("x << y")
422 self.check_src_roundtrip("x >> y and x >> z")
423 self.check_src_roundtrip("x + y - z * q ^ t ** k")
424 self.check_src_roundtrip("P * V if P and V else n * R * T")
425 self.check_src_roundtrip("lambda P, V, n: P * V == n * R * T")
426 self.check_src_roundtrip("flag & (other | foo)")
427 self.check_src_roundtrip("not x == y")
428 self.check_src_roundtrip("x == (not y)")
429 self.check_src_roundtrip("yield x")
430 self.check_src_roundtrip("yield from x")
431 self.check_src_roundtrip("call((yield x))")
432 self.check_src_roundtrip("return x + (yield x)")
433
Batuhan Taskaya25160cd2020-05-17 00:53:25 +0300434 def test_class_bases_and_keywords(self):
435 self.check_src_roundtrip("class X:\n pass")
436 self.check_src_roundtrip("class X(A):\n pass")
437 self.check_src_roundtrip("class X(A, B, C, D):\n pass")
438 self.check_src_roundtrip("class X(x=y):\n pass")
439 self.check_src_roundtrip("class X(metaclass=z):\n pass")
440 self.check_src_roundtrip("class X(x=y, z=d):\n pass")
441 self.check_src_roundtrip("class X(A, x=y):\n pass")
442 self.check_src_roundtrip("class X(A, **kw):\n pass")
443 self.check_src_roundtrip("class X(*args):\n pass")
444 self.check_src_roundtrip("class X(*args, **kwargs):\n pass")
445
Shantanua993e902020-11-20 13:16:42 -0800446 def test_fstrings(self):
447 self.check_src_roundtrip('''f\'\'\'-{f"""*{f"+{f'.{x}.'}+"}*"""}-\'\'\'''')
448 self.check_src_roundtrip('''f"\\u2028{'x'}"''')
449 self.check_src_roundtrip(r"f'{x}\n'")
450 self.check_src_roundtrip('''f''\'{"""\n"""}\\n''\'''')
451 self.check_src_roundtrip('''f''\'{f"""{x}\n"""}\\n''\'''')
452
Batuhan Taşkaya89aa4692020-03-02 21:59:01 +0300453 def test_docstrings(self):
454 docstrings = (
455 '"""simple doc string"""',
456 '''"""A more complex one
457 with some newlines"""''',
458 '''"""Foo bar baz
459
460 empty newline"""''',
461 '"""With some \t"""',
462 '"""Foo "bar" baz """',
Batuhan Taskayae966af72020-05-17 01:49:07 +0300463 '"""\\r"""',
464 '""""""',
465 '"""\'\'\'"""',
466 '"""\'\'\'\'\'\'"""',
Shantanua993e902020-11-20 13:16:42 -0800467 '"""🐍⛎𩸽üéş^\\\\X\\\\BB⟿"""',
468 '"""end in single \'quote\'"""',
469 "'''end in double \"quote\"'''",
470 '"""almost end in double "quote"."""',
Batuhan Taşkaya89aa4692020-03-02 21:59:01 +0300471 )
472
473 for prefix in docstring_prefixes:
474 for docstring in docstrings:
475 self.check_src_roundtrip(f"{prefix}{docstring}")
476
477 def test_docstrings_negative_cases(self):
478 # Test some cases that involve strings in the children of the
479 # first node but aren't docstrings to make sure we don't have
480 # False positives.
481 docstrings_negative = (
482 'a = """false"""',
483 '"""false""" + """unless its optimized"""',
484 '1 + 1\n"""false"""',
485 'f"""no, top level but f-fstring"""'
486 )
487 for prefix in docstring_prefixes:
488 for negative in docstrings_negative:
489 # this cases should be result with single quote
490 # rather then triple quoted docstring
491 src = f"{prefix}{negative}"
492 self.check_ast_roundtrip(src)
493 self.check_src_dont_roundtrip(src)
Batuhan Taşkaya397b96f2020-03-01 23:12:17 +0300494
Batuhan Taskayace4a7532020-05-17 00:46:11 +0300495 def test_unary_op_factor(self):
496 for prefix in ("+", "-", "~"):
497 self.check_src_roundtrip(f"{prefix}1")
498 for prefix in ("not",):
499 self.check_src_roundtrip(f"{prefix} 1")
500
Batuhan Taskayac102a142020-05-18 23:48:49 +0300501 def test_slices(self):
502 self.check_src_roundtrip("a[1]")
503 self.check_src_roundtrip("a[1, 2]")
504 self.check_src_roundtrip("a[(1, *a)]")
505
Mark Dickinsond751c2e2010-06-29 14:08:23 +0000506class DirectoryTestCase(ASTTestCase):
507 """Test roundtrip behaviour on all files in Lib and Lib/test."""
508
Pablo Galindo27fc3b62019-11-24 23:02:40 +0000509 lib_dir = pathlib.Path(__file__).parent / ".."
510 test_directories = (lib_dir, lib_dir / "test")
Pablo Galindo23a226b2019-12-29 19:20:55 +0000511 run_always_files = {"test_grammar.py", "test_syntax.py", "test_compile.py",
Shantanua993e902020-11-20 13:16:42 -0800512 "test_ast.py", "test_asdl_parser.py", "test_fstring.py"}
Mark Dickinsond751c2e2010-06-29 14:08:23 +0000513
Pablo Galindoac229112019-12-09 17:57:50 +0000514 _files_to_test = None
515
516 @classmethod
517 def files_to_test(cls):
518
519 if cls._files_to_test is not None:
520 return cls._files_to_test
Mark Dickinsond751c2e2010-06-29 14:08:23 +0000521
Pablo Galindo27fc3b62019-11-24 23:02:40 +0000522 items = [
523 item.resolve()
Pablo Galindoac229112019-12-09 17:57:50 +0000524 for directory in cls.test_directories
Pablo Galindo27fc3b62019-11-24 23:02:40 +0000525 for item in directory.glob("*.py")
526 if not item.name.startswith("bad")
527 ]
Mark Dickinsond751c2e2010-06-29 14:08:23 +0000528
Mark Dickinsonbe4fb692012-06-23 09:27:47 +0100529 # Test limited subset of files unless the 'cpu' resource is specified.
530 if not test.support.is_resource_enabled("cpu"):
Pablo Galindobe287c32019-12-29 20:18:36 +0000531
532 tests_to_run_always = {item for item in items if
533 item.name in cls.run_always_files}
534
Pablo Galindo23a226b2019-12-29 19:20:55 +0000535 items = set(random.sample(items, 10))
536
Pablo Galindobe287c32019-12-29 20:18:36 +0000537 # Make sure that at least tests that heavily use grammar features are
538 # always considered in order to reduce the chance of missing something.
539 items = list(items | tests_to_run_always)
Pablo Galindoac229112019-12-09 17:57:50 +0000540
541 # bpo-31174: Store the names sample to always test the same files.
542 # It prevents false alarms when hunting reference leaks.
543 cls._files_to_test = items
544
Pablo Galindo27fc3b62019-11-24 23:02:40 +0000545 return items
Victor Stinner8e482be2017-10-24 03:33:36 -0700546
547 def test_files(self):
Pablo Galindoac229112019-12-09 17:57:50 +0000548 for item in self.files_to_test():
Mark Dickinsond751c2e2010-06-29 14:08:23 +0000549 if test.support.verbose:
Pablo Galindo27fc3b62019-11-24 23:02:40 +0000550 print(f"Testing {item.absolute()}")
Eric V. Smith06cf6012016-09-03 12:33:38 -0400551
Pablo Galindo27fc3b62019-11-24 23:02:40 +0000552 with self.subTest(filename=item):
553 source = read_pyfile(item)
Batuhan Taşkaya89aa4692020-03-02 21:59:01 +0300554 self.check_ast_roundtrip(source)
Mark Dickinsond751c2e2010-06-29 14:08:23 +0000555
556
Pablo Galindo27fc3b62019-11-24 23:02:40 +0000557if __name__ == "__main__":
Zachary Ware2b0a6102014-07-16 14:26:09 -0500558 unittest.main()