bpo-32482: Improve syntax and grammar tests. (#5085)
diff --git a/Lib/test/test_grammar.py b/Lib/test/test_grammar.py
index 47b6b3e..23b6ce8 100644
--- a/Lib/test/test_grammar.py
+++ b/Lib/test/test_grammar.py
@@ -11,7 +11,7 @@
class TokenTests(unittest.TestCase):
- def testBackslash(self):
+ def test_backslash(self):
# Backslash means line continuation:
x = 1 \
+ 1
@@ -21,29 +21,42 @@
x = 0
self.assertEqual(x, 0, 'backslash ending comment')
- def testPlainIntegers(self):
+ def test_plain_integers(self):
+ self.assertEqual(type(000), type(0))
self.assertEqual(0xff, 255)
self.assertEqual(0377, 255)
+ self.assertEqual(0o377, 255)
self.assertEqual(2147483647, 017777777777)
+ self.assertEqual(2147483647, 0o17777777777)
+ self.assertEqual(0b1001, 9)
# "0x" is not a valid literal
self.assertRaises(SyntaxError, eval, "0x")
from sys import maxint
if maxint == 2147483647:
- self.assertEqual(-2147483647-1, -020000000000)
+ self.assertEqual(-2147483647-1, -0o20000000000)
# XXX -2147483648
self.assertTrue(037777777777 > 0)
+ self.assertTrue(0o37777777777 > 0)
self.assertTrue(0xffffffff > 0)
- for s in '2147483648', '040000000000', '0x100000000':
+ self.assertTrue(0b1111111111111111111111111111111 > 0)
+ for s in ('2147483648', '040000000000', '0o40000000000',
+ '0x100000000',
+ '0b10000000000000000000000000000000'):
try:
x = eval(s)
except OverflowError:
self.fail("OverflowError on huge integer literal %r" % s)
elif maxint == 9223372036854775807:
self.assertEqual(-9223372036854775807-1, -01000000000000000000000)
+ self.assertEqual(-9223372036854775807-1, -0o1000000000000000000000)
self.assertTrue(01777777777777777777777 > 0)
+ self.assertTrue(0o1777777777777777777777 > 0)
self.assertTrue(0xffffffffffffffff > 0)
+ self.assertTrue(0b11111111111111111111111111111111111111111111111111111111111111 > 0)
for s in '9223372036854775808', '02000000000000000000000', \
- '0x10000000000000000':
+ '0o2000000000000000000000', \
+ '0x10000000000000000', \
+ '0b100000000000000000000000000000000000000000000000000000000000000':
try:
x = eval(s)
except OverflowError:
@@ -51,7 +64,7 @@
else:
self.fail('Weird maxint value %r' % maxint)
- def testLongIntegers(self):
+ def test_long_integers(self):
x = 0L
x = 0l
x = 0xffffffffffffffffL
@@ -61,7 +74,7 @@
x = 123456789012345678901234567890L
x = 123456789012345678901234567890l
- def testFloats(self):
+ def test_floats(self):
x = 3.14
x = 314.
x = 0.314
@@ -81,7 +94,7 @@
self.assertEqual(1 if 0else 0, 0)
self.assertRaises(SyntaxError, eval, "0 if 1Else 0")
- def testStringLiterals(self):
+ def test_string_literals(self):
x = ''; y = ""; self.assertTrue(len(x) == 0 and x == y)
x = '\''; y = "'"; self.assertTrue(len(x) == 1 and x == y and ord(x) == 39)
x = '"'; y = "\""; self.assertTrue(len(x) == 1 and x == y and ord(x) == 34)
@@ -133,11 +146,11 @@
# expr_input: testlist NEWLINE
# XXX Hard to test -- used only in calls to input()
- def testEvalInput(self):
+ def test_eval_input(self):
# testlist ENDMARKER
x = eval('1, 0 or 1')
- def testFuncdef(self):
+ def test_funcdef(self):
### 'def' NAME parameters ':' suite
### parameters: '(' [varargslist] ')'
### varargslist: (fpdef ['=' test] ',')* ('*' NAME [',' ('**'|'*' '*') NAME]
@@ -153,9 +166,10 @@
f1(*(), **{})
def f2(one_argument): pass
def f3(two, arguments): pass
- # Silence Py3k warning
- exec('def f4(two, (compound, (argument, list))): pass')
- exec('def f5((compound, first), two): pass')
+ with check_py3k_warnings(('tuple parameter unpacking has been removed',
+ SyntaxWarning)):
+ exec('def f4(two, (compound, (argument, list))): pass')
+ exec('def f5((compound, first), two): pass')
self.assertEqual(f2.func_code.co_varnames, ('one_argument',))
self.assertEqual(f3.func_code.co_varnames, ('two', 'arguments'))
if sys.platform.startswith('java'):
@@ -174,8 +188,9 @@
def v0(*rest): pass
def v1(a, *rest): pass
def v2(a, b, *rest): pass
- # Silence Py3k warning
- exec('def v3(a, (b, c), *rest): return a, b, c, rest')
+ with check_py3k_warnings(('tuple parameter unpacking has been removed',
+ SyntaxWarning)):
+ exec('def v3(a, (b, c), *rest): return a, b, c, rest')
f1()
f2(1)
@@ -212,7 +227,9 @@
d01()
d01(1)
d01(*(1,))
+ d01(*[] or [2])
d01(**{'a':2})
+ d01(**{'a':2} or {})
def d11(a, b=1): pass
d11(1)
d11(1, 2)
@@ -280,9 +297,12 @@
d22v(*(1, 2, 3, 4))
d22v(1, 2, *(3, 4, 5))
d22v(1, *(2, 3), **{'d': 4})
- # Silence Py3k warning
- exec('def d31v((x)): pass')
- exec('def d32v((x,)): pass')
+ with check_py3k_warnings(('parenthesized argument names are invalid',
+ SyntaxWarning)):
+ exec('def d31v((x)): pass')
+ with check_py3k_warnings(('tuple parameter unpacking has been removed',
+ SyntaxWarning)):
+ exec('def d32v((x,)): pass')
d31v(1)
d32v((1,))
@@ -293,12 +313,19 @@
{'x':2, 'y':5}))
self.assertRaises(SyntaxError, eval, "f(1, *(2,3), 4)")
self.assertRaises(SyntaxError, eval, "f(1, x=2, *(3,4), x=5)")
+ self.assertEqual(f(**{'eggs':'scrambled', 'spam':'fried'}),
+ ((), {'eggs':'scrambled', 'spam':'fried'}))
+ self.assertEqual(f(spam='fried', **{'eggs':'scrambled'}),
+ ((), {'eggs':'scrambled', 'spam':'fried'}))
# Check ast errors in *args and *kwargs
check_syntax_error(self, "f(*g(1=2))")
check_syntax_error(self, "f(**g(1=2))")
- def testLambdef(self):
+ # Check trailing commas are permitted in funcdef argument list
+ def f(a,): pass
+
+ def test_lambdef(self):
### lambdef: 'lambda' [varargslist] ':' test
l1 = lambda : 0
self.assertEqual(l1(), 0)
@@ -311,12 +338,18 @@
self.assertEqual(l5(1, 2), 5)
self.assertEqual(l5(1, 2, 3), 6)
check_syntax_error(self, "lambda x: x = 2")
- check_syntax_error(self, "lambda (None,): None")
+ with check_py3k_warnings(('tuple parameter unpacking has been removed',
+ SyntaxWarning)):
+ check_syntax_error(self, "lambda (None,): None")
+
+ # check that trailing commas are permitted
+ l10 = lambda a,: 0
+
### stmt: simple_stmt | compound_stmt
# Tested below
- def testSimpleStmt(self):
+ def test_simple_stmt(self):
### simple_stmt: small_stmt (';' small_stmt)* [';']
x = 1; pass; del x
def foo():
@@ -327,7 +360,7 @@
### small_stmt: expr_stmt | print_stmt | pass_stmt | del_stmt | flow_stmt | import_stmt | global_stmt | access_stmt | exec_stmt
# Tested below
- def testExprStmt(self):
+ def test_expr_stmt(self):
# (exprlist '=')* exprlist
1
1, 2, 3
@@ -340,7 +373,7 @@
check_syntax_error(self, "x + 1 = 1")
check_syntax_error(self, "a + 1 = b + 2")
- def testPrintStmt(self):
+ def test_print_stmt(self):
# 'print' (test ',')* [test]
import StringIO
@@ -410,7 +443,7 @@
check_syntax_error(self, 'print ,')
check_syntax_error(self, 'print >> x,')
- def testDelStmt(self):
+ def test_del_stmt(self):
# 'del' exprlist
abc = [1,2,3]
x, y, z = abc
@@ -419,18 +452,18 @@
del abc
del x, y, (z, xyz)
- def testPassStmt(self):
+ def test_pass_stmt(self):
# 'pass'
pass
# flow_stmt: break_stmt | continue_stmt | return_stmt | raise_stmt
# Tested below
- def testBreakStmt(self):
+ def test_break_stmt(self):
# 'break'
while 1: break
- def testContinueStmt(self):
+ def test_continue_stmt(self):
# 'continue'
i = 1
while i: i = 0; continue
@@ -482,7 +515,7 @@
self.fail("continue then break in try/except in loop broken!")
test_inner()
- def testReturn(self):
+ def test_return(self):
# 'return' [testlist]
def g1(): return
def g2(): return 1
@@ -513,7 +546,7 @@
while count < 2:
count += 1
try:
- 1/0
+ 1.0/0.0
finally:
break
self.assertEqual(count, 1)
@@ -537,7 +570,7 @@
for count in [0, 1]:
self.assertEqual(count, 0)
try:
- 1/0
+ 1.0/0.0
finally:
break
self.assertEqual(count, 0)
@@ -559,13 +592,33 @@
def g3():
try:
- 1/0
+ 1.0/0.0
finally:
return 4
self.assertEqual(g3(), 4)
- def testYield(self):
+ def test_yield(self):
+ # Allowed as standalone statement
+ def g(): yield 1
+ # Allowed as RHS of assignment
+ def g(): x = yield 1
+ # Ordinary yield accepts implicit tuples
+ def g(): yield 1, 1
+ def g(): x = yield 1, 1
+ # Requires parentheses as subexpression
+ def g(): 1, (yield 1)
+ check_syntax_error(self, "def g(): 1, yield 1")
+ # Requires parentheses as call argument
+ def g(): f((yield 1))
+ def g(): f((yield 1), 1)
+ check_syntax_error(self, "def g(): f(yield 1)")
+ check_syntax_error(self, "def g(): f(yield 1, 1)")
+ # Not allowed at top level
+ check_syntax_error(self, "yield")
+ # Not allowed at class scope
check_syntax_error(self, "class foo:yield 1")
+ # Check annotation refleak on SyntaxError
+ check_syntax_error(self, "def g(a:(yield)): pass")
def test_yield_in_comprehensions(self):
# Check yield in comprehensions
@@ -607,14 +660,14 @@
check("((yield x) for x in ())",
"'yield' inside generator expression")
- def testRaise(self):
+ def test_raise(self):
# 'raise' test [',' test]
try: raise RuntimeError, 'just testing'
except RuntimeError: pass
try: raise KeyboardInterrupt
except KeyboardInterrupt: pass
- def testImport(self):
+ def test_import(self):
# 'import' dotted_as_names
import sys
import time, sys
@@ -627,13 +680,13 @@
from sys import (path, argv)
from sys import (path, argv,)
- def testGlobal(self):
+ def test_global(self):
# 'global' NAME (',' NAME)*
global a
global a, b
global one, two, three, four, five, six, seven, eight, nine, ten
- def testExec(self):
+ def test_exec(self):
# 'exec' expr ['in' expr [',' expr]]
z = None
del z
@@ -665,7 +718,7 @@
if (g, l) != ({'a':1}, {'b':2}):
self.fail('exec ... in g (%s), l (%s)' %(g,l))
- def testAssert(self):
+ def test_assert(self):
# assertTruestmt: 'assert' test [',' test]
assert 1
assert 1, 1
@@ -704,7 +757,7 @@
### compound_stmt: if_stmt | while_stmt | for_stmt | try_stmt | funcdef | classdef
# Tested below
- def testIf(self):
+ def test_if(self):
# 'if' test ':' suite ('elif' test ':' suite)* ['else' ':' suite]
if 1: pass
if 1: pass
@@ -717,7 +770,7 @@
elif 0: pass
else: pass
- def testWhile(self):
+ def test_while(self):
# 'while' test ':' suite ['else' ':' suite]
while 0: pass
while 0: pass
@@ -732,7 +785,7 @@
x = 2
self.assertEqual(x, 2)
- def testFor(self):
+ def test_for(self):
# 'for' exprlist 'in' exprlist ':' suite ['else' ':' suite]
for i in 1, 2, 3: pass
for i, j, k in (): pass
@@ -759,30 +812,30 @@
result.append(x)
self.assertEqual(result, [1, 2, 3])
- def testTry(self):
+ def test_try(self):
### try_stmt: 'try' ':' suite (except_clause ':' suite)+ ['else' ':' suite]
### | 'try' ':' suite 'finally' ':' suite
### except_clause: 'except' [expr [('as' | ',') expr]]
try:
- 1/0
+ 1/0.0
except ZeroDivisionError:
pass
else:
pass
- try: 1/0
+ try: 1/0.0
except EOFError: pass
except TypeError as msg: pass
except RuntimeError, msg: pass
except: pass
else: pass
- try: 1/0
+ try: 1/0.0
except (EOFError, TypeError, ZeroDivisionError): pass
- try: 1/0
+ try: 1/0.0
except (EOFError, TypeError, ZeroDivisionError), msg: pass
try: pass
finally: pass
- def testSuite(self):
+ def test_suite(self):
# simple_stmt | NEWLINE INDENT NEWLINE* (stmt NEWLINE*)+ DEDENT
if 1: pass
if 1:
@@ -797,7 +850,7 @@
pass
#
- def testTest(self):
+ def test_test(self):
### and_test ('or' and_test)*
### and_test: not_test ('and' not_test)*
### not_test: 'not' not_test | comparison
@@ -808,7 +861,7 @@
if not 1 and 1 and 1: pass
if 1 and 1 or 1 and 1 and 1 or not 1 and 1: pass
- def testComparison(self):
+ def test_comparison(self):
### comparison: expr (comp_op expr)*
### comp_op: '<'|'>'|'=='|'>='|'<='|'<>'|'!='|'in'|'not' 'in'|'is'|'is' 'not'
if 1: pass
@@ -824,40 +877,49 @@
if 1 in (): pass
if 1 not in (): pass
if 1 < 1 > 1 == 1 >= 1 <= 1 != 1 in 1 not in 1 is 1 is not 1: pass
- # Silence Py3k warning
- if eval('1 <> 1'): pass
- if eval('1 < 1 > 1 == 1 >= 1 <= 1 <> 1 != 1 in 1 not in 1 is 1 is not 1'): pass
+ with check_py3k_warnings(('<> not supported in 3.x; use !=',
+ DeprecationWarning)):
+ if eval('1 <> 1'): pass
+ with check_py3k_warnings(('<> not supported in 3.x; use !=',
+ DeprecationWarning)):
+ if eval('1 < 1 > 1 == 1 >= 1 <= 1 <> 1 != 1 in 1 not in 1 is 1 is not 1'): pass
- def testBinaryMaskOps(self):
+ def test_binary_mask_ops(self):
x = 1 & 1
x = 1 ^ 1
x = 1 | 1
- def testShiftOps(self):
+ def test_shift_ops(self):
x = 1 << 1
x = 1 >> 1
x = 1 << 1 >> 1
- def testAdditiveOps(self):
+ def test_additive_ops(self):
x = 1
x = 1 + 1
x = 1 - 1 - 1
x = 1 - 1 + 1 - 1 + 1
- def testMultiplicativeOps(self):
+ def test_multiplicative_ops(self):
x = 1 * 1
- x = 1 / 1
+ with check_py3k_warnings(('classic int division', DeprecationWarning)):
+ x = 1 / 1
+ x = 1 / 1.0
x = 1 % 1
- x = 1 / 1 * 1 % 1
+ with check_py3k_warnings(('classic int division', DeprecationWarning)):
+ x = 1 / 1 * 1 % 1
+ x = 1 / 1.0 * 1 % 1
- def testUnaryOps(self):
+ def test_unary_ops(self):
x = +1
x = -1
x = ~1
x = ~1 ^ 1 & 1 | 1 & 1 ^ -1
- x = -1*1/1 + 1*1 - ---1*1
+ with check_py3k_warnings(('classic int division', DeprecationWarning)):
+ x = -1*1/1 + 1*1 - ---1*1
+ x = -1*1/1.0 + 1*1 - ---1*1
- def testSelectors(self):
+ def test_selectors(self):
### trailer: '(' [testlist] ')' | '[' subscript ']' | '.' NAME
### subscript: expr | [expr] ':' [expr]
@@ -884,10 +946,10 @@
d[1,2] = 3
d[1,2,3] = 4
L = list(d)
- L.sort()
+ L.sort(key=lambda x: (type(x).__name__, x))
self.assertEqual(str(L), '[1, (1,), (1, 2), (1, 2, 3)]')
- def testAtoms(self):
+ def test_atoms(self):
### atom: '(' [testlist] ')' | '[' [testlist] ']' | '{' [dictmaker] '}' | '`' testlist '`' | NAME | NUMBER | STRING
### dictorsetmaker: (test ':' test (',' test ':' test)* [',']) | (test (',' test)* [','])
@@ -914,10 +976,10 @@
x = {'one', 'two', 'three'}
x = {2, 3, 4,}
- # Silence Py3k warning
- x = eval('`x`')
- x = eval('`1 or 2 or 3`')
- self.assertEqual(eval('`1,2`'), '(1, 2)')
+ with check_py3k_warnings(('backquote not supported', SyntaxWarning)):
+ x = eval('`x`')
+ x = eval('`1 or 2 or 3`')
+ self.assertEqual(eval('`1,2`'), '(1, 2)')
x = x
x = 'x'
@@ -927,7 +989,7 @@
### testlist: test (',' test)* [',']
# These have been exercised enough above
- def testClassdef(self):
+ def test_classdef(self):
# 'class' NAME ['(' [testlist] ')'] ':' suite
class B: pass
class B2(): pass
@@ -938,6 +1000,7 @@
def meth1(self): pass
def meth2(self, arg): pass
def meth3(self, a1, a2): pass
+
# decorator: '@' dotted_name [ '(' [arglist] ')' ] NEWLINE
# decorators: decorator+
# decorated: decorators (classdef | funcdef)
@@ -949,14 +1012,14 @@
pass
self.assertEqual(G.decorated, True)
- def testDictcomps(self):
+ def test_dictcomps(self):
# dictorsetmaker: ( (test ':' test (comp_for |
# (',' test ':' test)* [','])) |
# (test (comp_for | (',' test)* [','])) )
nums = [1, 2, 3]
self.assertEqual({i:i+1 for i in nums}, {1: 2, 2: 3, 3: 4})
- def testListcomps(self):
+ def test_listcomps(self):
# list comprehension tests
nums = [1, 2, 3, 4, 5]
strs = ["Apple", "Banana", "Coconut"]
@@ -979,7 +1042,7 @@
[[1], [1, 1], [1, 2, 4], [1, 3, 9, 27], [1, 4, 16, 64, 256]])
def test_in_func(l):
- return [None < x < 3 for x in l if x > 2]
+ return [0 < x < 3 for x in l if x > 2]
self.assertEqual(test_in_func(nums), [False, False, False])
@@ -1019,7 +1082,7 @@
self.assertEqual(x, [('Boeing', 'Airliner'), ('Boeing', 'Engine'), ('Ford', 'Engine'),
('Macdonalds', 'Cheeseburger')])
- def testGenexps(self):
+ def test_genexps(self):
# generator expression tests
g = ([x for x in range(10)] for x in range(1))
self.assertEqual(g.next(), [x for x in range(10)])
@@ -1054,7 +1117,7 @@
check_syntax_error(self, "foo(x for x in range(10), 100)")
check_syntax_error(self, "foo(100, x for x in range(10))")
- def testComprehensionSpecials(self):
+ def test_comprehension_specials(self):
# test for outmost iterable precomputation
x = 10; g = (i for i in range(x)); x = 5
self.assertEqual(len(list(g)), 10)
@@ -1093,11 +1156,11 @@
with manager() as x, manager():
pass
- def testIfElseExpr(self):
+ def test_if_else_expr(self):
# Test ifelse expressions in various cases
def _checkeval(msg, ret):
"helper to check that evaluation of expressions is done correctly"
- print x
+ print(msg)
return ret
self.assertEqual([ x() for x in lambda: True, lambda: False if x() ], [True])
@@ -1116,7 +1179,8 @@
self.assertEqual((6 + 1 if 1 else 2), 7)
self.assertEqual((6 - 1 if 1 else 2), 5)
self.assertEqual((6 * 2 if 1 else 4), 12)
- self.assertEqual((6 / 2 if 1 else 3), 3)
+ with check_py3k_warnings(('classic int division', DeprecationWarning)):
+ self.assertEqual((6 / 2 if 1 else 3), 3)
self.assertEqual((6 < 4 if 0 else 2), 2)
def test_paren_evaluation(self):
@@ -1129,13 +1193,7 @@
def test_main():
- with check_py3k_warnings(
- ("backquote not supported", SyntaxWarning),
- ("tuple parameter unpacking has been removed", SyntaxWarning),
- ("parenthesized argument names are invalid", SyntaxWarning),
- ("classic int division", DeprecationWarning),
- (".+ not supported in 3.x", DeprecationWarning)):
- run_unittest(TokenTests, GrammarTests)
+ run_unittest(TokenTests, GrammarTests)
if __name__ == '__main__':
test_main()