PEP 3107 - Function Annotations thanks to Tony Lownds
diff --git a/Lib/test/output/test_tokenize b/Lib/test/output/test_tokenize
index 4a3d58c..a46824d 100644
--- a/Lib/test/output/test_tokenize
+++ b/Lib/test/output/test_tokenize
@@ -682,4 +682,20 @@
177,11-177,15: NAME 'pass'
177,15-177,16: NEWLINE '\n'
178,0-178,1: NL '\n'
-179,0-179,0: ENDMARKER ''
+179,0-179,1: OP '@'
+179,1-179,13: NAME 'staticmethod'
+179,13-179,14: NEWLINE '\n'
+180,0-180,3: NAME 'def'
+180,4-180,7: NAME 'foo'
+180,7-180,8: OP '('
+180,8-180,9: NAME 'x'
+180,9-180,10: OP ':'
+180,10-180,11: NUMBER '1'
+180,11-180,12: OP ')'
+180,12-180,14: OP '->'
+180,14-180,15: NUMBER '1'
+180,15-180,16: OP ':'
+180,17-180,21: NAME 'pass'
+180,21-180,22: NEWLINE '\n'
+181,0-181,1: NL '\n'
+182,0-182,0: ENDMARKER ''
diff --git a/Lib/test/test_ast.py b/Lib/test/test_ast.py
index 11623ec..914f1d9 100644
--- a/Lib/test/test_ast.py
+++ b/Lib/test/test_ast.py
@@ -151,9 +151,9 @@
#### EVERYTHING BELOW IS GENERATED #####
exec_results = [
-('Module', [('FunctionDef', (1, 0), 'f', ('arguments', [], None, [], None, [], []), [('Pass', (1, 9))], [])]),
+('Module', [('FunctionDef', (1, 0), 'f', ('arguments', [], None, None, [], None, None, [], []), [('Pass', (1, 9))], [], None)]),
('Module', [('ClassDef', (1, 0), 'C', [], [('Pass', (1, 8))])]),
-('Module', [('FunctionDef', (1, 0), 'f', ('arguments', [], None, [], None, [], []), [('Return', (1, 8), ('Num', (1, 15), 1))], [])]),
+('Module', [('FunctionDef', (1, 0), 'f', ('arguments', [], None, None, [], None, None, [], []), [('Return', (1, 8), ('Num', (1, 15), 1))], [], None)]),
('Module', [('Delete', (1, 0), [('Name', (1, 4), 'v', ('Del',))])]),
('Module', [('Assign', (1, 0), [('Name', (1, 0), 'v', ('Store',))], ('Num', (1, 4), 1))]),
('Module', [('AugAssign', (1, 0), ('Name', (1, 0), 'v', ('Store',)), ('Add',), ('Num', (1, 5), 1))]),
@@ -180,13 +180,13 @@
('Expression', ('BoolOp', (1, 0), ('And',), [('Name', (1, 0), 'a', ('Load',)), ('Name', (1, 6), 'b', ('Load',))])),
('Expression', ('BinOp', (1, 0), ('Name', (1, 0), 'a', ('Load',)), ('Add',), ('Name', (1, 4), 'b', ('Load',)))),
('Expression', ('UnaryOp', (1, 0), ('Not',), ('Name', (1, 4), 'v', ('Load',)))),
-('Expression', ('Lambda', (1, 0), ('arguments', [], None, [], None, [], []), ('Name', (1, 7), 'None', ('Load',)))),
+('Expression', ('Lambda', (1, 0), ('arguments', [], None, None, [], None, None, [], []), ('Name', (1, 7), 'None', ('Load',)))),
('Expression', ('Dict', (1, 0), [('Num', (1, 2), 1)], [('Num', (1, 4), 2)])),
('Expression', ('ListComp', (1, 1), ('Name', (1, 1), 'a', ('Load',)), [('comprehension', ('Name', (1, 7), 'b', ('Store',)), ('Name', (1, 12), 'c', ('Load',)), [('Name', (1, 17), 'd', ('Load',))])])),
('Expression', ('GeneratorExp', (1, 1), ('Name', (1, 1), 'a', ('Load',)), [('comprehension', ('Name', (1, 7), 'b', ('Store',)), ('Name', (1, 12), 'c', ('Load',)), [('Name', (1, 17), 'd', ('Load',))])])),
('Expression', ('Compare', (1, 0), ('Num', (1, 0), 1), [('Lt',), ('Lt',)], [('Num', (1, 4), 2), ('Num', (1, 8), 3)])),
('Expression', ('Call', (1, 0), ('Name', (1, 0), 'f', ('Load',)), [('Num', (1, 2), 1), ('Num', (1, 4), 2)], [('keyword', 'c', ('Num', (1, 8), 3))], ('Name', (1, 11), 'd', ('Load',)), ('Name', (1, 15), 'e', ('Load',)))),
-('Expression', ('Num', (1, 0), 10L)),
+('Expression', ('Num', (1, 0), 10)),
('Expression', ('Str', (1, 0), 'string')),
('Expression', ('Attribute', (1, 0), ('Name', (1, 0), 'a', ('Load',)), 'b', ('Load',))),
('Expression', ('Subscript', (1, 0), ('Name', (1, 0), 'a', ('Load',)), ('Slice', ('Name', (1, 2), 'b', ('Load',)), ('Name', (1, 4), 'c', ('Load',)), None), ('Load',))),
diff --git a/Lib/test/test_compiler.py b/Lib/test/test_compiler.py
index 783a34c..2ecd093 100644
--- a/Lib/test/test_compiler.py
+++ b/Lib/test/test_compiler.py
@@ -115,6 +115,24 @@
dct = {}
exec(c, dct)
self.assertEquals(dct.get('result'), 3)
+ c = compiler.compile('def g(a):\n'
+ ' def f(): return a + 2\n'
+ ' return f()\n'
+ 'result = g(1)',
+ '<string>',
+ 'exec')
+ dct = {}
+ exec(c, dct)
+ self.assertEquals(dct.get('result'), 3)
+ c = compiler.compile('def g((a, b)):\n'
+ ' def f(): return a + b\n'
+ ' return f()\n'
+ 'result = g((1, 2))',
+ '<string>',
+ 'exec')
+ dct = {}
+ exec(c, dct)
+ self.assertEquals(dct.get('result'), 3)
def testGenExp(self):
c = compiler.compile('list((i,j) for i in range(3) if i < 3'
@@ -123,6 +141,22 @@
'eval')
self.assertEquals(eval(c), [(0, 3), (1, 3), (2, 3)])
+ def testFuncAnnotations(self):
+ testdata = [
+ ('def f(a: 1): pass', {'a': 1}),
+ ('''def f(a, (b:1, c:2, d), e:3=4, f=5,
+ *g:6, h:7, i=8, j:9=10, **k:11) -> 12: pass
+ ''', {'b': 1, 'c': 2, 'e': 3, 'g': 6, 'h': 7, 'j': 9,
+ 'k': 11, 'return': 12}),
+ ]
+ for sourcecode, expected in testdata:
+ # avoid IndentationError: unexpected indent from trailing lines
+ sourcecode = sourcecode.rstrip()+'\n'
+ c = compiler.compile(sourcecode, '<string>', 'exec')
+ dct = {}
+ exec(c, dct)
+ self.assertEquals(dct['f'].func_annotations, expected)
+
NOLINENO = (compiler.ast.Module, compiler.ast.Stmt, compiler.ast.Discard)
@@ -167,10 +201,11 @@
###############################################################################
-def test_main():
+def test_main(all=False):
global TEST_ALL
- TEST_ALL = test.test_support.is_resource_enabled("compiler")
+ TEST_ALL = all or test.test_support.is_resource_enabled("compiler")
test.test_support.run_unittest(CompilerTest)
if __name__ == "__main__":
- test_main()
+ import sys
+ test_main('all' in sys.argv)
diff --git a/Lib/test/test_grammar.py b/Lib/test/test_grammar.py
index f4a0478..34c550e 100644
--- a/Lib/test/test_grammar.py
+++ b/Lib/test/test_grammar.py
@@ -138,16 +138,22 @@
x = eval('1, 0 or 1')
def testFuncdef(self):
- ### 'def' NAME parameters ':' suite
- ### parameters: '(' [varargslist] ')'
- ### varargslist: (fpdef ['=' test] ',')*
- ### ('*' (NAME|',' fpdef ['=' test]) [',' ('**'|'*' '*') NAME]
- ### | ('**'|'*' '*') NAME)
- ### | fpdef ['=' test] (',' fpdef ['=' test])* [',']
- ### fpdef: NAME | '(' fplist ')'
- ### fplist: fpdef (',' fpdef)* [',']
- ### arglist: (argument ',')* (argument | *' test [',' '**' test] | '**' test)
- ### argument: [test '='] test # Really [keyword '='] test
+ ### [decorators] 'def' NAME parameters ['->' test] ':' suite
+ ### decorator: '@' dotted_name [ '(' [arglist] ')' ] NEWLINE
+ ### decorators: decorator+
+ ### parameters: '(' [typedargslist] ')'
+ ### typedargslist: ((tfpdef ['=' test] ',')*
+ ### ('*' [tname] (',' tname ['=' test])* [',' '**' tname] | '**' tname)
+ ### | tfpdef ['=' test] (',' tfpdef ['=' test])* [','])
+ ### tname: NAME [':' test]
+ ### tfpdef: tname | '(' tfplist ')'
+ ### tfplist: tfpdef (',' tfpdef)* [',']
+ ### varargslist: ((vfpdef ['=' test] ',')*
+ ### ('*' [vname] (',' vname ['=' test])* [',' '**' vname] | '**' vname)
+ ### | vfpdef ['=' test] (',' vfpdef ['=' test])* [','])
+ ### vname: NAME
+ ### vfpdef: vname | '(' vfplist ')'
+ ### vfplist: vfpdef (',' vfpdef)* [',']
def f1(): pass
f1()
f1(*())
@@ -294,6 +300,28 @@
pos2key2dict(1,2,k2=100,tokwarg1=100,tokwarg2=200)
pos2key2dict(1,2,tokwarg1=100,tokwarg2=200, k2=100)
+ # argument annotation tests
+ def f(x) -> list: pass
+ self.assertEquals(f.func_annotations, {'return': list})
+ def f(x:int): pass
+ self.assertEquals(f.func_annotations, {'x': int})
+ def f(*x:str): pass
+ self.assertEquals(f.func_annotations, {'x': str})
+ def f(**x:float): pass
+ self.assertEquals(f.func_annotations, {'x': float})
+ def f(x, y:1+2): pass
+ self.assertEquals(f.func_annotations, {'y': 3})
+ def f(a, (b:1, c:2, d)): pass
+ self.assertEquals(f.func_annotations, {'b': 1, 'c': 2})
+ def f(a, (b:1, c:2, d), e:3=4, f=5, *g:6): pass
+ self.assertEquals(f.func_annotations,
+ {'b': 1, 'c': 2, 'e': 3, 'g': 6})
+ def f(a, (b:1, c:2, d), e:3=4, f=5, *g:6, h:7, i=8, j:9=10,
+ **k:11) -> 12: pass
+ self.assertEquals(f.func_annotations,
+ {'b': 1, 'c': 2, 'e': 3, 'g': 6, 'h': 7, 'j': 9,
+ 'k': 11, 'return': 12})
+
def testLambdef(self):
### lambdef: 'lambda' [varargslist] ':' test
l1 = lambda : 0
diff --git a/Lib/test/test_tokenize.py b/Lib/test/test_tokenize.py
index be6c18d..de6e888 100644
--- a/Lib/test/test_tokenize.py
+++ b/Lib/test/test_tokenize.py
@@ -219,5 +219,15 @@
if verbose:
print 'finished'
+def test_rarrow():
+ """
+ This function exists solely to test the tokenization of the RARROW
+ operator.
+
+ >>> tokenize(iter(['->']).next) #doctest: +NORMALIZE_WHITESPACE
+ 1,0-1,2:\tOP\t'->'
+ 2,0-2,0:\tENDMARKER\t''
+ """
+
if __name__ == "__main__":
test_main()
diff --git a/Lib/test/tokenize_tests.txt b/Lib/test/tokenize_tests.txt
index 1facfc1..b1aa020 100644
--- a/Lib/test/tokenize_tests.txt
+++ b/Lib/test/tokenize_tests.txt
@@ -176,3 +176,6 @@
@staticmethod
def foo(): pass
+@staticmethod
+def foo(x:1)->1: pass
+