Skip to content

Commit 4afd647

Browse files
ddfishergvanrossum
authored andcommitted
Fast parser: support @no_type_check, give better ellipses error (#2722)
This PR converts 3 more test files to the fast parser. To do so, we add support for the @no_type_check decorator and fixup the error message about mixed ellipses arguments (i.e. fixes #2704).
1 parent 8a7b4e1 commit 4afd647

9 files changed

Lines changed: 64 additions & 43 deletions

File tree

‎mypy/fastparse.py‎

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,15 @@ def find(f: Callable[[V], bool], seq: Sequence[V]) -> V:
108108
return None
109109

110110

111+
def is_no_type_check_decorator(expr: ast35.expr) -> bool:
112+
if isinstance(expr, ast35.Name):
113+
return expr.id == 'no_type_check'
114+
elif isinstance(expr, ast35.Attribute):
115+
if isinstance(expr.value, ast35.Name):
116+
return expr.value.id == 'typing' and expr.attr == 'no_type_check'
117+
return False
118+
119+
111120
class ASTConverter(ast35.NodeTransformer):
112121
def __init__(self,
113122
pyversion: Tuple[int, int],
@@ -268,15 +277,21 @@ def visit_AsyncFunctionDef(self, n: ast35.AsyncFunctionDef) -> Union[FuncDef, De
268277
def do_func_def(self, n: Union[ast35.FunctionDef, ast35.AsyncFunctionDef],
269278
is_coroutine: bool = False) -> Union[FuncDef, Decorator]:
270279
"""Helper shared between visit_FunctionDef and visit_AsyncFunctionDef."""
271-
args = self.transform_args(n.args, n.lineno)
280+
no_type_check = bool(n.decorator_list and
281+
any(is_no_type_check_decorator(d) for d in n.decorator_list))
282+
283+
args = self.transform_args(n.args, n.lineno, no_type_check=no_type_check)
272284

273285
arg_kinds = [arg.kind for arg in args]
274286
arg_names = [arg.variable.name() for arg in args] # type: List[Optional[str]]
275287
arg_names = [None if argument_elide_name(name) else name for name in arg_names]
276288
if special_function_elide_names(n.name):
277289
arg_names = [None] * len(arg_names)
278290
arg_types = None # type: List[Type]
279-
if n.type_comment is not None:
291+
if no_type_check:
292+
arg_types = [None] * len(args)
293+
return_type = None
294+
elif n.type_comment is not None:
280295
try:
281296
func_type_ast = ast35.parse(n.type_comment, '<func_type>', 'func_type')
282297
assert isinstance(func_type_ast, ast35.FunctionType)
@@ -298,7 +313,7 @@ def do_func_def(self, n: Union[ast35.FunctionDef, ast35.AsyncFunctionDef],
298313
arg_types.insert(0, AnyType())
299314
except SyntaxError:
300315
self.fail(TYPE_COMMENT_SYNTAX_ERROR, n.lineno, n.col_offset)
301-
arg_types = [AnyType() for _ in args]
316+
arg_types = [AnyType()] * len(args)
302317
return_type = AnyType()
303318
else:
304319
arg_types = [a.type_annotation for a in args]
@@ -312,7 +327,10 @@ def do_func_def(self, n: Union[ast35.FunctionDef, ast35.AsyncFunctionDef],
312327

313328
func_type = None
314329
if any(arg_types) or return_type:
315-
if len(arg_types) > len(arg_kinds):
330+
if len(arg_types) != 1 and any(isinstance(t, EllipsisType) for t in arg_types):
331+
self.fail("Ellipses cannot accompany other argument types "
332+
"in function type signature.", n.lineno, 0)
333+
elif len(arg_types) > len(arg_kinds):
316334
self.fail('Type signature has too many arguments', n.lineno, 0)
317335
elif len(arg_types) < len(arg_kinds):
318336
self.fail('Type signature has too few arguments', n.lineno, 0)
@@ -356,9 +374,16 @@ def set_type_optional(self, type: Type, initializer: Expression) -> None:
356374
if isinstance(type, UnboundType):
357375
type.optional = optional
358376

359-
def transform_args(self, args: ast35.arguments, line: int) -> List[Argument]:
377+
def transform_args(self,
378+
args: ast35.arguments,
379+
line: int,
380+
no_type_check: bool = False,
381+
) -> List[Argument]:
360382
def make_argument(arg: ast35.arg, default: Optional[ast35.expr], kind: int) -> Argument:
361-
arg_type = TypeConverter(self.errors, line=line).visit(arg.annotation)
383+
if no_type_check:
384+
arg_type = None
385+
else:
386+
arg_type = TypeConverter(self.errors, line=line).visit(arg.annotation)
362387
return Argument(Var(arg.arg), arg_type, self.visit(default), kind)
363388

364389
new_args = []
@@ -752,7 +777,7 @@ def is_star2arg(k: ast35.keyword) -> bool:
752777
return CallExpr(self.visit(n.func),
753778
arg_types,
754779
arg_kinds,
755-
cast("List[str]", [None for _ in n.args]) + [k.arg for k in n.keywords])
780+
cast("List[str]", [None] * len(n.args)) + [k.arg for k in n.keywords])
756781

757782
# Num(object n) -- a number as a PyObject.
758783
@with_line

‎mypy/fastparse2.py‎

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
ARG_POS, ARG_OPT, ARG_STAR, ARG_NAMED, ARG_STAR2
3535
)
3636
from mypy.types import (
37-
Type, CallableType, AnyType, UnboundType,
37+
Type, CallableType, AnyType, UnboundType, EllipsisType
3838
)
3939
from mypy import defaults
4040
from mypy import experiments
@@ -114,6 +114,15 @@ def find(f: Callable[[V], bool], seq: Sequence[V]) -> V:
114114
return None
115115

116116

117+
def is_no_type_check_decorator(expr: ast27.expr) -> bool:
118+
if isinstance(expr, ast27.Name):
119+
return expr.id == 'no_type_check'
120+
elif isinstance(expr, ast27.Attribute):
121+
if isinstance(expr.value, ast27.Name):
122+
return expr.value.id == 'typing' and expr.attr == 'no_type_check'
123+
return False
124+
125+
117126
class ASTConverter(ast27.NodeTransformer):
118127
def __init__(self,
119128
pyversion: Tuple[int, int],
@@ -274,7 +283,10 @@ def visit_FunctionDef(self, n: ast27.FunctionDef) -> Statement:
274283
arg_names = [None] * len(arg_names)
275284

276285
arg_types = None # type: List[Type]
277-
if n.type_comment is not None and len(n.type_comment) > 0:
286+
if (n.decorator_list and any(is_no_type_check_decorator(d) for d in n.decorator_list)):
287+
arg_types = [None] * len(args)
288+
return_type = None
289+
elif n.type_comment is not None and len(n.type_comment) > 0:
278290
try:
279291
func_type_ast = ast35.parse(n.type_comment, '<func_type>', 'func_type')
280292
assert isinstance(func_type_ast, ast35.FunctionType)
@@ -293,7 +305,7 @@ def visit_FunctionDef(self, n: ast27.FunctionDef) -> Statement:
293305
arg_types.insert(0, AnyType())
294306
except SyntaxError:
295307
self.fail(TYPE_COMMENT_SYNTAX_ERROR, n.lineno, n.col_offset)
296-
arg_types = [AnyType() for _ in args]
308+
arg_types = [AnyType()] * len(args)
297309
return_type = AnyType()
298310
else:
299311
arg_types = [a.type_annotation for a in args]
@@ -307,7 +319,10 @@ def visit_FunctionDef(self, n: ast27.FunctionDef) -> Statement:
307319

308320
func_type = None
309321
if any(arg_types) or return_type:
310-
if len(arg_types) > len(arg_kinds):
322+
if len(arg_types) != 1 and any(isinstance(t, EllipsisType) for t in arg_types):
323+
self.fail("Ellipses cannot accompany other argument types "
324+
"in function type signature.", n.lineno, 0)
325+
elif len(arg_types) > len(arg_kinds):
311326
self.fail('Type signature has too many arguments', n.lineno, 0)
312327
elif len(arg_types) < len(arg_kinds):
313328
self.fail('Type signature has too few arguments', n.lineno, 0)

‎mypy/semanal.py‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1404,10 +1404,11 @@ def store_declared_types(self, lvalue: Lvalue, typ: Type) -> None:
14041404
self.fail('Tuple type expected for multiple variables',
14051405
lvalue)
14061406
elif isinstance(lvalue, StarExpr):
1407+
# Historical behavior for the old parser
14071408
if isinstance(typ, StarType):
14081409
self.store_declared_types(lvalue.expr, typ.type)
14091410
else:
1410-
self.fail('Star type expected for starred expression', lvalue)
1411+
self.store_declared_types(lvalue.expr, typ)
14111412
else:
14121413
# This has been flagged elsewhere as an error, so just ignore here.
14131414
pass

‎mypy/test/testcheck.py‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,8 @@
2727

2828
# List of files that contain test case descriptions.
2929
files = [
30-
'check-columns.test',
3130
'check-expressions.test',
32-
'check-functions.test',
3331
'check-generic-subtyping.test',
34-
'check-tuples.test',
3532
'check-varargs.test',
3633
]
3734
fast_parser_files = [
@@ -73,6 +70,9 @@
7370
'check-class-namedtuple.test',
7471
'check-selftype.test',
7572
'check-python2.test',
73+
'check-columns.test',
74+
'check-functions.test',
75+
'check-tuples.test',
7676
]
7777

7878
files.extend(fast_parser_files)

‎test-data/unit/check-columns.test‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
# flags: --show-column-numbers
33
1 +
44
[out]
5-
main:2:3: error: Parse error before end of line
5+
main:2:4: error: invalid syntax
66

77

88
[case testColumnsNestedFunctions]
@@ -40,9 +40,9 @@ class A:
4040
pass
4141
A().f()
4242
A().f(1)
43-
A().f('') # E:5: Argument 1 to "f" of "A" has incompatible type "str"; expected "int"
44-
A().f(1, 1) # E:5: Argument 2 to "f" of "A" has incompatible type "int"; expected "str"
45-
A().f(1, 'hello', 'hi') # E:5: Too many arguments for "f" of "A"
43+
A().f('') # E:0: Argument 1 to "f" of "A" has incompatible type "str"; expected "int"
44+
A().f(1, 1) # E:0: Argument 2 to "f" of "A" has incompatible type "int"; expected "str"
45+
A().f(1, 'hello', 'hi') # E:0: Too many arguments for "f" of "A"
4646

4747
[case testColumnsMultipleStatementsPerLine]
4848
# flags: --show-column-numbers

‎test-data/unit/check-functions.test‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1475,13 +1475,13 @@ class A:
14751475
def f(x, y, z): # type: (..., int) -> None
14761476
pass
14771477
[out]
1478-
main:1: error: Parse error before ): Ellipses cannot accompany other argument types in function type signature.
1478+
main:1: error: Ellipses cannot accompany other argument types in function type signature.
14791479

14801480
[case testEllipsisWithSomethingBeforeItFails]
14811481
def f(x, y, z): # type: (int, ...) -> None
14821482
pass
14831483
[out]
1484-
main:1: error: Parse error before ): Ellipses cannot accompany other argument types in function type signature.
1484+
main:1: error: Ellipses cannot accompany other argument types in function type signature.
14851485

14861486
[case testRejectCovariantArgument]
14871487
from typing import TypeVar, Generic

‎test-data/unit/check-python2.test‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ def f(x, y, z): # type: (...) -> None
183183
def f(x, y, z): # type: (..., int) -> None
184184
pass
185185
[out]
186-
main:1: error: Type signature has too few arguments
186+
main:1: error: Ellipses cannot accompany other argument types in function type signature.
187187

188188
[case testLambdaTupleArgInPython2]
189189
f = lambda (x, y): x + y

‎test-data/unit/check-tuples.test‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -387,7 +387,7 @@ aa, bb, *cc = t # E: Need type annotation for variable
387387
[case testAssignmentToStarAnnotation]
388388
from typing import List
389389
li, lo = None, None # type: List[int], List[object]
390-
a, b, *c = 1, 2 # type: int, int, *List[int]
390+
a, b, *c = 1, 2 # type: int, int, List[int]
391391
c = lo # E: Incompatible types in assignment (expression has type List[object], variable has type List[int])
392392
c = li
393393
[builtins fixtures/list.pyi]

‎test-data/unit/semanal-errors.test‎

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -149,16 +149,6 @@ z = 0 # type: x
149149
main:4: error: Invalid type "__main__.f"
150150
main:5: error: Invalid type "__main__.x"
151151

152-
[case testTwoStarsInType]
153-
import typing
154-
x, x2 = 1 # type: *object, *object
155-
y, y2 = 1 # type: object, (*object, *object)
156-
z, z2 = 1 # type: *object, (object, *object)
157-
[out]
158-
main:2: error: At most one star type allowed in a tuple
159-
main:3: error: At most one star type allowed in a tuple
160-
main:4: error: Star type only allowed for starred expressions
161-
162152
[case testGlobalVarRedefinition]
163153
import typing
164154
class A: pass
@@ -419,16 +409,6 @@ main:4: error: Invalid assignment target
419409
main:5: error: Invalid assignment target
420410
main:6: error: Invalid assignment target
421411

422-
[case testInvalidStarType]
423-
a = 1 # type: *int
424-
[out]
425-
main:1: error: Star type only allowed for starred expressions
426-
427-
[case testInvalidStarType]
428-
*a, b = 1 # type: int, int
429-
[out]
430-
main:1: error: Star type expected for starred expression
431-
432412
[case testTwoStarExpressions]
433413
a, *b, *c = 1
434414
*a, (*b, c) = 1

0 commit comments

Comments
 (0)