2Tests handling of callback protocols.
5# Specification: https://typing.readthedocs.io/en/latest/spec/callables.html#callback-protocols
7from typing import Any, Callable, ParamSpec, Protocol, TypeVar, cast, overload
9InputT = TypeVar("InputT", contravariant=True)
10OutputT = TypeVar("OutputT", covariant=True)
13class Proto1(Protocol):
14 def __call__(self, *vals: bytes, max_len: int | None = None) -> list[bytes]:
18def cb1_good1(*vals: bytes, max_len: int | None = None) -> list[bytes]:
22def cb1_bad1(*vals: bytes, max_items: int | None) -> list[bytes]:
26def cb1_bad2(*vals: bytes) -> list[bytes]:
30def cb1_bad3(*vals: bytes, max_len: str | None) -> list[bytes]:
34cb1: Proto1 = cb1_good1 # OK
35cb1 = cb1_bad1 # E: different names
[invalid-assignment] Object of type `def cb1_bad1(*vals: bytes, *, max_items: int | None) -> list[bytes]` is not assignable to `Proto1`
36cb1 = cb1_bad2 # E: parameter types
[invalid-assignment] Object of type `def cb1_bad2(*vals: bytes) -> list[bytes]` is not assignable to `Proto1`
37cb1 = cb1_bad3 # E: default argument
[invalid-assignment] Object of type `def cb1_bad3(*vals: bytes, *, max_len: str | None) -> list[bytes]` is not assignable to `Proto1`
40class Proto2(Protocol):
41 def __call__(self, *vals: bytes, **kwargs: str) -> None:
45def cb2_good1(*a: bytes, **b: str):
49def cb2_bad1(*a: bytes):
53def cb2_bad2(*a: str, **b: str):
57def cb2_bad3(*a: bytes, **b: bytes):
61def cb2_bad4(**b: str):
65cb2: Proto2 = cb2_good1 # OK
67cb2 = cb2_bad1 # E: missing **kwargs
[invalid-assignment] Object of type `def cb2_bad1(*a: bytes) -> Unknown` is not assignable to `Proto2`
68cb2 = cb2_bad2 # E: parameter type
[invalid-assignment] Object of type `def cb2_bad2(*a: str, **b: str) -> Unknown` is not assignable to `Proto2`
69cb2 = cb2_bad3 # E: parameter type
[invalid-assignment] Object of type `def cb2_bad3(*a: bytes, **b: bytes) -> Unknown` is not assignable to `Proto2`
70cb2 = cb2_bad4 # E: missing parameter
[invalid-assignment] Object of type `def cb2_bad4(**b: str) -> Unknown` is not assignable to `Proto2`
73class Proto3(Protocol):
74 def __call__(self) -> None:
78cb3: Proto3 = cb2_good1 # OK
85# A callback protocol with other attributes.
86class Proto4(Protocol):
89 def __call__(self, x: int) -> None:
93def cb4_bad1(x: int) -> None:
97var4: Proto4 = cb4_bad1 # E: missing attribute
[invalid-assignment] Object of type `def cb4_bad1(x: int) -> None` is not assignable to `Proto4`
100class Proto5(Protocol):
101 def __call__(self, *, a: int, b: str) -> int:
105def cb5_good1(a: int, b: str) -> int:
109cb5: Proto5 = cb5_good1 # OK
113 def __call__(self, *vals: bytes, maxlen: int | None = None) -> list[bytes]:
117def cb6_bad1(*vals: bytes, max_len: int | None = None) -> list[bytes]:
121cb6: NotProto6 = cb6_bad1 # E: NotProto6 isn't a protocol class
[invalid-assignment] Object of type `def cb6_bad1(*vals: bytes, *, max_len: int | None = None) -> list[bytes]` is not assignable to `NotProto6`
124class Proto7(Protocol[InputT, OutputT]):
125 def __call__(self, inputs: InputT) -> OutputT:
130 # Test for unannotated parameter.
131 def __call__(self, inputs) -> int:
135cb7_1: Proto7[int, int] = Class7_1() # OK
139 # Test for parameter with type Any.
140 def __call__(self, inputs: Any) -> int:
144cb7_2: Proto7[int, int] = Class7_2() # OK
147class Proto8(Protocol):
149 def __call__(self, x: int) -> int:
153 def __call__(self, x: str) -> str:
156 def __call__(self, x: Any) -> Any:
160def cb8_good1(x: Any) -> Any:
164def cb8_bad1(x: int) -> Any:
168cb8: Proto8 = cb8_good1 # OK
169cb8 = cb8_bad1 # E: parameter type
[invalid-assignment] Object of type `def cb8_bad1(x: int) -> Any` is not assignable to `Proto8`
173R = TypeVar("R", covariant=True)
176class Proto9(Protocol[P, R]):
179 def __call__(self, *args: P.args, **kwargs: P.kwargs) -> R:
183def decorator1(f: Callable[P, R]) -> Proto9[P, R]:
184 converted = cast(Proto9[P, R], f)
185 converted.other_attribute = 1
186 converted.other_attribute = "str" # E: incompatible type
[invalid-assignment] Object of type `Literal["str"]` is not assignable to attribute `other_attribute` of type `int`
187 converted.xxx = 3 # E: unknown attribute
[unresolved-attribute] Unresolved attribute `xxx` on type `Proto9[P@decorator1, R@decorator1]`
192def cb9_good(x: int) -> str:
196print(cb9_good.other_attribute) # OK
197print(cb9_good.other_attribute2) # E: unknown attribute
[unresolved-attribute] Object of type `Proto9[(x: int), str]` has no attribute `other_attribute2`
202class Proto10(Protocol):
206 __annotations__: dict[str, Any]
208 def __call__(self) -> None:
212def cb10_good() -> None:
216cb10: Proto10 = cb10_good # OK
219class Proto11(Protocol):
220 def __call__(self, x: int, /, y: str) -> Any:
224def cb11_good1(x: int, /, y: str, z: None = None) -> Any:
228def cb11_good2(x: int, y: str, z: None = None) -> Any:
232def cb11_bad1(x: int, y: str, /) -> Any:
236cb11: Proto11 = cb11_good1 # OK
237cb11 = cb11_good2 # OK
238cb11 = cb11_bad1 # E: y is position-only
[invalid-assignment] Object of type `def cb11_bad1(x: int, y: str, /) -> Any` is not assignable to `Proto11`
241class Proto12(Protocol):
242 def __call__(self, *args: Any, kwarg0: Any, kwarg1: Any) -> None:
246def cb12_good1(*args: Any, kwarg0: Any, kwarg1: Any) -> None:
250def cb12_good2(*args: Any, **kwargs: Any) -> None:
254def cb12_bad1(*args: Any, kwarg0: Any) -> None:
258cb12: Proto12 = cb12_good1 # OK
259cb12 = cb12_good2 # OK
260cb12 = cb12_bad1 # E: missing kwarg1
[invalid-assignment] Object of type `def cb12_bad1(*args: Any, *, kwarg0: Any) -> None` is not assignable to `Proto12`
263class Proto13_Default(Protocol):
264 # Callback with positional parameter with default arg value
265 def __call__(self, path: str = ...) -> str:
269class Proto13_NoDefault(Protocol):
270 # Callback with positional parameter but no default arg value
271 def __call__(self, path: str) -> str:
275def cb13_default(path: str = "") -> str:
279def cb13_no_default(path: str) -> str:
283cb13_1: Proto13_Default = cb13_default # OK
284cb13_2: Proto13_Default = cb13_no_default # E: no default
[invalid-assignment] Object of type `def cb13_no_default(path: str) -> str` is not assignable to `Proto13_Default`
286cb13_3: Proto13_NoDefault = cb13_default # OK
287cb13_4: Proto13_NoDefault = cb13_no_default # OK
290class Proto14_Default(Protocol):
291 # Callback with keyword parameter with default arg value
292 def __call__(self, *, path: str = ...) -> str:
296class Proto14_NoDefault(Protocol):
297 # Callback with keyword parameter with no default arg value
298 def __call__(self, *, path: str) -> str:
302def cb14_default(*, path: str = "") -> str:
306def cb14_no_default(*, path: str) -> str:
310cb14_1: Proto14_Default = cb14_default # OK
311cb14_2: Proto14_Default = cb14_no_default # E: no default
[invalid-assignment] Object of type `def cb14_no_default(*, path: str) -> str` is not assignable to `Proto14_Default`
312cb14_3: Proto14_NoDefault = cb14_default # OK
313cb14_4: Proto14_NoDefault = cb14_no_default # OK