@@ -15,8 +15,9 @@ def foo1(x: Callable[P, int]) -> Callable[P, str]: ...
15
15
def foo2(x: P) -> P: ... # E: Invalid location for ParamSpec "P" \
16
16
# N: You can use ParamSpec as the first argument to Callable, e.g., 'Callable[P, int]'
17
17
18
- # TODO(PEP612): uncomment once we have support for Concatenate
19
- # def foo3(x: Concatenate[int, P]) -> int: ... $ E: Invalid location for Concatenate
18
+ # TODO: Better error message
19
+ def foo3(x: Concatenate[int, P]) -> int: ... # E: Invalid location for ParamSpec "P" \
20
+ # N: You can use ParamSpec as the first argument to Callable, e.g., 'Callable[P, int]'
20
21
21
22
def foo4(x: List[P]) -> None: ... # E: Invalid location for ParamSpec "P" \
22
23
# N: You can use ParamSpec as the first argument to Callable, e.g., 'Callable[P, int]'
@@ -455,5 +456,82 @@ reveal_type(kb(n)) # N: Revealed type is "__main__.Z[[builtins.str]]" \
455
456
# TODO(PEP612): fancy "aesthetic" syntax defined in PEP
456
457
# n2: Z[bytes]
457
458
#
458
- # reveal_type(kb(n2)) # N: Revealed type is "__main__.Z[[builtins.str]]"
459
+ # reveal_type(kb(n2)) $ N: Revealed type is "__main__.Z[[builtins.str]]"
459
460
[builtins fixtures/tuple.pyi]
461
+
462
+ [case testParamSpecConcatenateFromPep]
463
+ from typing_extensions import ParamSpec, Concatenate
464
+ from typing import Callable, TypeVar, Generic
465
+
466
+ P = ParamSpec("P")
467
+ R = TypeVar("R")
468
+
469
+ # CASE 1
470
+ class Request:
471
+ ...
472
+
473
+ def with_request(f: Callable[Concatenate[Request, P], R]) -> Callable[P, R]:
474
+ def inner(*args: P.args, **kwargs: P.kwargs) -> R:
475
+ return f(Request(), *args, **kwargs)
476
+ return inner
477
+
478
+ @with_request
479
+ def takes_int_str(request: Request, x: int, y: str) -> int:
480
+ # use request
481
+ return x + 7
482
+
483
+ reveal_type(takes_int_str) # N: Revealed type is "def (x: builtins.int, y: builtins.str) -> builtins.int*"
484
+
485
+ takes_int_str(1, "A") # Accepted
486
+ takes_int_str("B", 2) # E: Argument 1 to "takes_int_str" has incompatible type "str"; expected "int" \
487
+ # E: Argument 2 to "takes_int_str" has incompatible type "int"; expected "str"
488
+
489
+ # CASE 2
490
+ T = TypeVar("T")
491
+ P_2 = ParamSpec("P_2")
492
+
493
+ class X(Generic[T, P]):
494
+ f: Callable[P, int]
495
+ x: T
496
+
497
+ def f1(x: X[int, P_2]) -> str: ... # Accepted
498
+ def f2(x: X[int, Concatenate[int, P_2]]) -> str: ... # Accepted
499
+ def f3(x: X[int, [int, bool]]) -> str: ... # Accepted
500
+ # Is ellipsis allowed by PEP? This shows up:
501
+ # def f4(x: X[int, ...]) -> str: ... # Accepted
502
+ # TODO: this is not rejected:
503
+ # def f5(x: X[int, int]) -> str: ... # Rejected
504
+
505
+ # CASE 3
506
+ def bar(x: int, *args: bool) -> int: ...
507
+ def add(x: Callable[P, int]) -> Callable[Concatenate[str, P], bool]: ...
508
+
509
+ reveal_type(add(bar)) # N: Revealed type is "def (builtins.str, x: builtins.int, *args: builtins.bool) -> builtins.bool"
510
+
511
+ def remove(x: Callable[Concatenate[int, P], int]) -> Callable[P, bool]: ...
512
+
513
+ reveal_type(remove(bar)) # N: Revealed type is "def (*args: builtins.bool) -> builtins.bool"
514
+
515
+ def transform(
516
+ x: Callable[Concatenate[int, P], int]
517
+ ) -> Callable[Concatenate[str, P], bool]: ...
518
+
519
+ # In the PEP, "__a" appears. What is that? Autogenerated names? To what spec?
520
+ reveal_type(transform(bar)) # N: Revealed type is "def (builtins.str, *args: builtins.bool) -> builtins.bool"
521
+
522
+ # CASE 4
523
+ def expects_int_first(x: Callable[Concatenate[int, P], int]) -> None: ...
524
+
525
+ @expects_int_first # E: Argument 1 to "expects_int_first" has incompatible type "Callable[[str], int]"; expected "Callable[[int], int]"
526
+ def one(x: str) -> int: ...
527
+
528
+ @expects_int_first # E: Argument 1 to "expects_int_first" has incompatible type "Callable[[NamedArg(int, 'x')], int]"; expected "Callable[[int], int]"
529
+ def two(*, x: int) -> int: ...
530
+
531
+ @expects_int_first # E: Argument 1 to "expects_int_first" has incompatible type "Callable[[KwArg(int)], int]"; expected "Callable[[int], int]"
532
+ def three(**kwargs: int) -> int: ...
533
+
534
+ @expects_int_first # Accepted
535
+ def four(*args: int) -> int: ...
536
+ [builtins fixtures/tuple.pyi]
537
+ [builtins fixtures/dict.pyi]
0 commit comments