2Tests subtyping rules for callables.
5# Specification: https://typing.readthedocs.io/en/latest/spec/callables.html#subtyping-rules-for-callables
7from typing import Callable, ParamSpec, Protocol, TypeAlias, overload
11# > Callable types are covariant with respect to their return types but
12# > contravariant with respect to their parameter types.
16 cb1: Callable[[float], int],
17 cb2: Callable[[float], float],
18 cb3: Callable[[int], int],
20 f1: Callable[[int], float] = cb1 # OK
21 f2: Callable[[int], float] = cb2 # OK
22 f3: Callable[[int], float] = cb3 # OK
24 f4: Callable[[float], float] = cb1 # OK
25 f5: Callable[[float], float] = cb2 # OK
26 f6: Callable[[float], float] = cb3 # E
[invalid-assignment] Object of type `(int, /) -> int` is not assignable to `(int | float, /) -> int | float`
28 f7: Callable[[int], int] = cb1 # OK
29 f8: Callable[[int], int] = cb2 # E
[invalid-assignment] Object of type `(int | float, /) -> int | float` is not assignable to `(int, /) -> int`
30 f9: Callable[[int], int] = cb3 # OK
33# > Callable A is a subtype of callable B if all keyword-only parameters in B
34# > are present in A as either keyword-only parameters or standard (positional
35# > or keyword) parameters.
38class PosOnly2(Protocol):
39 def __call__(self, b: int, a: int, /) -> None: ...
42class KwOnly2(Protocol):
43 def __call__(self, *, b: int, a: int) -> None: ...
46class Standard2(Protocol):
47 def __call__(self, a: int, b: int) -> None: ...
50def func2(standard: Standard2, pos_only: PosOnly2, kw_only: KwOnly2):
51 f1: Standard2 = pos_only # E
[invalid-assignment] Object of type `PosOnly2` is not assignable to `Standard2`
52 f2: Standard2 = kw_only # E
[invalid-assignment] Object of type `KwOnly2` is not assignable to `Standard2`
54 f3: PosOnly2 = standard # OK
55 f4: PosOnly2 = kw_only # E
[invalid-assignment] Object of type `KwOnly2` is not assignable to `PosOnly2`
57 f5: KwOnly2 = standard # OK
58 f6: KwOnly2 = pos_only # E
[invalid-assignment] Object of type `PosOnly2` is not assignable to `KwOnly2`
61# > If a callable B has a signature with a *args parameter, callable A
62# > must also have a *args parameter to be a subtype of B, and the type of
63# > B’s *args parameter must be a subtype of A’s *args parameter.
66class NoArgs3(Protocol):
67 def __call__(self) -> None: ...
70class IntArgs3(Protocol):
71 def __call__(self, *args: int) -> None: ...
74class FloatArgs3(Protocol):
75 def __call__(self, *args: float) -> None: ...
78def func3(no_args: NoArgs3, int_args: IntArgs3, float_args: FloatArgs3):
79 f1: NoArgs3 = int_args # OK
80 f2: NoArgs3 = float_args # OK
82 f3: IntArgs3 = no_args # E: missing *args parameter
[invalid-assignment] Object of type `NoArgs3` is not assignable to `IntArgs3`
83 f4: IntArgs3 = float_args # OK
85 f5: FloatArgs3 = no_args # E: missing *args parameter
[invalid-assignment] Object of type `NoArgs3` is not assignable to `FloatArgs3`
86 f6: FloatArgs3 = int_args # E: float is not subtype of int
[invalid-assignment] Object of type `IntArgs3` is not assignable to `FloatArgs3`
89# > If a callable B has a signature with one or more positional-only parameters,
90# > a callable A is a subtype of B if A has an *args parameter whose type is a
91# > supertype of the types of any otherwise-unmatched positional-only parameters
95class PosOnly4(Protocol):
96 def __call__(self, a: int, b: str, /) -> None: ...
99class IntArgs4(Protocol):
100 def __call__(self, *args: int) -> None: ...
103class IntStrArgs4(Protocol):
104 def __call__(self, *args: int | str) -> None: ...
107class StrArgs4(Protocol):
108 def __call__(self, a: int, /, *args: str) -> None: ...
111class Standard4(Protocol):
112 def __call__(self, a: int, b: str) -> None: ...
115def func4(int_args: IntArgs4, int_str_args: IntStrArgs4, str_args: StrArgs4):
116 f1: PosOnly4 = int_args # E: str is not subtype of int
[invalid-assignment] Object of type `IntArgs4` is not assignable to `PosOnly4`
117 f2: PosOnly4 = int_str_args # OK
118 f3: PosOnly4 = str_args # OK
119 f4: IntStrArgs4 = str_args # E: int | str is not subtype of str
[invalid-assignment] Object of type `StrArgs4` is not assignable to `IntStrArgs4`
120 f5: IntStrArgs4 = int_args # E: int | str is not subtype of int
[invalid-assignment] Object of type `IntArgs4` is not assignable to `IntStrArgs4`
121 f6: StrArgs4 = int_str_args # OK
122 f7: StrArgs4 = int_args # E: str is not subtype of int
[invalid-assignment] Object of type `IntArgs4` is not assignable to `StrArgs4`
123 f8: IntArgs4 = int_str_args # OK
124 f9: IntArgs4 = str_args # E: int is not subtype of str
[invalid-assignment] Object of type `StrArgs4` is not assignable to `IntArgs4`
125 f10: Standard4 = int_str_args # E: keyword parameters a and b missing
Expected a ty diagnostic for this line
126 f11: Standard4 = str_args # E: keyword parameter b missing
[invalid-assignment] Object of type `StrArgs4` is not assignable to `Standard4`
129# > If a callable B has a signature with a **kwargs parameter (without an
130# > unpacked TypedDict type annotation), callable A must also have a **kwargs
131# > parameter to be a subtype of B, and the type of B’s **kwargs parameter
132# > must be a subtype of A’s **kwargs parameter.
135class NoKwargs5(Protocol):
136 def __call__(self) -> None: ...
139class IntKwargs5(Protocol):
140 def __call__(self, **kwargs: int) -> None: ...
143class FloatKwargs5(Protocol):
144 def __call__(self, **kwargs: float) -> None: ...
147def func5(no_kwargs: NoKwargs5, int_kwargs: IntKwargs5, float_kwargs: FloatKwargs5):
148 f1: NoKwargs5 = int_kwargs # OK
149 f2: NoKwargs5 = float_kwargs # OK
151 f3: IntKwargs5 = no_kwargs # E: missing **kwargs parameter
[invalid-assignment] Object of type `NoKwargs5` is not assignable to `IntKwargs5`
152 f4: IntKwargs5 = float_kwargs # OK
154 f5: FloatKwargs5 = no_kwargs # E: missing **kwargs parameter
[invalid-assignment] Object of type `NoKwargs5` is not assignable to `FloatKwargs5`
155 f6: FloatKwargs5 = int_kwargs # E: float is not subtype of int
[invalid-assignment] Object of type `IntKwargs5` is not assignable to `FloatKwargs5`
158# > If a callable B has a signature with one or more keyword-only parameters,
159# > a callable A is a subtype of B if A has a **kwargs parameter whose type
160# > is a supertype of the types of any otherwise-unmatched keyword-only
164class KwOnly6(Protocol):
165 def __call__(self, *, a: int, b: str) -> None: ...
168class IntKwargs6(Protocol):
169 def __call__(self, **kwargs: int) -> None: ...
172class IntStrKwargs6(Protocol):
173 def __call__(self, **kwargs: int | str) -> None: ...
176class StrKwargs6(Protocol):
177 def __call__(self, *, a: int, **kwargs: str) -> None: ...
180class Standard6(Protocol):
181 def __call__(self, a: int, b: str) -> None: ...
185 int_kwargs: IntKwargs6, int_str_kwargs: IntStrKwargs6, str_kwargs: StrKwargs6
187 f1: KwOnly6 = int_kwargs # E: str is not subtype of int
[invalid-assignment] Object of type `IntKwargs6` is not assignable to `KwOnly6`
188 f2: KwOnly6 = int_str_kwargs # OK
189 f3: KwOnly6 = str_kwargs # OK
190 f4: IntStrKwargs6 = str_kwargs # E: int | str is not subtype of str
[invalid-assignment] Object of type `StrKwargs6` is not assignable to `IntStrKwargs6`
191 f5: IntStrKwargs6 = int_kwargs # E: int | str is not subtype of int
[invalid-assignment] Object of type `IntKwargs6` is not assignable to `IntStrKwargs6`
192 f6: StrKwargs6 = int_str_kwargs # OK
193 f7: StrKwargs6 = int_kwargs # E: str is not subtype of int
[invalid-assignment] Object of type `IntKwargs6` is not assignable to `StrKwargs6`
194 f8: IntKwargs6 = int_str_kwargs # OK
195 f9: IntKwargs6 = str_kwargs # E: int is not subtype of str
[invalid-assignment] Object of type `StrKwargs6` is not assignable to `IntKwargs6`
196 f10: Standard6 = int_str_kwargs # E: Does not accept positional arguments
[invalid-assignment] Object of type `IntStrKwargs6` is not assignable to `Standard6`
197 f11: Standard6 = str_kwargs # E: Does not accept positional arguments
[invalid-assignment] Object of type `StrKwargs6` is not assignable to `Standard6`
200# > A signature that includes *args: P.args, **kwargs: P.kwargs is equivalent
201# > to a Callable parameterized by P.
204class ProtocolWithP(Protocol[P]):
205 def __call__(self, *args: P.args, **kwargs: P.kwargs) -> None: ...
208TypeAliasWithP: TypeAlias = Callable[P, None]
211def func7(proto: ProtocolWithP[P], ta: TypeAliasWithP[P]):
212 # These two types are equivalent
213 f1: TypeAliasWithP[P] = proto # OK
214 f2: ProtocolWithP[P] = ta # OK
217# > If a callable A has a parameter x with a default argument value and B is
218# > the same as A except that x has no default argument, then A is a subtype
219# > of B. A is also a subtype of C if C is the same as A with parameter x
223class DefaultArg8(Protocol):
224 def __call__(self, x: int = 0) -> None: ...
227class NoDefaultArg8(Protocol):
228 def __call__(self, x: int) -> None: ...
232 def __call__(self) -> None: ...
235def func8(default_arg: DefaultArg8, no_default_arg: NoDefaultArg8, no_x: NoX8):
236 f1: DefaultArg8 = no_default_arg # E
[invalid-assignment] Object of type `NoDefaultArg8` is not assignable to `DefaultArg8`
237 f2: DefaultArg8 = no_x # E
[invalid-assignment] Object of type `NoX8` is not assignable to `DefaultArg8`
239 f3: NoDefaultArg8 = default_arg # OK
240 f4: NoDefaultArg8 = no_x # E
[invalid-assignment] Object of type `NoX8` is not assignable to `NoDefaultArg8`
242 f5: NoX8 = default_arg # OK
243 f6: NoX8 = no_default_arg # E
[invalid-assignment] Object of type `NoDefaultArg8` is not assignable to `NoX8`
246# > If a callable A is overloaded with two or more signatures, it is a subtype
247# > of callable B if at least one of the overloaded signatures in A is a
251class Overloaded9(Protocol):
253 def __call__(self, x: int) -> int: ...
255 def __call__(self, x: str) -> str: ...
258class IntArg9(Protocol):
259 def __call__(self, x: int) -> int: ...
262class StrArg9(Protocol):
263 def __call__(self, x: str) -> str: ...
266class FloatArg9(Protocol):
267 def __call__(self, x: float) -> float: ...
270def func9(overloaded: Overloaded9):
271 f1: IntArg9 = overloaded # OK
272 f2: StrArg9 = overloaded # OK
273 f3: FloatArg9 = overloaded # E
[invalid-assignment] Object of type `Overloaded9` is not assignable to `FloatArg9`
276# > If a callable B is overloaded with two or more signatures, callable A is
277# > a subtype of B if A is a subtype of all of the signatures in B.
280class Overloaded10(Protocol):
282 def __call__(self, x: int, y: str) -> float: ...
284 def __call__(self, x: str) -> complex: ...
287class StrArg10(Protocol):
288 def __call__(self, x: str) -> complex: ...
291class IntStrArg10(Protocol):
292 def __call__(self, x: int | str, y: str = "") -> int: ...
295def func10(int_str_arg: IntStrArg10, str_arg: StrArg10):
296 f1: Overloaded10 = int_str_arg # OK
297 f2: Overloaded10 = str_arg # E
[invalid-assignment] Object of type `StrArg10` is not assignable to `Overloaded10`