Skip to content

Commit ad9024d

Browse files
ddfishergvanrossum
authored andcommitted
Support per-argument type comment syntax (#1738)
This adds support for the (Python 2) per-argument type comment syntax now that python/typed_ast#5 has landed. It only works when using `--fast-parser`; without that these comments will be ignore. The code works by converting Python 2.7 per-argument type comments to Python 3 annotations in the typed_ast's conversion module -- this allows them to be mixed with the # type: (...) -> None syntax. Fixes #1102.
1 parent 4889c0c commit ad9024d

File tree

3 files changed

+122
-3
lines changed

3 files changed

+122
-3
lines changed

mypy/fastparse.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -254,7 +254,8 @@ def visit_FunctionDef(self, n: ast35.FunctionDef) -> Node:
254254
# for ellipsis arg
255255
if (len(func_type_ast.argtypes) == 1 and
256256
isinstance(func_type_ast.argtypes[0], ast35.Ellipsis)):
257-
arg_types = [AnyType() for a in args]
257+
arg_types = [a.type_annotation if a.type_annotation is not None else AnyType()
258+
for a in args]
258259
else:
259260
arg_types = [a if a is not None else AnyType() for
260261
a in TypeConverter(line=n.lineno).visit_list(func_type_ast.argtypes)]

test-data/unit/check-fastparse.test

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,3 +42,115 @@ class C:
4242
@x.setter
4343
def x(self, value: str) -> None: pass
4444
[builtins fixtures/property.py]
45+
46+
[case testFastParsePerArgumentAnnotations]
47+
# flags: fast-parser
48+
class A: pass
49+
class B: pass
50+
class C: pass
51+
class D: pass
52+
class E: pass
53+
class F: pass
54+
def f(a, # type: A
55+
b = None, # type: B
56+
*args, # type: C
57+
d = None, # type: D
58+
e, # type: E
59+
**kwargs # type: F
60+
):
61+
reveal_type(a) # E: Revealed type is '__main__.A'
62+
reveal_type(b) # E: Revealed type is '__main__.B'
63+
reveal_type(args) # E: Revealed type is 'builtins.tuple[__main__.C]'
64+
reveal_type(d) # E: Revealed type is '__main__.D'
65+
reveal_type(e) # E: Revealed type is '__main__.E'
66+
reveal_type(kwargs) # E: Revealed type is 'builtins.dict[builtins.str, __main__.F]'
67+
[builtins fixtures/dict.py]
68+
[out]
69+
main: note: In function "f":
70+
71+
[case testFastParsePerArgumentAnnotationsWithReturn]
72+
# flags: fast-parser
73+
class A: pass
74+
class B: pass
75+
class C: pass
76+
class D: pass
77+
class E: pass
78+
class F: pass
79+
def f(a, # type: A
80+
b = None, # type: B
81+
*args, # type: C
82+
d = None, # type: D
83+
e, # type: E
84+
**kwargs # type: F
85+
):
86+
# type: (...) -> int
87+
reveal_type(a) # E: Revealed type is '__main__.A'
88+
reveal_type(b) # E: Revealed type is '__main__.B'
89+
reveal_type(args) # E: Revealed type is 'builtins.tuple[__main__.C]'
90+
reveal_type(d) # E: Revealed type is '__main__.D'
91+
reveal_type(e) # E: Revealed type is '__main__.E'
92+
reveal_type(kwargs) # E: Revealed type is 'builtins.dict[builtins.str, __main__.F]'
93+
return "not an int" # E: Incompatible return value type (got "str", expected "int")
94+
[builtins fixtures/dict.py]
95+
[out]
96+
main: note: In function "f":
97+
98+
[case testFastParsePerArgumentAnnotationsWithAnnotatedBareStar]
99+
# flags: fast-parser
100+
def f(*, # type: int # E: bare * has associated type comment
101+
x # type: str
102+
):
103+
# type: (...) -> int
104+
pass
105+
[builtins fixtures/dict.py]
106+
[out]
107+
108+
[case testFastParsePerArgumentAnnotationsWithReturnAndBareStar]
109+
# flags: fast-parser
110+
def f(*,
111+
x # type: str
112+
):
113+
# type: (...) -> int
114+
reveal_type(x) # E: Revealed type is 'builtins.str'
115+
return "not an int" # E: Incompatible return value type (got "str", expected "int")
116+
[builtins fixtures/dict.py]
117+
[out]
118+
main: note: In function "f":
119+
120+
[case testFastParsePerArgumentAnnotations_python2]
121+
# flags: fast-parser
122+
class A: pass
123+
class B: pass
124+
class C: pass
125+
class D: pass
126+
def f(a, # type: A
127+
b = None, # type: B
128+
*args # type: C
129+
# kwargs not tested due to lack of 2.7 dict fixtures
130+
):
131+
reveal_type(a) # E: Revealed type is '__main__.A'
132+
reveal_type(b) # E: Revealed type is '__main__.B'
133+
reveal_type(args) # E: Revealed type is 'builtins.tuple[__main__.C]'
134+
[builtins fixtures/dict.py]
135+
[out]
136+
main: note: In function "f":
137+
138+
[case testFastParsePerArgumentAnnotationsWithReturn_python2]
139+
# flags: fast-parser
140+
class A: pass
141+
class B: pass
142+
class C: pass
143+
class D: pass
144+
def f(a, # type: A
145+
b = None, # type: B
146+
*args # type: C
147+
# kwargs not tested due to lack of 2.7 dict fixtures
148+
):
149+
# type: (...) -> int
150+
reveal_type(a) # E: Revealed type is '__main__.A'
151+
reveal_type(b) # E: Revealed type is '__main__.B'
152+
reveal_type(args) # E: Revealed type is 'builtins.tuple[__main__.C]'
153+
return "not an int" # E: Incompatible return value type (got "str", expected "int")
154+
[builtins fixtures/dict.py]
155+
[out]
156+
main: note: In function "f":

test-data/unit/lib-stub/__builtin__.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,14 @@
1+
class Any: pass
2+
13
class object:
2-
def __init__(self) -> None: pass
4+
def __init__(self):
5+
# type: () -> None
6+
pass
37

48
class type:
5-
def __init__(self, x) -> None: pass
9+
def __init__(self, x):
10+
# type: (Any) -> None
11+
pass
612

713
# These are provided here for convenience.
814
class int: pass

0 commit comments

Comments
 (0)