← Back to index

generics_paramspec_components.py

True Positive
False Positive
False Negative
Optional (detected)
Warning or Info
TP: 6
FP: 0
FN: 10
Optional: 0 / 0
1"""
2Tests the usage of a ParamSpec and its components (P.args, P.kwargs).
3"""
4
5# Specification: https://typing.readthedocs.io/en/latest/spec/generics.html#the-components-of-a-paramspec
6
7
8from typing import Any, Callable, Concatenate, ParamSpec, assert_type
9
10P = ParamSpec("P")
13def puts_p_into_scope1(f: Callable[P, int]) -> None:
14 def inner(*args: P.args, **kwargs: P.kwargs) -> None: # OK
15 pass
17 def mixed_up(*args: P.kwargs, **kwargs: P.args) -> None: # E
[invalid-type-form] `P.kwargs` is valid only in `**kwargs` annotation: Did you mean `P.args`? [invalid-type-form] `P.args` is valid only in `*args` annotation: Did you mean `P.kwargs`?
18 pass
20 def misplaced1(x: P.args) -> None: # E
Expected a ty diagnostic for this line
21 pass
23 def bad_kwargs1(*args: P.args, **kwargs: P.args) -> None: # E
[invalid-type-form] `P.args` is valid only in `*args` annotation: Did you mean `P.kwargs`?
24 pass
26 def bad_kwargs2(*args: P.args, **kwargs: Any) -> None: # E
Expected a ty diagnostic for this line
27 pass
30def out_of_scope(*args: P.args, **kwargs: P.kwargs) -> None: # E
Expected a ty diagnostic for this line
31 pass
34def puts_p_into_scope2(f: Callable[P, int]) -> None:
35 stored_args: P.args # E
Expected a ty diagnostic for this line
36 stored_kwargs: P.kwargs # E
Expected a ty diagnostic for this line
38 def just_args(*args: P.args) -> None: # E
Expected a ty diagnostic for this line
39 pass
41 def just_kwargs(**kwargs: P.kwargs) -> None: # E
Expected a ty diagnostic for this line
42 pass
45def decorator(f: Callable[P, int]) -> Callable[P, None]:
46 def foo(*args: P.args, **kwargs: P.kwargs) -> None:
47 assert_type(f(*args, **kwargs), int) # OK
49 f(*kwargs, **args) # E
[invalid-argument-type] Argument is incorrect: Expected `P@decorator.args`, found `P@decorator.kwargs` [invalid-argument-type] Argument is incorrect: Expected `P@decorator.kwargs`, found `P@decorator.args`
51 f(1, *args, **kwargs) # E
[invalid-argument-type] Argument is incorrect: Expected `P@decorator.args`, found `Literal[1]`
53 return foo # OK
56def add(f: Callable[P, int]) -> Callable[Concatenate[str, P], None]:
57 def foo(s: str, *args: P.args, **kwargs: P.kwargs) -> None: # OK
58 pass
60 def bar(*args: P.args, s: str, **kwargs: P.kwargs) -> None: # E
Expected a ty diagnostic for this line
61 pass
63 return foo # OK
66def remove(f: Callable[Concatenate[int, P], int]) -> Callable[P, None]:
67 def foo(*args: P.args, **kwargs: P.kwargs) -> None:
68 f(1, *args, **kwargs) # OK
70 f(*args, 1, **kwargs) # E
Expected a ty diagnostic for this line
72 f(*args, **kwargs) # E
Expected a ty diagnostic for this line
74 return foo # OK
77def outer(f: Callable[P, None]) -> Callable[P, None]:
78 def foo(x: int, *args: P.args, **kwargs: P.kwargs) -> None:
79 f(*args, **kwargs)
81 def bar(*args: P.args, **kwargs: P.kwargs) -> None:
82 foo(1, *args, **kwargs) # OK
83 foo(x=1, *args, **kwargs) # E
[invalid-argument-type] Argument to function `foo` is incorrect: Expected `int`, found `(...)` [parameter-already-assigned] Multiple values provided for parameter 1 (`x`) of function `foo`
85 return bar
88def twice(f: Callable[P, int], *args: P.args, **kwargs: P.kwargs) -> int:
89 return f(*args, **kwargs) + f(*args, **kwargs)
92def a_int_b_str(a: int, b: str) -> int:
93 return 0
96twice(a_int_b_str, 1, "A") # OK
97twice(a_int_b_str, b="A", a=1) # OK
98twice(a_int_b_str, "A", 1) # E
[invalid-argument-type] Argument to function `twice` is incorrect: Expected `int`, found `Literal["A"]` [invalid-argument-type] Argument to function `twice` is incorrect: Expected `str`, found `Literal[1]`