python (3.12.0)
1 """Test suite for 2to3's parser and grammar files.
2
3 This is the place to add tests for changes to 2to3's grammar, such as those
4 merging the grammars for Python 2 and 3. In addition to specific tests for
5 parts of the grammar we've changed, we also make sure we can parse the
6 test_grammar.py files from both Python 2 and Python 3.
7 """
8
9 # Testing imports
10 from . import support
11 from .support import driver, driver_no_print_statement
12
13 # Python imports
14 import difflib
15 import importlib
16 import operator
17 import os
18 import pickle
19 import shutil
20 import subprocess
21 import sys
22 import tempfile
23 import test.support
24 import unittest
25
26 # Local imports
27 from lib2to3.pgen2 import driver as pgen2_driver
28 from lib2to3.pgen2 import tokenize
29 from lib2to3.pgen2.parse import ParseError
30 from lib2to3.pygram import python_symbols as syms
31
32
33 class ESC[4;38;5;81mTestDriver(ESC[4;38;5;149msupportESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
34
35 def test_formfeed(self):
36 s = """print 1\n\x0Cprint 2\n"""
37 t = driver.parse_string(s)
38 self.assertEqual(t.children[0].children[0].type, syms.print_stmt)
39 self.assertEqual(t.children[1].children[0].type, syms.print_stmt)
40
41
42 class ESC[4;38;5;81mTestPgen2Caching(ESC[4;38;5;149msupportESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
43 def test_load_grammar_from_txt_file(self):
44 pgen2_driver.load_grammar(support.grammar_path, save=False, force=True)
45
46 def test_load_grammar_from_pickle(self):
47 # Make a copy of the grammar file in a temp directory we are
48 # guaranteed to be able to write to.
49 tmpdir = tempfile.mkdtemp()
50 try:
51 grammar_copy = os.path.join(
52 tmpdir, os.path.basename(support.grammar_path))
53 shutil.copy(support.grammar_path, grammar_copy)
54 pickle_name = pgen2_driver._generate_pickle_name(grammar_copy)
55
56 pgen2_driver.load_grammar(grammar_copy, save=True, force=True)
57 self.assertTrue(os.path.exists(pickle_name))
58
59 os.unlink(grammar_copy) # Only the pickle remains...
60 pgen2_driver.load_grammar(grammar_copy, save=False, force=False)
61 finally:
62 shutil.rmtree(tmpdir)
63
64 @unittest.skipIf(sys.executable is None, 'sys.executable required')
65 @unittest.skipIf(
66 sys.platform in {'emscripten', 'wasi'}, 'requires working subprocess'
67 )
68 def test_load_grammar_from_subprocess(self):
69 tmpdir = tempfile.mkdtemp()
70 tmpsubdir = os.path.join(tmpdir, 'subdir')
71 try:
72 os.mkdir(tmpsubdir)
73 grammar_base = os.path.basename(support.grammar_path)
74 grammar_copy = os.path.join(tmpdir, grammar_base)
75 grammar_sub_copy = os.path.join(tmpsubdir, grammar_base)
76 shutil.copy(support.grammar_path, grammar_copy)
77 shutil.copy(support.grammar_path, grammar_sub_copy)
78 pickle_name = pgen2_driver._generate_pickle_name(grammar_copy)
79 pickle_sub_name = pgen2_driver._generate_pickle_name(
80 grammar_sub_copy)
81 self.assertNotEqual(pickle_name, pickle_sub_name)
82
83 # Generate a pickle file from this process.
84 pgen2_driver.load_grammar(grammar_copy, save=True, force=True)
85 self.assertTrue(os.path.exists(pickle_name))
86
87 # Generate a new pickle file in a subprocess with a most likely
88 # different hash randomization seed.
89 sub_env = dict(os.environ)
90 sub_env['PYTHONHASHSEED'] = 'random'
91 code = """
92 from lib2to3.pgen2 import driver as pgen2_driver
93 pgen2_driver.load_grammar(%r, save=True, force=True)
94 """ % (grammar_sub_copy,)
95 cmd = [sys.executable,
96 '-Wignore:lib2to3:DeprecationWarning',
97 '-c', code]
98 subprocess.check_call( cmd, env=sub_env)
99 self.assertTrue(os.path.exists(pickle_sub_name))
100
101 with open(pickle_name, 'rb') as pickle_f_1, \
102 open(pickle_sub_name, 'rb') as pickle_f_2:
103 self.assertEqual(
104 pickle_f_1.read(), pickle_f_2.read(),
105 msg='Grammar caches generated using different hash seeds'
106 ' were not identical.')
107 finally:
108 shutil.rmtree(tmpdir)
109
110 def test_load_packaged_grammar(self):
111 modname = __name__ + '.load_test'
112 class ESC[4;38;5;81mMyLoader:
113 def get_data(self, where):
114 return pickle.dumps({'elephant': 19})
115 class ESC[4;38;5;81mMyModule:
116 __file__ = 'parsertestmodule'
117 __spec__ = importlib.util.spec_from_loader(modname, MyLoader())
118 sys.modules[modname] = MyModule()
119 self.addCleanup(operator.delitem, sys.modules, modname)
120 g = pgen2_driver.load_packaged_grammar(modname, 'Grammar.txt')
121 self.assertEqual(g.elephant, 19)
122
123
124 class ESC[4;38;5;81mGrammarTest(ESC[4;38;5;149msupportESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
125 def validate(self, code):
126 support.parse_string(code)
127
128 def invalid_syntax(self, code):
129 try:
130 self.validate(code)
131 except ParseError:
132 pass
133 else:
134 raise AssertionError("Syntax shouldn't have been valid")
135
136
137 class ESC[4;38;5;81mTestMatrixMultiplication(ESC[4;38;5;149mGrammarTest):
138 def test_matrix_multiplication_operator(self):
139 self.validate("a @ b")
140 self.validate("a @= b")
141
142
143 class ESC[4;38;5;81mTestYieldFrom(ESC[4;38;5;149mGrammarTest):
144 def test_yield_from(self):
145 self.validate("yield from x")
146 self.validate("(yield from x) + y")
147 self.invalid_syntax("yield from")
148
149
150 class ESC[4;38;5;81mTestAsyncAwait(ESC[4;38;5;149mGrammarTest):
151 def test_await_expr(self):
152 self.validate("""async def foo():
153 await x
154 """)
155
156 self.validate("""async def foo():
157 [i async for i in b]
158 """)
159
160 self.validate("""async def foo():
161 {i for i in b
162 async for i in a if await i
163 for b in i}
164 """)
165
166 self.validate("""async def foo():
167 [await i for i in b if await c]
168 """)
169
170 self.validate("""async def foo():
171 [ i for i in b if c]
172 """)
173
174 self.validate("""async def foo():
175
176 def foo(): pass
177
178 def foo(): pass
179
180 await x
181 """)
182
183 self.validate("""async def foo(): return await a""")
184
185 self.validate("""def foo():
186 def foo(): pass
187 async def foo(): await x
188 """)
189
190 self.invalid_syntax("await x")
191 self.invalid_syntax("""def foo():
192 await x""")
193
194 self.invalid_syntax("""def foo():
195 def foo(): pass
196 async def foo(): pass
197 await x
198 """)
199
200 def test_async_var(self):
201 self.validate("""async = 1""")
202 self.validate("""await = 1""")
203 self.validate("""def async(): pass""")
204
205 def test_async_for(self):
206 self.validate("""async def foo():
207 async for a in b: pass""")
208
209 def test_async_with(self):
210 self.validate("""async def foo():
211 async with a: pass""")
212
213 self.invalid_syntax("""def foo():
214 async with a: pass""")
215
216 def test_async_generator(self):
217 self.validate(
218 """async def foo():
219 return (i * 2 async for i in arange(42))"""
220 )
221 self.validate(
222 """def foo():
223 return (i * 2 async for i in arange(42))"""
224 )
225
226
227 class ESC[4;38;5;81mTestRaiseChanges(ESC[4;38;5;149mGrammarTest):
228 def test_2x_style_1(self):
229 self.validate("raise")
230
231 def test_2x_style_2(self):
232 self.validate("raise E, V")
233
234 def test_2x_style_3(self):
235 self.validate("raise E, V, T")
236
237 def test_2x_style_invalid_1(self):
238 self.invalid_syntax("raise E, V, T, Z")
239
240 def test_3x_style(self):
241 self.validate("raise E1 from E2")
242
243 def test_3x_style_invalid_1(self):
244 self.invalid_syntax("raise E, V from E1")
245
246 def test_3x_style_invalid_2(self):
247 self.invalid_syntax("raise E from E1, E2")
248
249 def test_3x_style_invalid_3(self):
250 self.invalid_syntax("raise from E1, E2")
251
252 def test_3x_style_invalid_4(self):
253 self.invalid_syntax("raise E from")
254
255
256 # Modelled after Lib/test/test_grammar.py:TokenTests.test_funcdef issue2292
257 # and Lib/test/text_parser.py test_list_displays, test_set_displays,
258 # test_dict_displays, test_argument_unpacking, ... changes.
259 class ESC[4;38;5;81mTestUnpackingGeneralizations(ESC[4;38;5;149mGrammarTest):
260 def test_mid_positional_star(self):
261 self.validate("""func(1, *(2, 3), 4)""")
262
263 def test_double_star_dict_literal(self):
264 self.validate("""func(**{'eggs':'scrambled', 'spam':'fried'})""")
265
266 def test_double_star_dict_literal_after_keywords(self):
267 self.validate("""func(spam='fried', **{'eggs':'scrambled'})""")
268
269 def test_double_star_expression(self):
270 self.validate("""func(**{'a':2} or {})""")
271 self.validate("""func(**() or {})""")
272
273 def test_star_expression(self):
274 self.validate("""func(*[] or [2])""")
275
276 def test_list_display(self):
277 self.validate("""[*{2}, 3, *[4]]""")
278
279 def test_set_display(self):
280 self.validate("""{*{2}, 3, *[4]}""")
281
282 def test_dict_display_1(self):
283 self.validate("""{**{}}""")
284
285 def test_dict_display_2(self):
286 self.validate("""{**{}, 3:4, **{5:6, 7:8}}""")
287
288 def test_complex_star_expression(self):
289 self.validate("func(* [] or [1])")
290
291 def test_complex_double_star_expression(self):
292 self.validate("func(**{1: 3} if False else {x: x for x in range(3)})")
293
294 def test_argument_unpacking_1(self):
295 self.validate("""f(a, *b, *c, d)""")
296
297 def test_argument_unpacking_2(self):
298 self.validate("""f(**a, **b)""")
299
300 def test_argument_unpacking_3(self):
301 self.validate("""f(2, *a, *b, **b, **c, **d)""")
302
303 def test_trailing_commas_1(self):
304 self.validate("def f(a, b): call(a, b)")
305 self.validate("def f(a, b,): call(a, b,)")
306
307 def test_trailing_commas_2(self):
308 self.validate("def f(a, *b): call(a, *b)")
309 self.validate("def f(a, *b,): call(a, *b,)")
310
311 def test_trailing_commas_3(self):
312 self.validate("def f(a, b=1): call(a, b=1)")
313 self.validate("def f(a, b=1,): call(a, b=1,)")
314
315 def test_trailing_commas_4(self):
316 self.validate("def f(a, **b): call(a, **b)")
317 self.validate("def f(a, **b,): call(a, **b,)")
318
319 def test_trailing_commas_5(self):
320 self.validate("def f(*a, b=1): call(*a, b=1)")
321 self.validate("def f(*a, b=1,): call(*a, b=1,)")
322
323 def test_trailing_commas_6(self):
324 self.validate("def f(*a, **b): call(*a, **b)")
325 self.validate("def f(*a, **b,): call(*a, **b,)")
326
327 def test_trailing_commas_7(self):
328 self.validate("def f(*, b=1): call(*b)")
329 self.validate("def f(*, b=1,): call(*b,)")
330
331 def test_trailing_commas_8(self):
332 self.validate("def f(a=1, b=2): call(a=1, b=2)")
333 self.validate("def f(a=1, b=2,): call(a=1, b=2,)")
334
335 def test_trailing_commas_9(self):
336 self.validate("def f(a=1, **b): call(a=1, **b)")
337 self.validate("def f(a=1, **b,): call(a=1, **b,)")
338
339 def test_trailing_commas_lambda_1(self):
340 self.validate("f = lambda a, b: call(a, b)")
341 self.validate("f = lambda a, b,: call(a, b,)")
342
343 def test_trailing_commas_lambda_2(self):
344 self.validate("f = lambda a, *b: call(a, *b)")
345 self.validate("f = lambda a, *b,: call(a, *b,)")
346
347 def test_trailing_commas_lambda_3(self):
348 self.validate("f = lambda a, b=1: call(a, b=1)")
349 self.validate("f = lambda a, b=1,: call(a, b=1,)")
350
351 def test_trailing_commas_lambda_4(self):
352 self.validate("f = lambda a, **b: call(a, **b)")
353 self.validate("f = lambda a, **b,: call(a, **b,)")
354
355 def test_trailing_commas_lambda_5(self):
356 self.validate("f = lambda *a, b=1: call(*a, b=1)")
357 self.validate("f = lambda *a, b=1,: call(*a, b=1,)")
358
359 def test_trailing_commas_lambda_6(self):
360 self.validate("f = lambda *a, **b: call(*a, **b)")
361 self.validate("f = lambda *a, **b,: call(*a, **b,)")
362
363 def test_trailing_commas_lambda_7(self):
364 self.validate("f = lambda *, b=1: call(*b)")
365 self.validate("f = lambda *, b=1,: call(*b,)")
366
367 def test_trailing_commas_lambda_8(self):
368 self.validate("f = lambda a=1, b=2: call(a=1, b=2)")
369 self.validate("f = lambda a=1, b=2,: call(a=1, b=2,)")
370
371 def test_trailing_commas_lambda_9(self):
372 self.validate("f = lambda a=1, **b: call(a=1, **b)")
373 self.validate("f = lambda a=1, **b,: call(a=1, **b,)")
374
375
376 # Adapted from Python 3's Lib/test/test_grammar.py:GrammarTests.testFuncdef
377 class ESC[4;38;5;81mTestFunctionAnnotations(ESC[4;38;5;149mGrammarTest):
378 def test_1(self):
379 self.validate("""def f(x) -> list: pass""")
380
381 def test_2(self):
382 self.validate("""def f(x:int): pass""")
383
384 def test_3(self):
385 self.validate("""def f(*x:str): pass""")
386
387 def test_4(self):
388 self.validate("""def f(**x:float): pass""")
389
390 def test_5(self):
391 self.validate("""def f(x, y:1+2): pass""")
392
393 def test_6(self):
394 self.validate("""def f(a, (b:1, c:2, d)): pass""")
395
396 def test_7(self):
397 self.validate("""def f(a, (b:1, c:2, d), e:3=4, f=5, *g:6): pass""")
398
399 def test_8(self):
400 s = """def f(a, (b:1, c:2, d), e:3=4, f=5,
401 *g:6, h:7, i=8, j:9=10, **k:11) -> 12: pass"""
402 self.validate(s)
403
404 def test_9(self):
405 s = """def f(
406 a: str,
407 b: int,
408 *,
409 c: bool = False,
410 **kwargs,
411 ) -> None:
412 call(c=c, **kwargs,)"""
413 self.validate(s)
414
415 def test_10(self):
416 s = """def f(
417 a: str,
418 ) -> None:
419 call(a,)"""
420 self.validate(s)
421
422 def test_11(self):
423 s = """def f(
424 a: str = '',
425 ) -> None:
426 call(a=a,)"""
427 self.validate(s)
428
429 def test_12(self):
430 s = """def f(
431 *args: str,
432 ) -> None:
433 call(*args,)"""
434 self.validate(s)
435
436 def test_13(self):
437 self.validate("def f(a: str, b: int) -> None: call(a, b)")
438 self.validate("def f(a: str, b: int,) -> None: call(a, b,)")
439
440 def test_14(self):
441 self.validate("def f(a: str, *b: int) -> None: call(a, *b)")
442 self.validate("def f(a: str, *b: int,) -> None: call(a, *b,)")
443
444 def test_15(self):
445 self.validate("def f(a: str, b: int=1) -> None: call(a, b=1)")
446 self.validate("def f(a: str, b: int=1,) -> None: call(a, b=1,)")
447
448 def test_16(self):
449 self.validate("def f(a: str, **b: int) -> None: call(a, **b)")
450 self.validate("def f(a: str, **b: int,) -> None: call(a, **b,)")
451
452 def test_17(self):
453 self.validate("def f(*a: str, b: int=1) -> None: call(*a, b=1)")
454 self.validate("def f(*a: str, b: int=1,) -> None: call(*a, b=1,)")
455
456 def test_18(self):
457 self.validate("def f(*a: str, **b: int) -> None: call(*a, **b)")
458 self.validate("def f(*a: str, **b: int,) -> None: call(*a, **b,)")
459
460 def test_19(self):
461 self.validate("def f(*, b: int=1) -> None: call(*b)")
462 self.validate("def f(*, b: int=1,) -> None: call(*b,)")
463
464 def test_20(self):
465 self.validate("def f(a: str='', b: int=2) -> None: call(a=a, b=2)")
466 self.validate("def f(a: str='', b: int=2,) -> None: call(a=a, b=2,)")
467
468 def test_21(self):
469 self.validate("def f(a: str='', **b: int) -> None: call(a=a, **b)")
470 self.validate("def f(a: str='', **b: int,) -> None: call(a=a, **b,)")
471
472
473 # Adapted from Python 3's Lib/test/test_grammar.py:GrammarTests.test_var_annot
474 class ESC[4;38;5;81mTestVarAnnotations(ESC[4;38;5;149mGrammarTest):
475 def test_1(self):
476 self.validate("var1: int = 5")
477
478 def test_2(self):
479 self.validate("var2: [int, str]")
480
481 def test_3(self):
482 self.validate("def f():\n"
483 " st: str = 'Hello'\n"
484 " a.b: int = (1, 2)\n"
485 " return st\n")
486
487 def test_4(self):
488 self.validate("def fbad():\n"
489 " x: int\n"
490 " print(x)\n")
491
492 def test_5(self):
493 self.validate("class C:\n"
494 " x: int\n"
495 " s: str = 'attr'\n"
496 " z = 2\n"
497 " def __init__(self, x):\n"
498 " self.x: int = x\n")
499
500 def test_6(self):
501 self.validate("lst: List[int] = []")
502
503
504 class ESC[4;38;5;81mTestExcept(ESC[4;38;5;149mGrammarTest):
505 def test_new(self):
506 s = """
507 try:
508 x
509 except E as N:
510 y"""
511 self.validate(s)
512
513 def test_old(self):
514 s = """
515 try:
516 x
517 except E, N:
518 y"""
519 self.validate(s)
520
521
522 class ESC[4;38;5;81mTestStringLiterals(ESC[4;38;5;149mGrammarTest):
523 prefixes = ("'", '"',
524 "r'", 'r"', "R'", 'R"',
525 "u'", 'u"', "U'", 'U"',
526 "b'", 'b"', "B'", 'B"',
527 "f'", 'f"', "F'", 'F"',
528 "ur'", 'ur"', "Ur'", 'Ur"',
529 "uR'", 'uR"', "UR'", 'UR"',
530 "br'", 'br"', "Br'", 'Br"',
531 "bR'", 'bR"', "BR'", 'BR"',
532 "rb'", 'rb"', "Rb'", 'Rb"',
533 "rB'", 'rB"', "RB'", 'RB"',)
534
535 def test_lit(self):
536 for pre in self.prefixes:
537 single = "{p}spamspamspam{s}".format(p=pre, s=pre[-1])
538 self.validate(single)
539 triple = "{p}{s}{s}eggs{s}{s}{s}".format(p=pre, s=pre[-1])
540 self.validate(triple)
541
542
543 # Adapted from Python 3's Lib/test/test_grammar.py:GrammarTests.testAtoms
544 class ESC[4;38;5;81mTestSetLiteral(ESC[4;38;5;149mGrammarTest):
545 def test_1(self):
546 self.validate("""x = {'one'}""")
547
548 def test_2(self):
549 self.validate("""x = {'one', 1,}""")
550
551 def test_3(self):
552 self.validate("""x = {'one', 'two', 'three'}""")
553
554 def test_4(self):
555 self.validate("""x = {2, 3, 4,}""")
556
557
558 # Adapted from Python 3's Lib/test/test_unicode_identifiers.py and
559 # Lib/test/test_tokenize.py:TokenizeTest.test_non_ascii_identifiers
560 class ESC[4;38;5;81mTestIdentifier(ESC[4;38;5;149mGrammarTest):
561 def test_non_ascii_identifiers(self):
562 self.validate("Örter = 'places'\ngrün = 'green'")
563 self.validate("蟒 = a蟒 = 锦蛇 = 1")
564 self.validate("µ = aµ = µµ = 1")
565 self.validate("𝔘𝔫𝔦𝔠𝔬𝔡𝔢 = a_𝔘𝔫𝔦𝔠𝔬𝔡𝔢 = 1")
566
567
568 class ESC[4;38;5;81mTestNumericLiterals(ESC[4;38;5;149mGrammarTest):
569 def test_new_octal_notation(self):
570 self.validate("""0o7777777777777""")
571 self.invalid_syntax("""0o7324528887""")
572
573 def test_new_binary_notation(self):
574 self.validate("""0b101010""")
575 self.invalid_syntax("""0b0101021""")
576
577
578 class ESC[4;38;5;81mTestClassDef(ESC[4;38;5;149mGrammarTest):
579 def test_new_syntax(self):
580 self.validate("class B(t=7): pass")
581 self.validate("class B(t, *args): pass")
582 self.validate("class B(t, **kwargs): pass")
583 self.validate("class B(t, *args, **kwargs): pass")
584 self.validate("class B(t, y=9, *args, **kwargs,): pass")
585
586
587 class ESC[4;38;5;81mTestParserIdempotency(ESC[4;38;5;149msupportESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
588
589 """A cut-down version of pytree_idempotency.py."""
590
591 def parse_file(self, filepath):
592 if test.support.verbose:
593 print(f"Parse file: {filepath}")
594 with open(filepath, "rb") as fp:
595 encoding = tokenize.detect_encoding(fp.readline)[0]
596 self.assertIsNotNone(encoding,
597 "can't detect encoding for %s" % filepath)
598 with open(filepath, "r", encoding=encoding) as fp:
599 source = fp.read()
600 try:
601 tree = driver.parse_string(source)
602 except ParseError:
603 try:
604 tree = driver_no_print_statement.parse_string(source)
605 except ParseError as err:
606 self.fail('ParseError on file %s (%s)' % (filepath, err))
607 new = str(tree)
608 if new != source:
609 print(diff_texts(source, new, filepath))
610 self.fail("Idempotency failed: %s" % filepath)
611
612 def test_all_project_files(self):
613 for filepath in support.all_project_files():
614 with self.subTest(filepath=filepath):
615 self.parse_file(filepath)
616
617 def test_extended_unpacking(self):
618 driver.parse_string("a, *b, c = x\n")
619 driver.parse_string("[*a, b] = x\n")
620 driver.parse_string("(z, *y, w) = m\n")
621 driver.parse_string("for *z, m in d: pass\n")
622
623
624 class ESC[4;38;5;81mTestLiterals(ESC[4;38;5;149mGrammarTest):
625
626 def validate(self, s):
627 driver.parse_string(support.dedent(s) + "\n\n")
628
629 def test_multiline_bytes_literals(self):
630 s = """
631 md5test(b"\xaa" * 80,
632 (b"Test Using Larger Than Block-Size Key "
633 b"and Larger Than One Block-Size Data"),
634 "6f630fad67cda0ee1fb1f562db3aa53e")
635 """
636 self.validate(s)
637
638 def test_multiline_bytes_tripquote_literals(self):
639 s = '''
640 b"""
641 <?xml version="1.0" encoding="UTF-8"?>
642 <!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN">
643 """
644 '''
645 self.validate(s)
646
647 def test_multiline_str_literals(self):
648 s = """
649 md5test("\xaa" * 80,
650 ("Test Using Larger Than Block-Size Key "
651 "and Larger Than One Block-Size Data"),
652 "6f630fad67cda0ee1fb1f562db3aa53e")
653 """
654 self.validate(s)
655
656
657 class ESC[4;38;5;81mTestNamedAssignments(ESC[4;38;5;149mGrammarTest):
658 """Also known as the walrus operator."""
659
660 def test_named_assignment_if(self):
661 driver.parse_string("if f := x(): pass\n")
662
663 def test_named_assignment_while(self):
664 driver.parse_string("while f := x(): pass\n")
665
666 def test_named_assignment_generator(self):
667 driver.parse_string("any((lastNum := num) == 1 for num in [1, 2, 3])\n")
668
669 def test_named_assignment_listcomp(self):
670 driver.parse_string("[(lastNum := num) == 1 for num in [1, 2, 3]]\n")
671
672
673 class ESC[4;38;5;81mTestPositionalOnlyArgs(ESC[4;38;5;149mGrammarTest):
674
675 def test_one_pos_only_arg(self):
676 driver.parse_string("def one_pos_only_arg(a, /): pass\n")
677
678 def test_all_markers(self):
679 driver.parse_string(
680 "def all_markers(a, b=2, /, c, d=4, *, e=5, f): pass\n")
681
682 def test_all_with_args_and_kwargs(self):
683 driver.parse_string(
684 """def all_markers_with_args_and_kwargs(
685 aa, b, /, _cc, d, *args, e, f_f, **kwargs,
686 ):
687 pass\n""")
688
689 def test_lambda_soup(self):
690 driver.parse_string(
691 "lambda a, b, /, c, d, *args, e, f, **kw: kw\n")
692
693 def test_only_positional_or_keyword(self):
694 driver.parse_string("def func(a,b,/,*,g,e=3): pass\n")
695
696
697 class ESC[4;38;5;81mTestPickleableException(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
698 def test_ParseError(self):
699 err = ParseError('msg', 2, None, (1, 'context'))
700 for proto in range(pickle.HIGHEST_PROTOCOL + 1):
701 err2 = pickle.loads(pickle.dumps(err, protocol=proto))
702 self.assertEqual(err.args, err2.args)
703 self.assertEqual(err.msg, err2.msg)
704 self.assertEqual(err.type, err2.type)
705 self.assertEqual(err.value, err2.value)
706 self.assertEqual(err.context, err2.context)
707
708
709 def diff_texts(a, b, filename):
710 a = a.splitlines()
711 b = b.splitlines()
712 return difflib.unified_diff(a, b, filename, filename,
713 "(original)", "(reserialized)",
714 lineterm="")
715
716
717 if __name__ == '__main__':
718 unittest.main()