mirror of
https://github.com/davidhalter/parso.git
synced 2026-09-28 06:02:23 +08:00
Build / lint (push) Canceled after 0s
Build / test (false, 3.10) (push) Canceled after 0s
Build / test (false, 3.11) (push) Canceled after 0s
Build / test (false, 3.12) (push) Canceled after 0s
Build / test (false, 3.13) (push) Canceled after 0s
Build / test (false, 3.8) (push) Canceled after 0s
Build / test (false, 3.9) (push) Canceled after 0s
Build / coverage (push) Canceled after 0s
Python 3.15 changed the wording of some SyntaxError exceptions to make it clearer. The previous PR only fixed one instance.
431 lines
9.2 KiB
Python
431 lines
9.2 KiB
Python
# -*- coding: utf-8 -*-
|
|
import sys
|
|
from textwrap import dedent
|
|
|
|
|
|
def indent(code):
|
|
lines = code.splitlines(True)
|
|
return ''.join([' ' * 2 + line for line in lines])
|
|
|
|
|
|
def build_nested(code, depth, base='def f():\n'):
|
|
if depth == 0:
|
|
return code
|
|
|
|
new_code = base + indent(code)
|
|
return build_nested(new_code, depth - 1, base=base)
|
|
|
|
|
|
FAILING_EXAMPLES = [
|
|
'1 +',
|
|
'?',
|
|
'continue',
|
|
'break',
|
|
'return',
|
|
'yield',
|
|
|
|
# SyntaxError from Python/ast.c
|
|
'f(x for x in bar, 1)',
|
|
'from foo import a,',
|
|
'from __future__ import whatever',
|
|
'from __future__ import braces',
|
|
'def f(x=3, y): pass',
|
|
'lambda x=3, y: x',
|
|
'__debug__ = 1',
|
|
'with x() as __debug__: pass',
|
|
|
|
'[]: int',
|
|
'[a, b]: int',
|
|
'(): int',
|
|
'(()): int',
|
|
'((())): int',
|
|
'{}: int',
|
|
'True: int',
|
|
'(a, b): int',
|
|
'*star,: int',
|
|
'a, b: int = 3',
|
|
'foo(+a=3)',
|
|
'f(lambda: 1=1)',
|
|
'f(x=1, x=2)',
|
|
'f(**x, y)',
|
|
'f(x=2, y)',
|
|
'f(**x, *y)',
|
|
'f(**x, y=3, z)',
|
|
# augassign
|
|
'a, b += 3',
|
|
'(a, b) += 3',
|
|
'[a, b] += 3',
|
|
'[a, 1] += 3',
|
|
'f() += 1',
|
|
'lambda x:None+=1',
|
|
'{} += 1',
|
|
'{a:b} += 1',
|
|
'{1} += 1',
|
|
'{*x} += 1',
|
|
'(x,) += 1',
|
|
'(x, y if a else q) += 1',
|
|
'[] += 1',
|
|
'[1,2] += 1',
|
|
'[] += 1',
|
|
'None += 1',
|
|
'... += 1',
|
|
'a > 1 += 1',
|
|
'"test" += 1',
|
|
'1 += 1',
|
|
'1.0 += 1',
|
|
'(yield) += 1',
|
|
'(yield from x) += 1',
|
|
'(x if x else y) += 1',
|
|
'a() += 1',
|
|
'a + b += 1',
|
|
'+a += 1',
|
|
'a and b += 1',
|
|
'*a += 1',
|
|
'a, b += 1',
|
|
'f"xxx" += 1',
|
|
# All assignment tests
|
|
'lambda a: 1 = 1',
|
|
'[x for x in y] = 1',
|
|
'{x for x in y} = 1',
|
|
'{x:x for x in y} = 1',
|
|
'(x for x in y) = 1',
|
|
'None = 1',
|
|
'... = 1',
|
|
'a == b = 1',
|
|
'{a, b} = 1',
|
|
'{a: b} = 1',
|
|
'1 = 1',
|
|
'"" = 1',
|
|
'b"" = 1',
|
|
'b"" = 1',
|
|
'"" "" = 1',
|
|
'1 | 1 = 3',
|
|
'1**1 = 3',
|
|
'~ 1 = 3',
|
|
'not 1 = 3',
|
|
'1 and 1 = 3',
|
|
'def foo(): (yield 1) = 3',
|
|
'def foo(): x = yield 1 = 3',
|
|
'async def foo(): await x = 3',
|
|
'(a if a else a) = a',
|
|
'a, 1 = x',
|
|
'foo() = 1',
|
|
# Cases without the equals but other assignments.
|
|
'with x as foo(): pass',
|
|
'del bar, 1',
|
|
'for x, 1 in []: pass',
|
|
'for (not 1) in []: pass',
|
|
'[x for 1 in y]',
|
|
'[x for a, 3 in y]',
|
|
'(x for 1 in y)',
|
|
'{x for 1 in y}',
|
|
'{x:x for 1 in y}',
|
|
# Unicode/Bytes issues.
|
|
r'u"\x"',
|
|
r'u"\"',
|
|
r'u"\u"',
|
|
r'u"""\U"""',
|
|
r'u"\Uffffffff"',
|
|
r"u'''\N{}'''",
|
|
r"u'\N{foo}'",
|
|
r'b"\x"',
|
|
r'b"\"',
|
|
'b"ä"',
|
|
|
|
'*a, *b = 3, 3',
|
|
'async def foo(): yield from []',
|
|
'yield from []',
|
|
'*a = 3',
|
|
'del *a, b',
|
|
'def x(*): pass',
|
|
'(%s *d) = x' % ('a,' * 256),
|
|
'(True,) = x',
|
|
'([False], a) = x',
|
|
'def x(): from math import *',
|
|
|
|
# invalid del statements
|
|
'del x + y',
|
|
'del x(y)',
|
|
'async def foo(): del await x',
|
|
'def foo(): del (yield x)',
|
|
'del [x for x in range(10)]',
|
|
'del *x',
|
|
'del *x,',
|
|
'del (*x,)',
|
|
'del [*x]',
|
|
'del x, *y',
|
|
'del *x.y,',
|
|
'del *x[y],',
|
|
'del *x[y::], z',
|
|
'del x, (y, *z)',
|
|
'del (x, *[y, z])',
|
|
'del [x, *(y, [*z])]',
|
|
'del {}',
|
|
'del {x}',
|
|
'del {x, y}',
|
|
'del {x, *y}',
|
|
|
|
# invalid starred expressions
|
|
'*x',
|
|
'(*x)',
|
|
'((*x))',
|
|
'1 + (*x)',
|
|
'*x; 1',
|
|
'1; *x',
|
|
'1\n*x',
|
|
'x = *y',
|
|
'x: int = *y',
|
|
'def foo(): return *x',
|
|
'def foo(): yield *x',
|
|
'f"{*x}"',
|
|
'for *x in 1: pass',
|
|
'[1 for *x in 1]',
|
|
|
|
# str/bytes combinations
|
|
'"s" b""',
|
|
'"s" b"" ""',
|
|
'b"" "" b"" ""',
|
|
'f"s" b""',
|
|
'b"s" f""',
|
|
|
|
# Parser/tokenize.c
|
|
r'"""',
|
|
r'"',
|
|
r"'''",
|
|
r"'",
|
|
r"\blub",
|
|
# IndentationError: too many levels of indentation
|
|
build_nested('pass', 100),
|
|
|
|
# SyntaxErrors from Python/symtable.c
|
|
'def f(x, x): pass',
|
|
'nonlocal a',
|
|
|
|
# IndentationError
|
|
' foo',
|
|
'def x():\n 1\n 2',
|
|
'def x():\n 1\n 2',
|
|
'if 1:\nfoo',
|
|
'if 1: blubb\nif 1:\npass\nTrue and False',
|
|
|
|
# f-strings
|
|
'f"{}"',
|
|
r'f"{\}"',
|
|
'f"{\'\\\'}"',
|
|
'f"{#}"',
|
|
"f'{1!b}'",
|
|
"f'{'",
|
|
"f'{'",
|
|
"f'}'",
|
|
"f'{\"}'",
|
|
"f'{\"}'",
|
|
# Now nested parsing
|
|
"f'{continue}'",
|
|
"f'{1;1}'",
|
|
"f'{a;}'",
|
|
"f'{b\"\" \"\"}'",
|
|
|
|
'async def foo():\n yield x\n return 1',
|
|
'async def foo():\n yield x\n return 1',
|
|
|
|
'async def bla():\n def x(): await bla()',
|
|
'del None',
|
|
'del True',
|
|
'del False',
|
|
'del ...',
|
|
|
|
# Errors of global / nonlocal
|
|
dedent('''
|
|
def glob():
|
|
x = 3
|
|
x.z
|
|
global x'''),
|
|
dedent('''
|
|
def glob():
|
|
x = 3
|
|
global x'''),
|
|
dedent('''
|
|
def glob():
|
|
x
|
|
global x'''),
|
|
dedent('''
|
|
def glob():
|
|
x = 3
|
|
x.z
|
|
nonlocal x'''),
|
|
dedent('''
|
|
def glob():
|
|
x = 3
|
|
nonlocal x'''),
|
|
dedent('''
|
|
def glob():
|
|
x
|
|
nonlocal x'''),
|
|
# Annotation issues
|
|
dedent('''
|
|
def glob():
|
|
x[0]: foo
|
|
global x'''),
|
|
dedent('''
|
|
def glob():
|
|
x.a: foo
|
|
global x'''),
|
|
dedent('''
|
|
def glob():
|
|
x: foo
|
|
global x'''),
|
|
dedent('''
|
|
def glob():
|
|
x: foo = 5
|
|
global x'''),
|
|
dedent('''
|
|
def glob():
|
|
x: foo = 5
|
|
x
|
|
global x'''),
|
|
dedent('''
|
|
def glob():
|
|
global x
|
|
x: foo = 3
|
|
'''),
|
|
# global/nonlocal + param
|
|
dedent('''
|
|
def glob(x):
|
|
global x
|
|
'''),
|
|
dedent('''
|
|
def glob(x):
|
|
nonlocal x
|
|
'''),
|
|
dedent('''
|
|
def x():
|
|
a =3
|
|
def z():
|
|
nonlocal a
|
|
a = 3
|
|
nonlocal a
|
|
'''),
|
|
dedent('''
|
|
def x():
|
|
a = 4
|
|
def y():
|
|
global a
|
|
nonlocal a
|
|
'''),
|
|
# Missing binding of nonlocal
|
|
dedent('''
|
|
def x():
|
|
nonlocal a
|
|
'''),
|
|
dedent('''
|
|
def x():
|
|
def y():
|
|
nonlocal a
|
|
'''),
|
|
dedent('''
|
|
def x():
|
|
a = 4
|
|
def y():
|
|
global a
|
|
print(a)
|
|
def z():
|
|
nonlocal a
|
|
'''),
|
|
# Name is assigned before nonlocal declaration
|
|
dedent('''
|
|
def x(a):
|
|
def y():
|
|
a = 10
|
|
nonlocal a
|
|
'''),
|
|
]
|
|
|
|
if sys.version_info[:2] >= (3, 7):
|
|
# This is somehow ok in previous versions.
|
|
FAILING_EXAMPLES += [
|
|
'class X(base for base in bases): pass',
|
|
]
|
|
|
|
if sys.version_info[:2] < (3, 8):
|
|
FAILING_EXAMPLES += [
|
|
# Python/compile.c
|
|
dedent('''\
|
|
for a in [1]:
|
|
try:
|
|
pass
|
|
finally:
|
|
continue
|
|
'''), # 'continue' not supported inside 'finally' clause"
|
|
]
|
|
|
|
if sys.version_info[:2] >= (3, 8):
|
|
# assignment expressions from issue#89
|
|
FAILING_EXAMPLES += [
|
|
# Case 2
|
|
'(lambda: x := 1)',
|
|
'((lambda: x) := 1)',
|
|
# Case 3
|
|
'(a[i] := x)',
|
|
'((a[i]) := x)',
|
|
'(a(i) := x)',
|
|
# Case 4
|
|
'(a.b := c)',
|
|
'[(i.i:= 0) for ((i), j) in range(5)]',
|
|
# Case 5
|
|
'[i:= 0 for i, j in range(5)]',
|
|
'[(i:= 0) for ((i), j) in range(5)]',
|
|
'[(i:= 0) for ((i), j), in range(5)]',
|
|
'[(i:= 0) for ((i), j.i), in range(5)]',
|
|
'[[(i:= i) for j in range(5)] for i in range(5)]',
|
|
'[i for i, j in range(5) if True or (i:= 1)]',
|
|
'[False and (i:= 0) for i, j in range(5)]',
|
|
# Case 6
|
|
'[i+1 for i in (i:= range(5))]',
|
|
'[i+1 for i in (j:= range(5))]',
|
|
'[i+1 for i in (lambda: (j:= range(5)))()]',
|
|
# Case 7
|
|
'class Example:\n [(j := i) for i in range(5)]',
|
|
# Not in that issue
|
|
'(await a := x)',
|
|
'((await a) := x)',
|
|
# new discoveries
|
|
'((a, b) := (1, 2))',
|
|
'([a, b] := [1, 2])',
|
|
'({a, b} := {1, 2})',
|
|
'({a: b} := {1: 2})',
|
|
'(a + b := 1)',
|
|
'(True := 1)',
|
|
'(False := 1)',
|
|
'(None := 1)',
|
|
'(__debug__ := 1)',
|
|
# Unparenthesized walrus not allowed in dict literals, dict comprehensions and slices
|
|
'{a:="a": b:=1}',
|
|
'{y:=1: 2 for x in range(5)}',
|
|
'a[b:=0:1:2]',
|
|
]
|
|
# f-string debugging syntax with invalid conversion character
|
|
FAILING_EXAMPLES += [
|
|
"f'{1=!b}'",
|
|
]
|
|
|
|
if sys.version_info[:2] < (3, 12):
|
|
FAILING_EXAMPLES += [
|
|
# f-string expression part cannot include a backslash before 3.12
|
|
r'''f"{'\n'}"''',
|
|
# this compiles successfully but fails when evaluated in 3.12
|
|
"f'{1:{5:{3}}}'",
|
|
]
|
|
|
|
if sys.version_info[:2] < (3, 13):
|
|
# this compiles successfully but fails when evaluated in 3.13
|
|
FAILING_EXAMPLES += [
|
|
'from .__future__ import whatever',
|
|
]
|
|
|
|
if sys.version_info[:2] < (3, 15):
|
|
# these nested expression successfully evaluate with 3.15
|
|
FAILING_EXAMPLES += [
|
|
'[*[] for a in [1]]',
|
|
'{**{} for a in [1]}',
|
|
]
|