blob: fe09fb43c97c38d35ab0193b555ab78fe733022c [file] [log] [blame] [edit]
-- 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
f(a, g()) # E: "g" does not return a value
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 "Optional[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()
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]
-- 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]
# flags: --no-strict-optional
def f(a: 'A') -> None:
pass
class A: pass
a = None # type: A
f(*None)
f(*a) # E: List or tuple expected as variadic arguments
f(*(a,))
[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 "Optional[B]" \
# 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 "Optional[B]"
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: List or tuple expected as variadic arguments
if int():
a, b = f(*a) # E: List or tuple expected as variadic arguments
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") \
# E: Incompatible types in assignment (expression has type "List[<nothing>]", variable has type "List[A]") \
# N: "List" is invariant -- see https://mypy.readthedocs.io/en/stable/common_issues.html#variance \
# N: Consider using "Sequence" instead, which is covariant
if int():
aa, a = G().f(*[a]) # E: Incompatible types in assignment (expression has type "List[<nothing>]", variable has type "A")
if int():
ab, aa = G().f(*[a]) \
# E: Incompatible types in assignment (expression has type "List[<nothing>]", variable has type "List[A]") \
# N: "List" is invariant -- see https://mypy.readthedocs.io/en/stable/common_issues.html#variance \
# N: Consider using "Sequence" instead, which is covariant \
# E: Argument 1 to "f" of "G" has incompatible type "*List[A]"; expected "B"
if int():
ao, ao = G().f(*[a]) \
# E: Incompatible types in assignment (expression has type "List[<nothing>]", variable has type "List[object]") \
# N: "List" is invariant -- see https://mypy.readthedocs.io/en/stable/common_issues.html#variance \
# N: Consider using "Sequence" instead, which is covariant
if int():
aa, aa = G().f(*[a]) \
# E: Incompatible types in assignment (expression has type "List[<nothing>]", variable has type "List[A]") \
# N: "List" is invariant -- see https://mypy.readthedocs.io/en/stable/common_issues.html#variance \
# N: Consider using "Sequence" instead, which is covariant
[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 "Union[Literal[1]?, None]"
reveal_type(f(1, *(None, 1))) # N: Revealed type is "Union[Literal[1]?, None]"
reveal_type(f(1, *(1, None))) # N: Revealed type is "Union[builtins.int, 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 "Callable[[VarArg(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[Union[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: List or tuple expected as variadic arguments
[builtins fixtures/dict.pyi]
-- Keyword arguments unpacking
[case testUnpackKwargsReveal]
from typing_extensions import Unpack, TypedDict
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]
[case testUnpackOutsideOfKwargs]
from typing_extensions import Unpack, TypedDict
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]
[case testUnpackWithoutTypedDict]
from typing_extensions import Unpack
def foo(**kwargs: Unpack[dict]) -> None: # E: Unpack item in ** argument must be a TypedDict
...
[builtins fixtures/dict.pyi]
[case testUnpackWithDuplicateKeywords]
from typing_extensions import Unpack, TypedDict
class Person(TypedDict):
name: str
age: int
def foo(name: str, **kwargs: Unpack[Person]) -> None: # E: Overlap between argument names and ** TypedDict items: "name"
...
[builtins fixtures/dict.pyi]
[case testUnpackWithDuplicateKeywordKwargs]
from typing_extensions import Unpack, TypedDict
from typing import Dict, List
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]
[case testUnpackKwargsNonIdentifier]
from typing_extensions import Unpack, TypedDict
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]
[case testUnpackKwargsEmpty]
from typing_extensions import Unpack, TypedDict
Empty = TypedDict("Empty", {})
def foo(**kwargs: Unpack[Empty]) -> None: # N: "foo" defined here
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]
[case testUnpackTypedDictTotality]
from typing_extensions import Unpack, TypedDict
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]
[case testUnpackUnexpectedKeyword]
from typing_extensions import Unpack, TypedDict
class Person(TypedDict, total=False):
name: str
age: int
def foo(**kwargs: Unpack[Person]) -> None: # N: "foo" defined here
...
foo(name='John', age=42, department='Sales') # E: Unexpected keyword argument "department" for "foo"
foo(name='Jennifer', age=38)
[builtins fixtures/dict.pyi]
[case testUnpackKeywordTypes]
from typing_extensions import Unpack, TypedDict
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]
[case testUnpackKeywordTypesTypedDict]
from typing_extensions import Unpack, TypedDict
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]
[case testFunctionBodyWithUnpackedKwargs]
from typing_extensions import Unpack, TypedDict
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]
[case testUnpackKwargsOverrides]
from typing_extensions import Unpack, TypedDict
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]
[case testUnpackKwargsOverridesTypedDict]
from typing_extensions import Unpack, TypedDict
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]
[case testUnpackKwargsGeneric]
from typing import Generic, TypeVar
from typing_extensions import Unpack, TypedDict
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]
[case testUnpackKwargsInference]
from typing import Generic, TypeVar, Protocol
from typing_extensions import Unpack, TypedDict
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]
[case testUnpackKwargsOverload]
from typing import Any, overload
from typing_extensions import Unpack, TypedDict
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]
[case testUnpackKwargsJoin]
from typing_extensions import Unpack, TypedDict
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]
[case testUnpackKwargsParamSpec]
from typing import Callable, Any, TypeVar, List
from typing_extensions import ParamSpec, Unpack, TypedDict
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]
[case testUnpackGenericTypedDictImplicitAnyEnabled]
from typing import Generic, TypeVar
from typing_extensions import Unpack, TypedDict
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]
[case testUnpackGenericTypedDictImplicitAnyDisabled]
# flags: --disallow-any-generics
from typing import Generic, TypeVar
from typing_extensions import Unpack, TypedDict
T = TypeVar("T")
class TD(TypedDict, Generic[T]):
key: str
value: T
def foo(**kwds: Unpack[TD]) -> None: ... # E: Missing type parameters for generic type "TD"
foo(key="yes", value=42)
foo(key="yes", value="ok")
[builtins fixtures/dict.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]