| -- Test cases for the type checker related to varargs. | |
| -- Varargs within body | |
| -- ------------------- | |
| [case testVarArgsWithinFunction] | |
| from typing import Tuple | |
| def f( *b: 'B') -> None: | |
| ab: Tuple[B, ...] | |
| ac: Tuple[C, ...] | |
| if int(): | |
| b = ac # E: Incompatible types in assignment (expression has type "tuple[C, ...]", variable has type "tuple[B, ...]") | |
| ac = b # E: Incompatible types in assignment (expression has type "tuple[B, ...]", variable has type "tuple[C, ...]") | |
| b = ab | |
| ab = b | |
| class B: pass | |
| class C: pass | |
| [builtins fixtures/tuple.pyi] | |
| [out] | |
| [case testVarArgsAreTuple] | |
| from typing import Tuple, Sequence | |
| def want_tuple(types: Tuple[type, ...]): pass | |
| def want_sequence(types: Sequence[type]): pass | |
| def test(*t: type) -> None: | |
| want_tuple(t) | |
| want_sequence(t) | |
| [builtins fixtures/tuple.pyi] | |
| [out] | |
| -- Calling varargs function | |
| -- ------------------------ | |
| [case testCallingVarArgsFunction] | |
| def f( *a: 'A') -> None: pass | |
| def g() -> None: pass | |
| class A: pass | |
| class B(A): pass | |
| class C: pass | |
| a: A | |
| b: B | |
| c: C | |
| f(c) # E: Argument 1 to "f" has incompatible type "C"; expected "A" | |
| f(a, b, c) # E: Argument 3 to "f" has incompatible type "C"; expected "A" | |
| f(g()) # E: "g" does not return a value (it only ever returns None) \ | |
| # E: Argument 1 to "f" has incompatible type "None"; expected "A" | |
| f(a, g()) # E: "g" does not return a value (it only ever returns None) \ | |
| # E: Argument 2 to "f" has incompatible type "None"; expected "A" | |
| f() | |
| f(a) | |
| f(b) | |
| f(a, b, a, b) | |
| [builtins fixtures/list.pyi] | |
| [case testCallingVarArgsFunctionWithAlsoNormalArgs] | |
| def f(a: 'C', *b: 'A') -> None: pass | |
| class A: pass | |
| class B(A): pass | |
| class C: pass | |
| a: A | |
| b: B | |
| c: C | |
| f(a) # E: Argument 1 to "f" has incompatible type "A"; expected "C" | |
| f(c, c) # E: Argument 2 to "f" has incompatible type "C"; expected "A" | |
| f(c, a, b, c) # E: Argument 4 to "f" has incompatible type "C"; expected "A" | |
| f(c) | |
| f(c, a) | |
| f(c, b, b, a, b) | |
| [builtins fixtures/list.pyi] | |
| [case testCallingVarArgsFunctionWithDefaultArgs] | |
| # flags: --implicit-optional --no-strict-optional | |
| def f(a: 'C' = None, *b: 'A') -> None: | |
| pass | |
| class A: pass | |
| class B(A): pass | |
| class C: pass | |
| a: A | |
| b: B | |
| c: C | |
| f(a) # E: Argument 1 to "f" has incompatible type "A"; expected "C | None" | |
| f(c, c) # E: Argument 2 to "f" has incompatible type "C"; expected "A" | |
| f(c, a, b, c) # E: Argument 4 to "f" has incompatible type "C"; expected "A" | |
| f() | |
| f(c) | |
| f(c, a) | |
| f(c, b, b, a, b) | |
| [builtins fixtures/list.pyi] | |
| [case testCallVarargsFunctionWithIterable] | |
| from typing import Iterable | |
| it1: Iterable[int] | |
| it2: Iterable[str] | |
| def f(*x: int) -> None: pass | |
| f(*it1) | |
| f(*it2) # E: Argument 1 to "f" has incompatible type "*Iterable[str]"; expected "int" | |
| [builtins fixtures/for.pyi] | |
| [case testCallVarargsFunctionWithTwoTupleStarArgs] | |
| from typing import TypeVar, Tuple | |
| T1 = TypeVar('T1') | |
| T2 = TypeVar('T2') | |
| T3 = TypeVar('T3') | |
| T4 = TypeVar('T4') | |
| def f(a: T1, b: T2, c: T3, d: T4) -> Tuple[T1, T2, T3, T4]: ... | |
| x: Tuple[int, str] | |
| y: Tuple[float, bool] | |
| reveal_type(f(*x, *y)) # N: Revealed type is "tuple[builtins.int, builtins.str, builtins.float, builtins.bool]" | |
| [builtins fixtures/list.pyi] | |
| [case testCallVarargsFunctionWithIterableAndPositional] | |
| from typing import Iterable | |
| it1: Iterable[int] | |
| def f(*x: int) -> None: pass | |
| f(*it1, 1, 2) | |
| f(*it1, 1, *it1, 2) | |
| f(*it1, '') # E: Argument 2 to "f" has incompatible type "str"; expected "int" | |
| [builtins fixtures/for.pyi] | |
| [case testCallVarargsFunctionWithTupleAndPositional] | |
| def f(*x: int) -> None: pass | |
| it1 = (1, 2) | |
| it2 = ('',) | |
| f(*it1, 1, 2) | |
| f(*it1, 1, *it1, 2) | |
| f(*it1, 1, *it2, 2) # E: Argument 3 to "f" has incompatible type "*tuple[str]"; expected "int" | |
| f(*it1, '') # E: Argument 2 to "f" has incompatible type "str"; expected "int" | |
| [builtins fixtures/for.pyi] | |
| [case testCallVarArgsWithMatchingNamedArgument] | |
| def foo(*args: int) -> None: ... | |
| foo(args=1) # E: Unexpected keyword argument "args" for "foo" | |
| def bar(*args: int, **kwargs: str) -> None: ... | |
| bar(args=1) # E: Argument "args" to "bar" has incompatible type "int"; expected "str" | |
| [builtins fixtures/for.pyi] | |
| -- Calling varargs function + type inference | |
| -- ----------------------------------------- | |
| [case testTypeInferenceWithCalleeVarArgs] | |
| from typing import TypeVar | |
| T = TypeVar('T') | |
| def f( *a: T) -> T: | |
| pass | |
| class A: pass | |
| class B(A): pass | |
| class C: pass | |
| a: A | |
| b: B | |
| c: C | |
| o: object | |
| if int(): | |
| a = f(o) # E: Incompatible types in assignment (expression has type "object", variable has type "A") | |
| if int(): | |
| b = f(b, a) # E: Incompatible types in assignment (expression has type "A", variable has type "B") | |
| if int(): | |
| b = f(a, b) # E: Incompatible types in assignment (expression has type "A", variable has type "B") | |
| if int(): | |
| o = f() | |
| if int(): | |
| a = f(a) | |
| if int(): | |
| a = f(b) | |
| if int(): | |
| a = f(a, b, a) | |
| if int(): | |
| o = f(a, b, o) | |
| if int(): | |
| c = f(c) | |
| [builtins fixtures/list.pyi] | |
| [case testTypeInferenceWithCalleeVarArgsAndDefaultArgs] | |
| # flags: --no-strict-optional | |
| from typing import TypeVar | |
| T = TypeVar('T') | |
| a = None # type: A | |
| o = None # type: object | |
| def f(a: T, b: T = None, *c: T) -> T: | |
| pass | |
| class A: pass | |
| if int(): | |
| a = f(o) # E: Incompatible types in assignment (expression has type "object", variable has type "A") | |
| if int(): | |
| a = f(a, o) # E: Incompatible types in assignment (expression has type "object", variable has type "A") | |
| if int(): | |
| a = f(a, a, o) # E: Incompatible types in assignment (expression has type "object", variable has type "A") | |
| if int(): | |
| a = f(a, a, a, o) # E: Incompatible types in assignment (expression has type "object", variable has type "A") | |
| if int(): | |
| a = f(a) | |
| if int(): | |
| a = f(a, a) | |
| if int(): | |
| a = f(a, a, a) | |
| [builtins fixtures/list.pyi] | |
| -- Calling normal function with varargs | |
| -- ------------------------------------ | |
| [case testCallingWithListVarArgs] | |
| from typing import List, Any, cast | |
| def f(a: 'A', b: 'B') -> None: | |
| pass | |
| class A: pass | |
| class B: pass | |
| aa: List[A] | |
| ab: List[B] | |
| a: A | |
| b: B | |
| f(*aa) # E: Argument 1 to "f" has incompatible type "*list[A]"; expected "B" | |
| f(a, *ab) # Ok | |
| f(a, b) | |
| (cast(Any, f))(*aa) # IDEA: Move to check-dynamic? | |
| (cast(Any, f))(a, *ab) # IDEA: Move to check-dynamic? | |
| [builtins fixtures/list.pyi] | |
| [case testCallingWithTupleVarArgs] | |
| def f(a: 'A', b: 'B', c: 'C') -> None: pass | |
| class A: pass | |
| class B: pass | |
| class C: pass | |
| class CC(C): pass | |
| a: A | |
| b: B | |
| c: C | |
| cc: CC | |
| f(*(a, b, b)) # E: Argument 1 to "f" has incompatible type "*tuple[A, B, B]"; expected "C" | |
| f(*(b, b, c)) # E: Argument 1 to "f" has incompatible type "*tuple[B, B, C]"; expected "A" | |
| f(a, *(b, b)) # E: Argument 2 to "f" has incompatible type "*tuple[B, B]"; expected "C" | |
| f(b, *(b, c)) # E: Argument 1 to "f" has incompatible type "B"; expected "A" | |
| f(*(a, b)) # E: Missing positional arguments "b", "c" in call to "f" | |
| f(*(a, b, c, c)) # E: Too many arguments for "f" | |
| f(a, *(b, c, c)) # E: Too many arguments for "f" | |
| f(*(a, b, c)) | |
| f(a, *(b, c)) | |
| f(a, b, *(c,)) | |
| f(a, *(b, cc)) | |
| [builtins fixtures/tuple.pyi] | |
| [case testInvalidVarArg] | |
| from typing import Any | |
| def f(a: 'A') -> None: | |
| pass | |
| class A: pass | |
| a = A() | |
| f(*None) # E: Expected iterable as variadic argument | |
| f(*a) # E: Expected iterable as variadic argument | |
| f(*(a,)) | |
| f(*4) # E: Expected iterable as variadic argument | |
| f(a, *4) # E: Expected iterable as variadic argument | |
| def main(f: Any) -> None: | |
| f(*3) # E: Expected iterable as variadic argument | |
| [builtins fixtures/tuple.pyi] | |
| -- Calling varargs function with varargs | |
| -- ------------------------------------- | |
| [case testCallingVarArgsFunctionWithListVarArgs] | |
| from typing import List | |
| def f(a: 'A', *b: 'B') -> None: pass | |
| def g(a: 'A', *b: 'A') -> None: pass | |
| class A: pass | |
| class B: pass | |
| aa: List[A] | |
| ab: List[B] | |
| a: A | |
| b: B | |
| f(*aa) # E: Argument 1 to "f" has incompatible type "*list[A]"; expected "B" | |
| f(a, *aa) # E: Argument 2 to "f" has incompatible type "*list[A]"; expected "B" | |
| f(b, *ab) # E: Argument 1 to "f" has incompatible type "B"; expected "A" | |
| f(a, a, *ab) # E: Argument 2 to "f" has incompatible type "A"; expected "B" | |
| f(a, b, *aa) # E: Argument 3 to "f" has incompatible type "*list[A]"; expected "B" | |
| f(b, b, *ab) # E: Argument 1 to "f" has incompatible type "B"; expected "A" | |
| g(*ab) # E: Argument 1 to "g" has incompatible type "*list[B]"; expected "A" | |
| f(a, *ab) | |
| f(a, b, *ab) | |
| f(a, b, b, *ab) | |
| g(*aa) | |
| [builtins fixtures/list.pyi] | |
| [case testCallingVarArgsFunctionWithTupleVarArgs] | |
| def f(a: 'A', *b: 'B') -> None: | |
| pass | |
| class A: pass | |
| class B: pass | |
| class C: pass | |
| class CC(C): pass | |
| a: A | |
| b: B | |
| c: C | |
| cc: CC | |
| f(*(b, b, b)) # E: Argument 1 to "f" has incompatible type "*tuple[B, B, B]"; expected "A" | |
| f(*(a, a, b)) # E: Argument 1 to "f" has incompatible type "*tuple[A, A, B]"; expected "B" | |
| f(*(a, b, a)) # E: Argument 1 to "f" has incompatible type "*tuple[A, B, A]"; expected "B" | |
| f(a, *(a, b)) # E: Argument 2 to "f" has incompatible type "*tuple[A, B]"; expected "B" | |
| f(b, *(b, b)) # E: Argument 1 to "f" has incompatible type "B"; expected "A" | |
| f(b, b, *(b,)) # E: Argument 1 to "f" has incompatible type "B"; expected "A" | |
| f(a, a, *(b,)) # E: Argument 2 to "f" has incompatible type "A"; expected "B" | |
| f(a, b, *(a,)) # E: Argument 3 to "f" has incompatible type "*tuple[A]"; expected "B" | |
| f(*()) # E: Too few arguments for "f" | |
| f(*(a, b, b)) | |
| f(a, *(b, b)) | |
| f(a, b, *(b,)) | |
| [builtins fixtures/list.pyi] | |
| -- Varargs special cases | |
| -- --------------------- | |
| [case testDynamicVarArg] | |
| from typing import Any | |
| def f(a: 'A') -> None: pass | |
| def g(a: 'A', *b: 'A') -> None: pass | |
| class A: pass | |
| d: Any | |
| a: A | |
| f(a, a, *d) # E: Too many arguments for "f" | |
| f(a, *d) # Ok | |
| f(*d) # Ok | |
| g(*d) | |
| g(a, *d) | |
| g(a, a, *d) | |
| [builtins fixtures/list.pyi] | |
| [case testListVarArgsAndSubtyping] | |
| from typing import List | |
| def f( *a: 'A') -> None: | |
| pass | |
| def g( *a: 'B') -> None: | |
| pass | |
| class A: pass | |
| class B(A): pass | |
| aa: List[A] | |
| ab: List[B] | |
| g(*aa) # E: Argument 1 to "g" has incompatible type "*list[A]"; expected "B" | |
| f(*aa) | |
| f(*ab) | |
| g(*ab) | |
| [builtins fixtures/list.pyi] | |
| [case testCallerVarArgsAndDefaultArgs] | |
| # flags: --implicit-optional --no-strict-optional | |
| def f(a: 'A', b: 'B' = None, *c: 'B') -> None: | |
| pass | |
| class A: pass | |
| class B: pass | |
| a, b = None, None # type: (A, B) | |
| f(*()) # E: Too few arguments for "f" | |
| f(a, *[a]) # E: Argument 2 to "f" has incompatible type "*list[A]"; expected "B | None" \ | |
| # E: Argument 2 to "f" has incompatible type "*list[A]"; expected "B" | |
| f(a, b, *[a]) # E: Argument 3 to "f" has incompatible type "*list[A]"; expected "B" | |
| f(*(a, a, b)) # E: Argument 1 to "f" has incompatible type "*tuple[A, A, B]"; expected "B | None" | |
| f(*(a,)) | |
| f(*(a, b)) | |
| f(*(a, b, b, b)) | |
| f(a, *[]) | |
| f(a, *[b]) | |
| f(a, *[b, b]) | |
| [builtins fixtures/list.pyi] | |
| [case testVarArgsAfterKeywordArgInCall1] | |
| # see: mypy issue #2729 | |
| def f(x: int, y: str) -> None: pass | |
| f(x=1, *[2]) | |
| [builtins fixtures/list.pyi] | |
| [out] | |
| main:3: error: "f" gets multiple values for keyword argument "x" | |
| main:3: error: Argument 1 to "f" has incompatible type "*list[int]"; expected "str" | |
| [case testVarArgsAfterKeywordArgInCall2] | |
| # see: mypy issue #2729 | |
| def f(x: int, y: str) -> None: pass | |
| f(y='x', *[1]) | |
| [builtins fixtures/list.pyi] | |
| [out] | |
| main:3: error: "f" gets multiple values for keyword argument "y" | |
| main:3: error: Argument 1 to "f" has incompatible type "*list[int]"; expected "str" | |
| [case testVarArgsAfterKeywordArgInCall3] | |
| def f(x: int, y: str) -> None: pass | |
| f(y='x', *(1,)) | |
| [builtins fixtures/list.pyi] | |
| [case testVarArgsAfterKeywordArgInCall4] | |
| def f(x: int, *, y: str) -> None: pass | |
| f(y='x', *[1]) | |
| [builtins fixtures/list.pyi] | |
| [case testVarArgsAfterKeywordArgInCall5] | |
| def f(x: int, *, y: str) -> None: pass | |
| f(y='x', *(1,)) | |
| [builtins fixtures/list.pyi] | |
| [case testVarArgsEmptyList] | |
| from typing import List | |
| def foo() -> None: | |
| pass | |
| lst: List[int] = [] | |
| foo(*lst) | |
| [builtins fixtures/list.pyi] | |
| [case testVarArgsEmptyTuple] | |
| def foo() -> None: | |
| pass | |
| foo(*()) | |
| [builtins fixtures/tuple.pyi] | |
| -- Overloads + varargs | |
| -- ------------------- | |
| [case testIntersectionTypesAndVarArgs] | |
| # flags: --no-strict-optional | |
| from foo import * | |
| [file foo.pyi] | |
| from typing import overload | |
| a, b = None, None # type: (A, B) | |
| if int(): | |
| b = f() # E: Incompatible types in assignment (expression has type "A", variable has type "B") | |
| if int(): | |
| b = f(a) # E: Incompatible types in assignment (expression has type "A", variable has type "B") | |
| if int(): | |
| b = f(a, b) # E: Incompatible types in assignment (expression has type "A", variable has type "B") | |
| if int(): | |
| a = f(b) # E: Incompatible types in assignment (expression has type "B", variable has type "A") | |
| if int(): | |
| a = f(b, b) # E: Incompatible types in assignment (expression has type "B", variable has type "A") | |
| if int(): | |
| b = f(a, *[b]) # E: Incompatible types in assignment (expression has type "A", variable has type "B") | |
| if int(): | |
| b = f(*()) # E: Incompatible types in assignment (expression has type "A", variable has type "B") | |
| if int(): | |
| b = f(*(a,)) # E: Incompatible types in assignment (expression has type "A", variable has type "B") | |
| if int(): | |
| b = f(*(a, b)) # E: Incompatible types in assignment (expression has type "A", variable has type "B") | |
| if int(): | |
| a = f(*(b,)) # E: Incompatible types in assignment (expression has type "B", variable has type "A") | |
| if int(): | |
| a = f(*(b, b)) # E: Incompatible types in assignment (expression has type "B", variable has type "A") | |
| if int(): | |
| a = f(*[b]) # E: Incompatible types in assignment (expression has type "B", variable has type "A") | |
| a = f() | |
| a = f(a) | |
| a = f(a, b) | |
| b = f(b) | |
| b = f(b, b) | |
| a = f(a, *[b]) | |
| a = f(*()) | |
| a = f(*(a,)) | |
| a = f(*(a, b)) | |
| b = f(*(b,)) | |
| b = f(*(b, b)) | |
| b = f(*[b]) | |
| class A: pass | |
| class B: pass | |
| @overload | |
| def f(a: A = None, *b: B) -> A: pass | |
| @overload | |
| def f(a: B, *b: B) -> B: pass | |
| [builtins fixtures/list.pyi] | |
| -- Caller varargs + type inference | |
| -- ------------------------------- | |
| [case testCallerVarArgsListWithTypeInference] | |
| from typing import List, TypeVar, Tuple | |
| S = TypeVar('S') | |
| T = TypeVar('T') | |
| def f(a: S, *b: T) -> Tuple[S, T]: | |
| pass | |
| class A: pass | |
| class B: pass | |
| a: A | |
| b: B | |
| aa: List[A] | |
| if int(): | |
| a, b = f(*aa) # E: Argument 1 to "f" has incompatible type "*list[A]"; expected "B" | |
| if int(): | |
| b, b = f(*aa) # E: Argument 1 to "f" has incompatible type "*list[A]"; expected "B" | |
| if int(): | |
| a, a = f(b, *aa) # E: Argument 1 to "f" has incompatible type "B"; expected "A" | |
| if int(): | |
| b, b = f(b, *aa) # E: Argument 2 to "f" has incompatible type "*list[A]"; expected "B" | |
| if int(): | |
| b, b = f(b, b, *aa) # E: Argument 3 to "f" has incompatible type "*list[A]"; expected "B" | |
| if int(): | |
| a, b = f(a, *a) # E: Expected iterable as variadic argument | |
| if int(): | |
| a, b = f(*a) # E: Expected iterable as variadic argument | |
| if int(): | |
| a, a = f(*aa) | |
| if int(): | |
| b, a = f(b, *aa) | |
| if int(): | |
| b, a = f(b, a, *aa) | |
| [builtins fixtures/list.pyi] | |
| [case testCallerVarArgsTupleWithTypeInference] | |
| from typing import TypeVar, Tuple | |
| S = TypeVar('S') | |
| T = TypeVar('T') | |
| def f(a: S, b: T) -> Tuple[S, T]: pass | |
| class A: pass | |
| class B: pass | |
| a: A | |
| b: B | |
| if int(): | |
| a, a = f(*(a, b)) # E: Argument 1 to "f" has incompatible type "*tuple[A, B]"; expected "A" | |
| if int(): | |
| b, b = f(a, *(b,)) # E: Argument 1 to "f" has incompatible type "A"; expected "B" | |
| if int(): | |
| a, a = f(*(a, b)) # E: Argument 1 to "f" has incompatible type "*tuple[A, B]"; expected "A" | |
| if int(): | |
| b, b = f(a, *(b,)) # E: Argument 1 to "f" has incompatible type "A"; expected "B" | |
| if int(): | |
| a, b = f(*(a, b, b)) # E: Too many arguments for "f" | |
| if int(): | |
| a, b = f(*(a, b)) | |
| if int(): | |
| a, b = f(a, *(b,)) | |
| [builtins fixtures/list.pyi] | |
| [case testCallerVarargsAndComplexTypeInference] | |
| from typing import List, TypeVar, Generic, Tuple | |
| T = TypeVar('T') | |
| S = TypeVar('S') | |
| a: A | |
| b: B | |
| ao: List[object] | |
| aa: List[A] | |
| ab: List[B] | |
| class G(Generic[T]): | |
| def f(self, *a: S) -> Tuple[List[S], List[T]]: | |
| pass | |
| class A: pass | |
| class B: pass | |
| if int(): | |
| a, aa = G().f(*[a]) # E: Incompatible types in assignment (expression has type "list[A]", variable has type "A") | |
| if int(): | |
| aa, a = G().f(*[a]) # E: Incompatible types in assignment (expression has type "list[Never]", variable has type "A") | |
| if int(): | |
| ab, aa = G().f(*[a]) # E: Argument 1 to "f" of "G" has incompatible type "*list[A]"; expected "B" | |
| if int(): | |
| ao, ao = G().f(*[a]) | |
| if int(): | |
| aa, aa = G().f(*[a]) | |
| [builtins fixtures/list.pyi] | |
| [case testCallerTupleVarArgsAndGenericCalleeVarArg] | |
| from typing import TypeVar | |
| T = TypeVar('T') | |
| def f(*args: T) -> T: ... | |
| reveal_type(f(*(1, None))) # N: Revealed type is "Literal[1]? | None" | |
| reveal_type(f(1, *(None, 1))) # N: Revealed type is "Literal[1]? | None" | |
| reveal_type(f(1, *(1, None))) # N: Revealed type is "Literal[1]? | None" | |
| [builtins fixtures/tuple.pyi] | |
| -- Comment signatures | |
| -- ------------------ | |
| [case testVarArgsAndCommentSignature] | |
| import typing | |
| def f(*x): # type: (*int) -> None | |
| pass | |
| f(1) | |
| f(1, 2) | |
| f('') # E: Argument 1 to "f" has incompatible type "str"; expected "int" | |
| f(1, '') # E: Argument 2 to "f" has incompatible type "str"; expected "int" | |
| [builtins fixtures/list.pyi] | |
| -- Subtyping | |
| -- --------- | |
| [case testVarArgsFunctionSubtyping] | |
| from typing import Callable | |
| x: Callable[[int], None] | |
| def f(*x: int) -> None: pass | |
| def g(*x: str) -> None: pass | |
| x = f | |
| x = g # E: Incompatible types in assignment (expression has type "def g(*x: str) -> None", variable has type "Callable[[int], None]") | |
| [builtins fixtures/list.pyi] | |
| [out] | |
| -- Decorated method where self is implied by *args | |
| -- ----------------------------------------------- | |
| [case testVarArgsCallableSelf] | |
| from typing import Callable | |
| def cm(func) -> Callable[..., None]: pass | |
| class C: | |
| @cm | |
| def foo(self) -> None: pass | |
| C().foo() | |
| C().foo(1) # The decorator's return type says this should be okay | |
| [case testInvariantDictArgNote] | |
| from typing import Dict, Sequence | |
| def f(x: Dict[str, Sequence[int]]) -> None: pass | |
| def g(x: Dict[str, float]) -> None: pass | |
| def h(x: Dict[str, int]) -> None: pass | |
| a = {'a': [1, 2]} | |
| b = {'b': ['c', 'd']} | |
| c = {'c': 1.0} | |
| d = {'d': 1} | |
| f(a) # E: Argument 1 to "f" has incompatible type "dict[str, list[int]]"; expected "dict[str, Sequence[int]]" \ | |
| # N: "dict" is invariant -- see https://mypy.readthedocs.io/en/stable/common_issues.html#variance \ | |
| # N: Consider using "Mapping" instead, which is covariant in the value type | |
| f(b) # E: Argument 1 to "f" has incompatible type "dict[str, list[str]]"; expected "dict[str, Sequence[int]]" | |
| g(c) | |
| g(d) # E: Argument 1 to "g" has incompatible type "dict[str, int]"; expected "dict[str, float]" \ | |
| # N: "dict" is invariant -- see https://mypy.readthedocs.io/en/stable/common_issues.html#variance \ | |
| # N: Consider using "Mapping" instead, which is covariant in the value type | |
| h(c) # E: Argument 1 to "h" has incompatible type "dict[str, float]"; expected "dict[str, int]" | |
| h(d) | |
| [builtins fixtures/dict.pyi] | |
| [typing fixtures/typing-medium.pyi] | |
| [case testInvariantListArgNote] | |
| from typing import List, Union | |
| def f(numbers: List[Union[int, float]]) -> None: pass | |
| a = [1, 2] | |
| f(a) # E: Argument 1 to "f" has incompatible type "list[int]"; expected "list[int | float]" \ | |
| # N: "list" is invariant -- see https://mypy.readthedocs.io/en/stable/common_issues.html#variance \ | |
| # N: Consider using "Sequence" instead, which is covariant | |
| x = [1] | |
| y = ['a'] | |
| if int(): | |
| x = y # E: Incompatible types in assignment (expression has type "list[str]", variable has type "list[int]") | |
| [builtins fixtures/list.pyi] | |
| [case testInvariantTypeConfusingNames] | |
| from typing import TypeVar | |
| class Listener: pass | |
| class DictReader: pass | |
| def f(x: Listener) -> None: pass | |
| def g(y: DictReader) -> None: pass | |
| a = [1, 2] | |
| b = {'b': 1} | |
| f(a) # E: Argument 1 to "f" has incompatible type "list[int]"; expected "Listener" | |
| g(b) # E: Argument 1 to "g" has incompatible type "dict[str, int]"; expected "DictReader" | |
| [builtins fixtures/dict.pyi] | |
| [case testInvariantTypeConfusingNames2] | |
| from typing import Iterable, Generic, TypeVar, List | |
| T = TypeVar('T') | |
| class I(Iterable[T]): | |
| ... | |
| class Bad(Generic[T]): | |
| ... | |
| def bar(*args: float) -> float: | |
| ... | |
| good1: Iterable[float] | |
| good2: List[float] | |
| good3: I[float] | |
| bad1: I[str] | |
| bad2: Bad[float] | |
| bar(*good1) | |
| bar(*good2) | |
| bar(*good3) | |
| bar(*bad1) # E: Argument 1 to "bar" has incompatible type "*I[str]"; expected "float" | |
| bar(*bad2) # E: Expected iterable as variadic argument | |
| [builtins fixtures/dict.pyi] | |
| -- Keyword arguments unpacking | |
| [case testUnpackKwargsReveal] | |
| from typing import TypedDict | |
| from typing_extensions import Unpack | |
| class Person(TypedDict): | |
| name: str | |
| age: int | |
| def foo(arg: bool, **kwargs: Unpack[Person]) -> None: ... | |
| reveal_type(foo) # N: Revealed type is "def (arg: builtins.bool, **kwargs: Unpack[TypedDict('__main__.Person', {'name': builtins.str, 'age': builtins.int})])" | |
| [builtins fixtures/dict.pyi] | |
| [typing fixtures/typing-typeddict.pyi] | |
| [case testUnpackOutsideOfKwargs] | |
| from typing import TypedDict | |
| from typing_extensions import Unpack | |
| class Person(TypedDict): | |
| name: str | |
| age: int | |
| def foo(x: Unpack[Person]) -> None: # E: Unpack is only valid in a variadic position | |
| ... | |
| def bar(x: int, *args: Unpack[Person]) -> None: # E: "Person" cannot be unpacked (must be tuple or TypeVarTuple) | |
| ... | |
| def baz(**kwargs: Unpack[Person]) -> None: # OK | |
| ... | |
| [builtins fixtures/dict.pyi] | |
| [typing fixtures/typing-typeddict.pyi] | |
| [case testUnpackWithoutTypedDict] | |
| from typing_extensions import Unpack | |
| def foo(**kwargs: Unpack[dict]) -> None: # E: Unpack item in ** parameter must be a TypedDict | |
| ... | |
| [builtins fixtures/dict.pyi] | |
| [case testUnpackWithDuplicateKeywords] | |
| from typing import TypedDict | |
| from typing_extensions import Unpack | |
| class Person(TypedDict): | |
| name: str | |
| age: int | |
| def foo(name: str, **kwargs: Unpack[Person]) -> None: # E: Overlap between parameter names and ** TypedDict items: "name" | |
| ... | |
| [builtins fixtures/dict.pyi] | |
| [typing fixtures/typing-typeddict.pyi] | |
| [case testUnpackWithDuplicateKeywordKwargs] | |
| from typing_extensions import Unpack | |
| from typing import Dict, List, TypedDict | |
| class Spec(TypedDict): | |
| args: List[int] | |
| kwargs: Dict[int, int] | |
| def foo(**kwargs: Unpack[Spec]) -> None: # Allowed | |
| ... | |
| foo(args=[1], kwargs={"2": 3}) # E: Dict entry 0 has incompatible type "str": "int"; expected "int": "int" | |
| [builtins fixtures/dict.pyi] | |
| [typing fixtures/typing-typeddict.pyi] | |
| [case testUnpackKwargsNonIdentifier] | |
| from typing import TypedDict | |
| from typing_extensions import Unpack | |
| Weird = TypedDict("Weird", {"@": int}) | |
| def foo(**kwargs: Unpack[Weird]) -> None: | |
| reveal_type(kwargs["@"]) # N: Revealed type is "builtins.int" | |
| foo(**{"@": 42}) | |
| foo(**{"no": "way"}) # E: Argument 1 to "foo" has incompatible type "**dict[str, str]"; expected "int" | |
| [builtins fixtures/dict.pyi] | |
| [typing fixtures/typing-typeddict.pyi] | |
| [case testUnpackKwargsEmpty] | |
| from typing import TypedDict | |
| from typing_extensions import Unpack | |
| Empty = TypedDict("Empty", {}) | |
| def foo(**kwargs: Unpack[Empty]) -> None: | |
| reveal_type(kwargs) # N: Revealed type is "TypedDict('__main__.Empty', {})" | |
| foo() | |
| foo(x=1) # E: Unexpected keyword argument "x" for "foo" | |
| [builtins fixtures/dict.pyi] | |
| [typing fixtures/typing-typeddict.pyi] | |
| [case testUnpackTypedDictTotality] | |
| from typing import TypedDict | |
| from typing_extensions import Unpack | |
| class Circle(TypedDict, total=True): | |
| radius: int | |
| color: str | |
| x: int | |
| y: int | |
| def foo(**kwargs: Unpack[Circle]): | |
| ... | |
| foo(x=0, y=0, color='orange') # E: Missing named argument "radius" for "foo" | |
| class Square(TypedDict, total=False): | |
| side: int | |
| color: str | |
| def bar(**kwargs: Unpack[Square]): | |
| ... | |
| bar(side=12) | |
| [builtins fixtures/dict.pyi] | |
| [typing fixtures/typing-typeddict.pyi] | |
| [case testUnpackUnexpectedKeyword] | |
| from typing import TypedDict | |
| from typing_extensions import Unpack | |
| class Person(TypedDict, total=False): | |
| name: str | |
| age: int | |
| def foo(**kwargs: Unpack[Person]) -> None: | |
| ... | |
| foo(name='John', age=42, department='Sales') # E: Unexpected keyword argument "department" for "foo" | |
| foo(name='Jennifer', age=38) | |
| [builtins fixtures/dict.pyi] | |
| [typing fixtures/typing-typeddict.pyi] | |
| [case testUnpackKeywordTypes] | |
| from typing import TypedDict | |
| from typing_extensions import Unpack | |
| class Person(TypedDict): | |
| name: str | |
| age: int | |
| def foo(**kwargs: Unpack[Person]): | |
| ... | |
| foo(name='John', age='42') # E: Argument "age" to "foo" has incompatible type "str"; expected "int" | |
| foo(name='Jennifer', age=38) | |
| [builtins fixtures/dict.pyi] | |
| [typing fixtures/typing-typeddict.pyi] | |
| [case testUnpackKeywordTypesTypedDict] | |
| from typing import TypedDict | |
| from typing_extensions import Unpack | |
| class Person(TypedDict): | |
| name: str | |
| age: int | |
| class LegacyPerson(TypedDict): | |
| name: str | |
| age: str | |
| def foo(**kwargs: Unpack[Person]) -> None: | |
| ... | |
| lp = LegacyPerson(name="test", age="42") | |
| foo(**lp) # E: Argument "age" to "foo" has incompatible type "str"; expected "int" | |
| [builtins fixtures/dict.pyi] | |
| [typing fixtures/typing-typeddict.pyi] | |
| [case testFunctionBodyWithUnpackedKwargs] | |
| from typing import TypedDict | |
| from typing_extensions import Unpack | |
| class Person(TypedDict): | |
| name: str | |
| age: int | |
| def foo(**kwargs: Unpack[Person]) -> int: | |
| name: str = kwargs['name'] | |
| age: str = kwargs['age'] # E: Incompatible types in assignment (expression has type "int", variable has type "str") | |
| department: str = kwargs['department'] # E: TypedDict "Person" has no key "department" | |
| return kwargs['age'] | |
| [builtins fixtures/dict.pyi] | |
| [typing fixtures/typing-typeddict.pyi] | |
| [case testUnpackKwargsOverrides] | |
| from typing import TypedDict | |
| from typing_extensions import Unpack | |
| class Person(TypedDict): | |
| name: str | |
| age: int | |
| class Base: | |
| def foo(self, **kwargs: Unpack[Person]) -> None: ... | |
| class SubGood(Base): | |
| def foo(self, *, name: str, age: int, extra: bool = False) -> None: ... | |
| class SubBad(Base): | |
| def foo(self, *, name: str, age: str) -> None: ... # E: Argument 2 of "foo" is incompatible with supertype "Base"; supertype defines the argument type as "int" \ | |
| # N: This violates the Liskov substitution principle \ | |
| # N: See https://mypy.readthedocs.io/en/stable/common_issues.html#incompatible-overrides | |
| [builtins fixtures/dict.pyi] | |
| [typing fixtures/typing-typeddict.pyi] | |
| [case testUnpackKwargsOverridesTypedDict] | |
| from typing import TypedDict | |
| from typing_extensions import Unpack | |
| class Person(TypedDict): | |
| name: str | |
| age: int | |
| class PersonExtra(Person, total=False): | |
| extra: bool | |
| class Unrelated(TypedDict): | |
| baz: int | |
| class Base: | |
| def foo(self, **kwargs: Unpack[Person]) -> None: ... | |
| class SubGood(Base): | |
| def foo(self, **kwargs: Unpack[PersonExtra]) -> None: ... | |
| class SubBad(Base): | |
| def foo(self, **kwargs: Unpack[Unrelated]) -> None: ... # E: Signature of "foo" incompatible with supertype "Base" \ | |
| # N: Superclass: \ | |
| # N: def foo(*, name: str, age: int) -> None \ | |
| # N: Subclass: \ | |
| # N: def foo(self, *, baz: int) -> None | |
| [builtins fixtures/dict.pyi] | |
| [typing fixtures/typing-typeddict.pyi] | |
| [case testUnpackKwargsGeneric] | |
| from typing import Generic, TypedDict, TypeVar | |
| from typing_extensions import Unpack | |
| T = TypeVar("T") | |
| class Person(TypedDict, Generic[T]): | |
| name: str | |
| value: T | |
| def foo(**kwargs: Unpack[Person[T]]) -> T: ... | |
| reveal_type(foo(name="test", value=42)) # N: Revealed type is "builtins.int" | |
| [builtins fixtures/dict.pyi] | |
| [typing fixtures/typing-typeddict.pyi] | |
| [case testUnpackKwargsInference] | |
| from typing import Generic, TypedDict, TypeVar, Protocol | |
| from typing_extensions import Unpack | |
| T_contra = TypeVar("T_contra", contravariant=True) | |
| class CBPerson(Protocol[T_contra]): | |
| def __call__(self, **kwargs: Unpack[Person[T_contra]]) -> None: ... | |
| T = TypeVar("T") | |
| class Person(TypedDict, Generic[T]): | |
| name: str | |
| value: T | |
| def test(cb: CBPerson[T]) -> T: ... | |
| def foo(*, name: str, value: int) -> None: ... | |
| reveal_type(test(foo)) # N: Revealed type is "builtins.int" | |
| [builtins fixtures/dict.pyi] | |
| [typing fixtures/typing-typeddict.pyi] | |
| [case testUnpackKwargsOverload] | |
| from typing import TypedDict, Any, overload | |
| from typing_extensions import Unpack | |
| class Person(TypedDict): | |
| name: str | |
| age: int | |
| class Fruit(TypedDict): | |
| sort: str | |
| taste: int | |
| @overload | |
| def foo(**kwargs: Unpack[Person]) -> int: ... | |
| @overload | |
| def foo(**kwargs: Unpack[Fruit]) -> str: ... | |
| def foo(**kwargs: Any) -> Any: | |
| ... | |
| reveal_type(foo(sort="test", taste=999)) # N: Revealed type is "builtins.str" | |
| [builtins fixtures/dict.pyi] | |
| [typing fixtures/typing-typeddict.pyi] | |
| [case testUnpackKwargsJoin] | |
| from typing import TypedDict | |
| from typing_extensions import Unpack | |
| class Person(TypedDict): | |
| name: str | |
| age: int | |
| def foo(*, name: str, age: int) -> None: ... | |
| def bar(**kwargs: Unpack[Person]) -> None: ... | |
| reveal_type([foo, bar]) # N: Revealed type is "builtins.list[def (*, name: builtins.str, age: builtins.int)]" | |
| reveal_type([bar, foo]) # N: Revealed type is "builtins.list[def (*, name: builtins.str, age: builtins.int)]" | |
| [builtins fixtures/dict.pyi] | |
| [typing fixtures/typing-typeddict.pyi] | |
| [case testUnpackKwargsParamSpec] | |
| from typing import Callable, Any, TypedDict, TypeVar, List | |
| from typing_extensions import ParamSpec, Unpack | |
| class Person(TypedDict): | |
| name: str | |
| age: int | |
| P = ParamSpec('P') | |
| T = TypeVar('T') | |
| def dec(f: Callable[P, T]) -> Callable[P, List[T]]: ... | |
| @dec | |
| def g(**kwargs: Unpack[Person]) -> int: ... | |
| reveal_type(g) # N: Revealed type is "def (*, name: builtins.str, age: builtins.int) -> builtins.list[builtins.int]" | |
| [builtins fixtures/dict.pyi] | |
| [typing fixtures/typing-typeddict.pyi] | |
| [case testUnpackGenericTypedDictImplicitAnyEnabled] | |
| from typing import Generic, TypedDict, TypeVar | |
| from typing_extensions import Unpack | |
| T = TypeVar("T") | |
| class TD(TypedDict, Generic[T]): | |
| key: str | |
| value: T | |
| def foo(**kwds: Unpack[TD]) -> None: ... # Same as `TD[Any]` | |
| foo(key="yes", value=42) | |
| foo(key="yes", value="ok") | |
| [builtins fixtures/dict.pyi] | |
| [typing fixtures/typing-typeddict.pyi] | |
| [case testUnpackGenericTypedDictImplicitAnyDisabled] | |
| # flags: --disallow-any-generics | |
| from typing import Generic, TypedDict, TypeVar | |
| from typing_extensions import Unpack | |
| T = TypeVar("T") | |
| class TD(TypedDict, Generic[T]): | |
| key: str | |
| value: T | |
| def foo(**kwds: Unpack[TD]) -> None: ... # E: Missing type arguments for generic type "TD" | |
| foo(key="yes", value=42) | |
| foo(key="yes", value="ok") | |
| [builtins fixtures/dict.pyi] | |
| [typing fixtures/typing-typeddict.pyi] | |
| [case testUnpackNoCrashOnEmpty] | |
| from typing_extensions import Unpack | |
| class C: | |
| def __init__(self, **kwds: Unpack) -> None: ... # E: Unpack[...] requires exactly one type argument | |
| class D: | |
| def __init__(self, **kwds: Unpack[int, str]) -> None: ... # E: Unpack[...] requires exactly one type argument | |
| [builtins fixtures/dict.pyi] | |
| [case testUnpackInCallableType] | |
| # flags: --python-version 3.11 | |
| from typing import Callable, TypedDict | |
| from typing_extensions import Unpack | |
| class TD(TypedDict): | |
| key: str | |
| value: str | |
| foo: Callable[[Unpack[TD]], None] | |
| foo(key="yes", value=42) # E: Argument "value" has incompatible type "int"; expected "str" | |
| foo(key="yes", value="ok") | |
| bad: Callable[[*TD], None] # E: "TD" cannot be unpacked (must be tuple or TypeVarTuple) | |
| [builtins fixtures/dict.pyi] | |
| [typing fixtures/typing-typeddict.pyi] |