314 lines
6.9 KiB
Python
314 lines
6.9 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 +',
|
|
'?',
|
|
# Python/compile.c
|
|
dedent('''\
|
|
for a in [1]:
|
|
try:
|
|
pass
|
|
finally:
|
|
continue
|
|
'''), # 'continue' not supported inside 'finally' clause"
|
|
'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',
|
|
'from .__future__ import whatever',
|
|
'def f(x=3, y): pass',
|
|
'lambda x=3, y: x',
|
|
'__debug__ = 1',
|
|
'with x() as __debug__: pass',
|
|
# Mostly 3.6 relevant
|
|
'[]: 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)',
|
|
'a, b += 3',
|
|
'(a, b) += 3',
|
|
'[a, b] += 3',
|
|
# 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"\"',
|
|
'*a, *b = 3, 3',
|
|
'async def foo(): yield from []',
|
|
'yield from []',
|
|
'*a = 3',
|
|
'del *a, b',
|
|
'def x(*): pass',
|
|
'(%s *d) = x' % ('a,' * 256),
|
|
'{**{} for a in [1]}',
|
|
|
|
# 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"{}"',
|
|
'f"{\\}"',
|
|
'f"{\'\\\'}"',
|
|
'f"{#}"',
|
|
"f'{1!b}'",
|
|
"f'{1:{5:{3}}}'",
|
|
"f'{'",
|
|
"f'{'",
|
|
"f'}'",
|
|
"f'{\"}'",
|
|
"f'{\"}'",
|
|
# Now nested parsing
|
|
"f'{continue}'",
|
|
"f'{1;1}'",
|
|
"f'{a=3}'",
|
|
"f'{b\"\" \"\"}'",
|
|
]
|
|
|
|
GLOBAL_NONLOCAL_ERROR = [
|
|
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
|
|
'''),
|
|
]
|
|
|
|
if sys.version_info >= (3, 6):
|
|
FAILING_EXAMPLES += GLOBAL_NONLOCAL_ERROR
|
|
FAILING_EXAMPLES += [
|
|
# Raises multiple errors in previous versions.
|
|
'async def foo():\n def nofoo():[x async for x in []]',
|
|
]
|
|
if sys.version_info >= (3, 5):
|
|
FAILING_EXAMPLES += [
|
|
# Raises different errors so just ignore them for now.
|
|
'[*[] for a in [1]]',
|
|
# Raises multiple errors in previous versions.
|
|
'async def bla():\n def x(): await bla()',
|
|
]
|
|
if sys.version_info >= (3, 4):
|
|
# Before that del None works like del list, it gives a NameError.
|
|
FAILING_EXAMPLES.append('del None')
|
|
if sys.version_info >= (3,):
|
|
FAILING_EXAMPLES += [
|
|
# Unfortunately assigning to False and True do not raise an error in
|
|
# 2.x.
|
|
'(True,) = x',
|
|
'([False], a) = x',
|
|
# A symtable error that raises only a SyntaxWarning in Python 2.
|
|
'def x(): from math import *',
|
|
# unicode chars in bytes are allowed in python 2
|
|
'b"ä"',
|
|
# combining strings and unicode is allowed in Python 2.
|
|
'"s" b""',
|
|
]
|
|
if sys.version_info >= (2, 7):
|
|
# This is something that raises a different error in 2.6 than in the other
|
|
# versions. Just skip it for 2.6.
|
|
FAILING_EXAMPLES.append('[a, 1] += 3')
|
|
|
|
if sys.version_info[:2] == (3, 5):
|
|
# yields are not allowed in 3.5 async functions. Therefore test them
|
|
# separately, here.
|
|
FAILING_EXAMPLES += [
|
|
'async def foo():\n yield x',
|
|
'async def foo():\n yield x',
|
|
]
|
|
else:
|
|
FAILING_EXAMPLES += [
|
|
'async def foo():\n yield x\n return 1',
|
|
'async def foo():\n yield x\n return 1',
|
|
]
|
|
|
|
|
|
if sys.version_info[:2] <= (3, 4):
|
|
# Python > 3.4 this is valid code.
|
|
FAILING_EXAMPLES += [
|
|
'a = *[1], 2',
|
|
'(*[1], 2)',
|
|
]
|