From c636a80f5466af2387a7655e93ef03d5ffb7d816 Mon Sep 17 00:00:00 2001 From: elazar Date: Mon, 31 Jul 2017 17:43:19 +0300 Subject: [PATCH 1/2] Rephrase 'incompatible default' message Add tests for tuple parameter --- mypy/checker.py | 12 ++++++-- test-data/unit/check-functions.test | 47 ++++++++++++++++++++++++++--- test-data/unit/check-inference.test | 2 +- test-data/unit/check-modules.test | 6 ++-- test-data/unit/check-optional.test | 4 +-- 5 files changed, 57 insertions(+), 14 deletions(-) diff --git a/mypy/checker.py b/mypy/checker.py index 760a137500f9..5ce7e43d198f 100644 --- a/mypy/checker.py +++ b/mypy/checker.py @@ -740,9 +740,15 @@ def is_implicit_any(t: Type) -> bool: # Type check initialization expressions. for arg in item.arguments: - init = arg.initialization_statement - if init: - self.accept(init) + if arg.initializer is not None: + name = arg.variable.name() + msg = 'Incompatible default for ' + if name.startswith('__tuple_arg_'): + msg += "tuple argument no' {}".format(name[12:]) + else: + msg += 'argument "{}"'.format(name) + self.check_simple_assignment(arg.variable.type, arg.initializer, + context=arg, msg=msg, lvalue_name='argument', rvalue_name='default') # Type check body in a new scope. with self.binder.top_frame_context(): diff --git a/test-data/unit/check-functions.test b/test-data/unit/check-functions.test index bc5a56b56014..c6d0a29ca972 100644 --- a/test-data/unit/check-functions.test +++ b/test-data/unit/check-functions.test @@ -388,17 +388,54 @@ class A: pass [case testDefaultArgumentExpressions2] import typing -def f(x: 'A' = B()) -> None: # E: Incompatible types in assignment (expression has type "B", variable has type "A") +def f(x: 'A' = B()) -> None: # E: Incompatible default for argument "x" (default has type "B", argument has type "A") b = x # type: B # E: Incompatible types in assignment (expression has type "A", variable has type "B") a = x # type: A class B: pass class A: pass -[out] + +[case testDefaultArgumentExpressionsGeneric] +from typing import TypeVar +T = TypeVar('T', bound='A') +def f(x: T = B()) -> None: # E: Incompatible default for argument "x" (default has type "B", argument has type "T") + b = x # type: B # E: Incompatible types in assignment (expression has type "T", variable has type "B") + a = x # type: A + +class B: pass +class A: pass + +[case testDefaultArgumentExpressionsPython2] +# flags: --python-version 2.7 +from typing import Tuple +def f(x = B()): # E: Incompatible default for argument "x" (default has type "B", argument has type "A") + # type: (A) -> None + b = x # type: B # E: Incompatible types in assignment (expression has type "A", variable has type "B") + a = x # type: A + +class B: pass +class A: pass + +[case testDefaultTupleArgumentExpressionsPython2] +# flags: --python-version 2.7 +from typing import Tuple +def f((x, y) = (A(), B())): # E: Incompatible default for tuple argument no' 1 (default has type "Tuple[A, B]", argument has type "Tuple[B, B]") + # type: (Tuple[B, B]) -> None + b = x # type: B + a = x # type: A # E: Incompatible types in assignment (expression has type "B", variable has type "A") +def g(a, (x, y) = (A(),)): # E: Incompatible default for tuple argument no' 2 (default has type "Tuple[A]", argument has type "Tuple[B, B]") + # type: (int, Tuple[B, B]) -> None + pass +def h((x, y) = (A(), B(), A())): # E: Incompatible default for tuple argument no' 1 (default has type "Tuple[A, B, A]", argument has type "Tuple[B, B]") + # type: (Tuple[B, B]) -> None + pass + +class B: pass +class A: pass [case testDefaultArgumentsWithSubtypes] import typing -def f(x: 'B' = A()) -> None: # E: Incompatible types in assignment (expression has type "A", variable has type "B") +def f(x: 'B' = A()) -> None: # E: Incompatible default for argument "x" (default has type "A", argument has type "B") pass def g(x: 'A' = B()) -> None: pass @@ -409,7 +446,7 @@ class B(A): pass [case testMultipleDefaultArgumentExpressions] import typing -def f(x: 'A' = B(), y: 'B' = B()) -> None: # E: Incompatible types in assignment (expression has type "B", variable has type "A") +def f(x: 'A' = B(), y: 'B' = B()) -> None: # E: Incompatible default for argument "x" (default has type "B", argument has type "A") pass def h(x: 'A' = A(), y: 'B' = B()) -> None: pass @@ -420,7 +457,7 @@ class B: pass [case testMultipleDefaultArgumentExpressions2] import typing -def g(x: 'A' = A(), y: 'B' = A()) -> None: # E: Incompatible types in assignment (expression has type "A", variable has type "B") +def g(x: 'A' = A(), y: 'B' = A()) -> None: # E: Incompatible default for argument "y" (default has type "A", argument has type "B") pass class A: pass diff --git a/test-data/unit/check-inference.test b/test-data/unit/check-inference.test index 42cd312c0531..4c461993e6f8 100644 --- a/test-data/unit/check-inference.test +++ b/test-data/unit/check-inference.test @@ -1119,7 +1119,7 @@ from typing import Callable def f(a: Callable[..., None] = lambda *a, **k: None): pass -def g(a: Callable[..., None] = lambda *a, **k: 1): # E: Incompatible types in assignment (expression has type Callable[[VarArg(Any), KwArg(Any)], int], variable has type Callable[..., None]) +def g(a: Callable[..., None] = lambda *a, **k: 1): # E: Incompatible default for argument "a" (default has type Callable[[VarArg(Any), KwArg(Any)], int], argument has type Callable[..., None]) pass [builtins fixtures/dict.pyi] diff --git a/test-data/unit/check-modules.test b/test-data/unit/check-modules.test index 6e363bdb24ea..5b90eee81324 100644 --- a/test-data/unit/check-modules.test +++ b/test-data/unit/check-modules.test @@ -475,11 +475,11 @@ def f(x: int = ...) -> None: pass [file m.pyi] def g(x: int = '') -> None: pass [out] -tmp/m.pyi:1: error: Incompatible types in assignment (expression has type "str", variable has type "int") -main:2: error: Incompatible types in assignment (expression has type "ellipsis", variable has type "int") +tmp/m.pyi:1: error: Incompatible default for argument "x" (default has type "str", argument has type "int") +main:2: error: Incompatible default for argument "x" (default has type "ellipsis", argument has type "int") [case testEllipsisDefaultArgValueInNonStub] -def f(x: int = ...) -> None: pass # E: Incompatible types in assignment (expression has type "ellipsis", variable has type "int") +def f(x: int = ...) -> None: pass # E: Incompatible default for argument "x" (default has type "ellipsis", argument has type "int") [out] [case testStarImportOverlapping] diff --git a/test-data/unit/check-optional.test b/test-data/unit/check-optional.test index 0103386fca4e..1cdef1079221 100644 --- a/test-data/unit/check-optional.test +++ b/test-data/unit/check-optional.test @@ -127,7 +127,7 @@ f(None) [case testNoInferOptionalFromDefaultNone] # flags: --no-implicit-optional -def f(x: int = None) -> None: # E: Incompatible types in assignment (expression has type None, variable has type "int") +def f(x: int = None) -> None: # E: Incompatible default for argument "x" (default has type None, argument has type "int") pass [out] @@ -140,7 +140,7 @@ f(None) [case testNoInferOptionalFromDefaultNoneComment] # flags: --no-implicit-optional -def f(x=None): # E: Incompatible types in assignment (expression has type None, variable has type "int") +def f(x=None): # E: Incompatible default for argument "x" (default has type None, argument has type "int") # type: (int) -> None pass [out] From 0065cd0310a7274e30a3844fa384540ad7e61b0d Mon Sep 17 00:00:00 2001 From: elazar Date: Mon, 31 Jul 2017 22:23:42 +0300 Subject: [PATCH 2/2] remove no' --- mypy/checker.py | 2 +- test-data/unit/check-functions.test | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/mypy/checker.py b/mypy/checker.py index 5ce7e43d198f..ca19d756dfb0 100644 --- a/mypy/checker.py +++ b/mypy/checker.py @@ -744,7 +744,7 @@ def is_implicit_any(t: Type) -> bool: name = arg.variable.name() msg = 'Incompatible default for ' if name.startswith('__tuple_arg_'): - msg += "tuple argument no' {}".format(name[12:]) + msg += "tuple argument {}".format(name[12:]) else: msg += 'argument "{}"'.format(name) self.check_simple_assignment(arg.variable.type, arg.initializer, diff --git a/test-data/unit/check-functions.test b/test-data/unit/check-functions.test index c6d0a29ca972..04bb746ad66b 100644 --- a/test-data/unit/check-functions.test +++ b/test-data/unit/check-functions.test @@ -419,14 +419,14 @@ class A: pass [case testDefaultTupleArgumentExpressionsPython2] # flags: --python-version 2.7 from typing import Tuple -def f((x, y) = (A(), B())): # E: Incompatible default for tuple argument no' 1 (default has type "Tuple[A, B]", argument has type "Tuple[B, B]") +def f((x, y) = (A(), B())): # E: Incompatible default for tuple argument 1 (default has type "Tuple[A, B]", argument has type "Tuple[B, B]") # type: (Tuple[B, B]) -> None b = x # type: B a = x # type: A # E: Incompatible types in assignment (expression has type "B", variable has type "A") -def g(a, (x, y) = (A(),)): # E: Incompatible default for tuple argument no' 2 (default has type "Tuple[A]", argument has type "Tuple[B, B]") +def g(a, (x, y) = (A(),)): # E: Incompatible default for tuple argument 2 (default has type "Tuple[A]", argument has type "Tuple[B, B]") # type: (int, Tuple[B, B]) -> None pass -def h((x, y) = (A(), B(), A())): # E: Incompatible default for tuple argument no' 1 (default has type "Tuple[A, B, A]", argument has type "Tuple[B, B]") +def h((x, y) = (A(), B(), A())): # E: Incompatible default for tuple argument 1 (default has type "Tuple[A, B, A]", argument has type "Tuple[B, B]") # type: (Tuple[B, B]) -> None pass