Commit a0c01bf1 authored by Pablo Galindo's avatar Pablo Galindo Committed by GitHub

bpo-37115: Support annotations in positional-only arguments (GH-13698)

parent 2f58a841
...@@ -620,14 +620,22 @@ class GrammarTests(unittest.TestCase): ...@@ -620,14 +620,22 @@ class GrammarTests(unittest.TestCase):
self.assertEqual(f.__annotations__, {'return': list}) self.assertEqual(f.__annotations__, {'return': list})
def f(x: int): pass def f(x: int): pass
self.assertEqual(f.__annotations__, {'x': int}) self.assertEqual(f.__annotations__, {'x': int})
def f(x: int, /): pass
self.assertEqual(f.__annotations__, {'x': int})
def f(x: int = 34, /): pass
self.assertEqual(f.__annotations__, {'x': int})
def f(*x: str): pass def f(*x: str): pass
self.assertEqual(f.__annotations__, {'x': str}) self.assertEqual(f.__annotations__, {'x': str})
def f(**x: float): pass def f(**x: float): pass
self.assertEqual(f.__annotations__, {'x': float}) self.assertEqual(f.__annotations__, {'x': float})
def f(x, y: 1+2): pass def f(x, y: 1+2): pass
self.assertEqual(f.__annotations__, {'y': 3}) self.assertEqual(f.__annotations__, {'y': 3})
def f(x, y: 1+2, /): pass
self.assertEqual(f.__annotations__, {'y': 3})
def f(a, b: 1, c: 2, d): pass def f(a, b: 1, c: 2, d): pass
self.assertEqual(f.__annotations__, {'b': 1, 'c': 2}) self.assertEqual(f.__annotations__, {'b': 1, 'c': 2})
def f(a, b: 1, /, c: 2, d): pass
self.assertEqual(f.__annotations__, {'b': 1, 'c': 2})
def f(a, b: 1, c: 2, d, e: 3 = 4, f=5, *g: 6): pass def f(a, b: 1, c: 2, d, e: 3 = 4, f=5, *g: 6): pass
self.assertEqual(f.__annotations__, self.assertEqual(f.__annotations__,
{'b': 1, 'c': 2, 'e': 3, 'g': 6}) {'b': 1, 'c': 2, 'e': 3, 'g': 6})
...@@ -636,6 +644,11 @@ class GrammarTests(unittest.TestCase): ...@@ -636,6 +644,11 @@ class GrammarTests(unittest.TestCase):
self.assertEqual(f.__annotations__, self.assertEqual(f.__annotations__,
{'b': 1, 'c': 2, 'e': 3, 'g': 6, 'h': 7, 'j': 9, {'b': 1, 'c': 2, 'e': 3, 'g': 6, 'h': 7, 'j': 9,
'k': 11, 'return': 12}) 'k': 11, 'return': 12})
def f(a, b: 1, c: 2, d, e: 3 = 4, f: int = 5, /, *g: 6, h: 7, i=8, j: 9 = 10,
**k: 11) -> 12: pass
self.assertEqual(f.__annotations__,
{'b': 1, 'c': 2, 'e': 3, 'f': int, 'g': 6, 'h': 7, 'j': 9,
'k': 11, 'return': 12})
# Check for issue #20625 -- annotations mangling # Check for issue #20625 -- annotations mangling
class Spam: class Spam:
def f(self, *, __kw: 1): def f(self, *, __kw: 1):
......
...@@ -99,12 +99,25 @@ def fa( ...@@ -99,12 +99,25 @@ def fa(
): ):
pass pass
def fa(
a = 1, # type: A
/
):
pass
def fab( def fab(
a, # type: A a, # type: A
b, # type: B b, # type: B
): ):
pass pass
def fab(
a, # type: A
/,
b, # type: B
):
pass
def fab( def fab(
a, # type: A a, # type: A
b # type: B b # type: B
...@@ -149,6 +162,13 @@ def fav( ...@@ -149,6 +162,13 @@ def fav(
): ):
pass pass
def fav(
a, # type: A
/,
*v, # type: V
):
pass
def fav( def fav(
a, # type: A a, # type: A
*v # type: V *v # type: V
...@@ -161,6 +181,13 @@ def fak( ...@@ -161,6 +181,13 @@ def fak(
): ):
pass pass
def fak(
a, # type: A
/,
**k, # type: K
):
pass
def fak( def fak(
a, # type: A a, # type: A
**k # type: K **k # type: K
...@@ -174,6 +201,14 @@ def favk( ...@@ -174,6 +201,14 @@ def favk(
): ):
pass pass
def favk(
a, # type: A
/,
*v, # type: V
**k, # type: K
):
pass
def favk( def favk(
a, # type: A a, # type: A
*v, # type: V *v, # type: V
...@@ -290,18 +325,21 @@ class TypeCommentTests(unittest.TestCase): ...@@ -290,18 +325,21 @@ class TypeCommentTests(unittest.TestCase):
for t in tree.body: for t in tree.body:
# The expected args are encoded in the function name # The expected args are encoded in the function name
todo = set(t.name[1:]) todo = set(t.name[1:])
self.assertEqual(len(t.args.args), self.assertEqual(len(t.args.args) + len(t.args.posonlyargs),
len(todo) - bool(t.args.vararg) - bool(t.args.kwarg)) len(todo) - bool(t.args.vararg) - bool(t.args.kwarg))
self.assertTrue(t.name.startswith('f'), t.name) self.assertTrue(t.name.startswith('f'), t.name)
for c in t.name[1:]: for index, c in enumerate(t.name[1:]):
todo.remove(c) todo.remove(c)
if c == 'v': if c == 'v':
arg = t.args.vararg arg = t.args.vararg
elif c == 'k': elif c == 'k':
arg = t.args.kwarg arg = t.args.kwarg
else: else:
assert 0 <= ord(c) - ord('a') < len(t.args.args) assert 0 <= ord(c) - ord('a') < len(t.args.posonlyargs + t.args.args)
arg = t.args.args[ord(c) - ord('a')] if index < len(t.args.posonlyargs):
arg = t.args.posonlyargs[ord(c) - ord('a')]
else:
arg = t.args.args[ord(c) - ord('a') - len(t.args.posonlyargs)]
self.assertEqual(arg.arg, c) # That's the argument name self.assertEqual(arg.arg, c) # That's the argument name
self.assertEqual(arg.type_comment, arg.arg.upper()) self.assertEqual(arg.type_comment, arg.arg.upper())
assert not todo assert not todo
......
...@@ -1991,6 +1991,8 @@ compiler_visit_annotations(struct compiler *c, arguments_ty args, ...@@ -1991,6 +1991,8 @@ compiler_visit_annotations(struct compiler *c, arguments_ty args,
if (!compiler_visit_argannotations(c, args->args, names)) if (!compiler_visit_argannotations(c, args->args, names))
goto error; goto error;
if (!compiler_visit_argannotations(c, args->posonlyargs, names))
goto error;
if (args->vararg && args->vararg->annotation && if (args->vararg && args->vararg->annotation &&
!compiler_visit_argannotation(c, args->vararg->arg, !compiler_visit_argannotation(c, args->vararg->arg,
args->vararg->annotation, names)) args->vararg->annotation, names))
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment