[Python-checkins] bpo-37115: Support annotations in positional-only arguments (GH-13698)

Pablo Galindo webhook-mailer at python.org
Fri May 31 10:19:55 EDT 2019


https://github.com/python/cpython/commit/a0c01bf1364f2996bb0186ddfc41d74350e01c39
commit: a0c01bf1364f2996bb0186ddfc41d74350e01c39
branch: master
author: Pablo Galindo <Pablogsal at gmail.com>
committer: GitHub <noreply at github.com>
date: 2019-05-31T15:19:50+01:00
summary:

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

files:
M Lib/test/test_grammar.py
M Lib/test/test_type_comments.py
M Python/compile.c

diff --git a/Lib/test/test_grammar.py b/Lib/test/test_grammar.py
index 6d7d5544ed9c..2a3b71fac4a5 100644
--- a/Lib/test/test_grammar.py
+++ b/Lib/test/test_grammar.py
@@ -620,14 +620,22 @@ def f(x) -> list: pass
         self.assertEqual(f.__annotations__, {'return': list})
         def f(x: int): pass
         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
         self.assertEqual(f.__annotations__, {'x': str})
         def f(**x: float): pass
         self.assertEqual(f.__annotations__, {'x': float})
         def f(x, y: 1+2): pass
         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
         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
         self.assertEqual(f.__annotations__,
                          {'b': 1, 'c': 2, 'e': 3, 'g': 6})
@@ -636,6 +644,11 @@ def f(a, b: 1, c: 2, d, e: 3 = 4, f=5, *g: 6, h: 7, i=8, j: 9 = 10,
         self.assertEqual(f.__annotations__,
                          {'b': 1, 'c': 2, 'e': 3, 'g': 6, 'h': 7, 'j': 9,
                           '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
         class Spam:
             def f(self, *, __kw: 1):
diff --git a/Lib/test/test_type_comments.py b/Lib/test/test_type_comments.py
index 83d8717247aa..55b54e7f203e 100644
--- a/Lib/test/test_type_comments.py
+++ b/Lib/test/test_type_comments.py
@@ -99,12 +99,25 @@ def fa(
 ):
     pass
 
+def fa(
+    a = 1,  # type: A
+    /
+):
+    pass
+
 def fab(
     a,  # type: A
     b,  # type: B
 ):
     pass
 
+def fab(
+    a,  # type: A
+    /,
+    b,  # type: B
+):
+    pass
+
 def fab(
     a,  # type: A
     b   # type: B
@@ -149,6 +162,13 @@ def fav(
 ):
     pass
 
+def fav(
+    a,  # type: A
+    /,
+    *v,  # type: V
+):
+    pass
+
 def fav(
     a,  # type: A
     *v  # type: V
@@ -161,6 +181,13 @@ def fak(
 ):
     pass
 
+def fak(
+    a,  # type: A
+    /,
+    **k,  # type: K
+):
+    pass
+
 def fak(
     a,  # type: A
     **k  # type: K
@@ -174,6 +201,14 @@ def favk(
 ):
     pass
 
+def favk(
+    a,  # type: A
+    /,
+    *v,  # type: V
+    **k,  # type: K
+):
+    pass
+
 def favk(
     a,  # type: A
     *v,  # type: V
@@ -290,18 +325,21 @@ def test_longargs(self):
             for t in tree.body:
                 # The expected args are encoded in the function name
                 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))
                 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)
                     if c == 'v':
                         arg = t.args.vararg
                     elif c == 'k':
                         arg = t.args.kwarg
                     else:
-                        assert 0 <= ord(c) - ord('a') < len(t.args.args)
-                        arg = t.args.args[ord(c) - ord('a')]
+                        assert 0 <= ord(c) - ord('a') < len(t.args.posonlyargs + t.args.args)
+                        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.type_comment, arg.arg.upper())
                 assert not todo
diff --git a/Python/compile.c b/Python/compile.c
index f1c97bdfe47f..f6ec929b3ca4 100644
--- a/Python/compile.c
+++ b/Python/compile.c
@@ -1991,6 +1991,8 @@ compiler_visit_annotations(struct compiler *c, arguments_ty args,
 
     if (!compiler_visit_argannotations(c, args->args, names))
         goto error;
+    if (!compiler_visit_argannotations(c, args->posonlyargs, names))
+        goto error;
     if (args->vararg && args->vararg->annotation &&
         !compiler_visit_argannotation(c, args->vararg->arg,
                                      args->vararg->annotation, names))



More information about the Python-checkins mailing list