blob: f2281babb193e9b8985849129dd5cfb8ee7d64ed [file] [log] [blame] [edit]
[case testBasicParamSpec]
from typing_extensions import ParamSpec
P = ParamSpec('P')
[builtins fixtures/tuple.pyi]
[case testInvalidParamSpecDefinitions]
from typing import ParamSpec
P1 = ParamSpec("P1", covariant=True) # E: Only the first argument to ParamSpec has defined semantics
P2 = ParamSpec("P2", contravariant=True) # E: Only the first argument to ParamSpec has defined semantics
P3 = ParamSpec("P3", bound=int) # E: Only the first argument to ParamSpec has defined semantics
P4 = ParamSpec("P4", int, str) # E: Only the first argument to ParamSpec has defined semantics
P5 = ParamSpec("P5", covariant=True, bound=int) # E: Only the first argument to ParamSpec has defined semantics
[builtins fixtures/tuple.pyi]
[case testParamSpecLocations]
from typing import Callable, List
from typing_extensions import ParamSpec, Concatenate
P = ParamSpec('P')
x: P # E: ParamSpec "P" is unbound
def foo1(x: Callable[P, int]) -> Callable[P, str]: ...
def foo2(x: P) -> P: ... # E: Invalid location for ParamSpec "P" \
# N: You can use ParamSpec as the first argument to Callable, e.g., 'Callable[P, int]'
# TODO(PEP612): uncomment once we have support for Concatenate
# def foo3(x: Concatenate[int, P]) -> int: ... $ E: Invalid location for Concatenate
def foo4(x: List[P]) -> None: ... # E: Invalid location for ParamSpec "P" \
# N: You can use ParamSpec as the first argument to Callable, e.g., 'Callable[P, int]'
def foo5(x: Callable[[int, str], P]) -> None: ... # E: Invalid location for ParamSpec "P" \
# N: You can use ParamSpec as the first argument to Callable, e.g., 'Callable[P, int]'
def foo6(x: Callable[[P], int]) -> None: ... # E: Invalid location for ParamSpec "P" \
# N: You can use ParamSpec as the first argument to Callable, e.g., 'Callable[P, int]'
[builtins fixtures/tuple.pyi]
[case testParamSpecContextManagerLike]
from typing import Callable, List, Iterator, TypeVar
from typing_extensions import ParamSpec
P = ParamSpec('P')
T = TypeVar('T')
def tmpcontextmanagerlike(x: Callable[P, Iterator[T]]) -> Callable[P, List[T]]: ...
@tmpcontextmanagerlike
def whatever(x: int) -> Iterator[int]:
yield x
reveal_type(whatever) # N: Revealed type is "def (x: builtins.int) -> builtins.list[builtins.int*]"
reveal_type(whatever(217)) # N: Revealed type is "builtins.list[builtins.int*]"
[builtins fixtures/tuple.pyi]
[case testInvalidParamSpecType]
# flags: --python-version 3.10
from typing import ParamSpec
P = ParamSpec("P")
class MyFunction(P): # E: Invalid base class "P"
...
[case testParamSpecRevealType]
from typing import Callable
from typing_extensions import ParamSpec
P = ParamSpec('P')
def f(x: Callable[P, int]) -> None: ...
reveal_type(f) # N: Revealed type is "def [P] (x: def (*P.args, **P.kwargs) -> builtins.int)"
[builtins fixtures/tuple.pyi]
[case testParamSpecSimpleFunction]
from typing import Callable, TypeVar
from typing_extensions import ParamSpec
P = ParamSpec('P')
def changes_return_type_to_str(x: Callable[P, int]) -> Callable[P, str]: ...
def returns_int(a: str, b: bool) -> int: ...
reveal_type(changes_return_type_to_str(returns_int)) # N: Revealed type is "def (a: builtins.str, b: builtins.bool) -> builtins.str"
[builtins fixtures/tuple.pyi]
[case testParamSpecSimpleClass]
from typing import Callable, TypeVar, Generic
from typing_extensions import ParamSpec
P = ParamSpec('P')
class C(Generic[P]):
def __init__(self, x: Callable[P, None]) -> None: ...
def m(self, *args: P.args, **kwargs: P.kwargs) -> int:
return 1
def f(x: int, y: str) -> None: ...
reveal_type(C(f)) # N: Revealed type is "__main__.C[def (x: builtins.int, y: builtins.str)]"
reveal_type(C(f).m) # N: Revealed type is "def (x: builtins.int, y: builtins.str) -> builtins.int"
[builtins fixtures/dict.pyi]
[case testParamSpecClassWithPrefixArgument]
from typing import Callable, TypeVar, Generic
from typing_extensions import ParamSpec
P = ParamSpec('P')
class C(Generic[P]):
def __init__(self, x: Callable[P, None]) -> None: ...
def m(self, a: str, *args: P.args, **kwargs: P.kwargs) -> int:
return 1
def f(x: int, y: str) -> None: ...
reveal_type(C(f).m) # N: Revealed type is "def (a: builtins.str, x: builtins.int, y: builtins.str) -> builtins.int"
reveal_type(C(f).m('', 1, '')) # N: Revealed type is "builtins.int"
[builtins fixtures/dict.pyi]
[case testParamSpecDecorator]
from typing import Callable, TypeVar, Generic
from typing_extensions import ParamSpec
P = ParamSpec('P')
R = TypeVar('R')
class W(Generic[P, R]):
f: Callable[P, R]
x: int
def __call__(self, *args: P.args, **kwargs: P.kwargs) -> R:
reveal_type(self.f(*args, **kwargs)) # N: Revealed type is "R`2"
return self.f(*args, **kwargs)
def dec() -> Callable[[Callable[P, R]], W[P, R]]:
pass
@dec()
def f(a: int, b: str) -> None: ...
reveal_type(f) # N: Revealed type is "__main__.W[def (a: builtins.int, b: builtins.str), None]"
reveal_type(f(1, '')) # N: Revealed type is "None"
reveal_type(f.x) # N: Revealed type is "builtins.int"
## TODO: How should this work?
#
# class C:
# @dec()
# def m(self, x: int) -> str: ...
#
# reveal_type(C().m(x=1))
[builtins fixtures/dict.pyi]
[case testParamSpecFunction]
from typing import Callable, TypeVar
from typing_extensions import ParamSpec
P = ParamSpec('P')
R = TypeVar('R')
def f(x: Callable[P, R], *args: P.args, **kwargs: P.kwargs) -> R:
return x(*args, **kwargs)
def g(x: int, y: str) -> None: ...
reveal_type(f(g, 1, y='x')) # N: Revealed type is "None"
f(g, 'x', y='x') # E: Argument 2 to "f" has incompatible type "str"; expected "int"
f(g, 1, y=1) # E: Argument "y" to "f" has incompatible type "int"; expected "str"
f(g) # E: Missing positional arguments "x", "y" in call to "f"
[builtins fixtures/dict.pyi]
[case testParamSpecSpecialCase]
from typing import Callable, TypeVar
from typing_extensions import ParamSpec
P = ParamSpec('P')
T = TypeVar('T')
def register(func: Callable[P, T], *args: P.args, **kwargs: P.kwargs) -> Callable[P, T]: ...
def f(x: int, y: str, z: int, a: str) -> None: ...
x = register(f, 1, '', 1, '')
[builtins fixtures/dict.pyi]
[case testParamSpecInferredFromAny]
from typing import Callable, Any
from typing_extensions import ParamSpec
P = ParamSpec('P')
def f(x: Callable[P, int]) -> Callable[P, str]: ...
g: Any
reveal_type(f(g)) # N: Revealed type is "def (*Any, **Any) -> builtins.str"
f(g)(1, 3, x=1, y=2)
[builtins fixtures/tuple.pyi]
[case testParamSpecDecoratorImplementation]
from typing import Callable, Any, TypeVar, List
from typing_extensions import ParamSpec
P = ParamSpec('P')
T = TypeVar('T')
def dec(f: Callable[P, T]) -> Callable[P, List[T]]:
def wrapper(*args: P.args, **kwargs: P.kwargs) -> List[T]:
return [f(*args, **kwargs)]
return wrapper
@dec
def g(x: int, y: str = '') -> int: ...
reveal_type(g) # N: Revealed type is "def (x: builtins.int, y: builtins.str =) -> builtins.list[builtins.int*]"
[builtins fixtures/dict.pyi]
[case testParamSpecArgsAndKwargsTypes]
from typing import Callable, TypeVar, Generic
from typing_extensions import ParamSpec
P = ParamSpec('P')
class C(Generic[P]):
def __init__(self, x: Callable[P, None]) -> None: ...
def m(self, *args: P.args, **kwargs: P.kwargs) -> None:
reveal_type(args) # N: Revealed type is "P.args`1"
reveal_type(kwargs) # N: Revealed type is "P.kwargs`1"
[builtins fixtures/dict.pyi]
[case testParamSpecSubtypeChecking1]
from typing import Callable, TypeVar, Generic, Any
from typing_extensions import ParamSpec
P = ParamSpec('P')
class C(Generic[P]):
def __init__(self, x: Callable[P, None]) -> None: ...
def m(self, *args: P.args, **kwargs: P.kwargs) -> None:
args = args
kwargs = kwargs
o: object
o = args
o = kwargs
o2: object
args = o2 # E: Incompatible types in assignment (expression has type "object", variable has type "P.args")
kwargs = o2 # E: Incompatible types in assignment (expression has type "object", variable has type "P.kwargs")
a: Any
a = args
a = kwargs
args = kwargs # E: Incompatible types in assignment (expression has type "P.kwargs", variable has type "P.args")
kwargs = args # E: Incompatible types in assignment (expression has type "P.args", variable has type "P.kwargs")
args = a
kwargs = a
[builtins fixtures/dict.pyi]
[case testParamSpecSubtypeChecking2]
from typing import Callable, Generic
from typing_extensions import ParamSpec
P = ParamSpec('P')
P2 = ParamSpec('P2')
class C(Generic[P]):
pass
def f(c1: C[P], c2: C[P2]) -> None:
c1 = c1
c2 = c2
c1 = c2 # E: Incompatible types in assignment (expression has type "C[P2]", variable has type "C[P]")
c2 = c1 # E: Incompatible types in assignment (expression has type "C[P]", variable has type "C[P2]")
def g(f: Callable[P, None], g: Callable[P2, None]) -> None:
f = f
g = g
f = g # E: Incompatible types in assignment (expression has type "Callable[P2, None]", variable has type "Callable[P, None]")
g = f # E: Incompatible types in assignment (expression has type "Callable[P, None]", variable has type "Callable[P2, None]")
[builtins fixtures/dict.pyi]
[case testParamSpecJoin]
from typing import Callable, Generic, TypeVar
from typing_extensions import ParamSpec
P = ParamSpec('P')
P2 = ParamSpec('P2')
P3 = ParamSpec('P3')
T = TypeVar('T')
def join(x: T, y: T) -> T: ...
class C(Generic[P, P2]):
def m(self, f: Callable[P, None], g: Callable[P2, None]) -> None:
reveal_type(join(f, f)) # N: Revealed type is "def (*P.args, **P.kwargs)"
reveal_type(join(f, g)) # N: Revealed type is "builtins.function*"
def m2(self, *args: P.args, **kwargs: P.kwargs) -> None:
reveal_type(join(args, args)) # N: Revealed type is "P.args`1"
reveal_type(join(kwargs, kwargs)) # N: Revealed type is "P.kwargs`1"
reveal_type(join(args, kwargs)) # N: Revealed type is "builtins.object*"
def f(*args2: P2.args, **kwargs2: P2.kwargs) -> None:
reveal_type(join(args, args2)) # N: Revealed type is "builtins.object*"
reveal_type(join(kwargs, kwargs2)) # N: Revealed type is "builtins.object*"
def m3(self, c: C[P, P3]) -> None:
reveal_type(join(c, c)) # N: Revealed type is "__main__.C*[P`1, P3`-1]"
reveal_type(join(self, c)) # N: Revealed type is "builtins.object*"
[builtins fixtures/dict.pyi]
[case testParamSpecClassWithAny]
from typing import Callable, Generic, Any
from typing_extensions import ParamSpec
P = ParamSpec('P')
class C(Generic[P]):
def __init__(self, x: Callable[P, None]) -> None: ...
def m(self, *args: P.args, **kwargs: P.kwargs) -> int:
return 1
c: C[Any]
reveal_type(c) # N: Revealed type is "__main__.C[Any]"
reveal_type(c.m) # N: Revealed type is "def (*args: Any, **kwargs: Any) -> builtins.int"
c.m(4, 6, y='x')
c = c
def f() -> None: pass
c2 = C(f)
c2 = c
c3 = C(f)
c = c3
[builtins fixtures/dict.pyi]
[case testParamSpecInferredFromLambda]
from typing import Callable, TypeVar
from typing_extensions import ParamSpec
P = ParamSpec('P')
T = TypeVar('T')
# Similar to atexit.register
def register(f: Callable[P, T], *args: P.args, **kwargs: P.kwargs) -> Callable[P, T]: ... # N: "register" defined here
def f(x: int) -> None: pass
reveal_type(register(lambda: f(1))) # N: Revealed type is "def ()"
reveal_type(register(lambda x: f(x), x=1)) # N: Revealed type is "def (x: Any)"
register(lambda x: f(x)) # E: Missing positional argument "x" in call to "register"
register(lambda x: f(x), y=1) # E: Unexpected keyword argument "y" for "register"
[builtins fixtures/dict.pyi]
[case testParamSpecInvalidCalls]
from typing import Callable, Generic
from typing_extensions import ParamSpec
P = ParamSpec('P')
P2 = ParamSpec('P2')
class C(Generic[P, P2]):
def m1(self, *args: P.args, **kwargs: P.kwargs) -> None:
self.m1(*args, **kwargs)
self.m2(*args, **kwargs) # E: Argument 1 to "m2" of "C" has incompatible type "*P.args"; expected "P2.args" \
# E: Argument 2 to "m2" of "C" has incompatible type "**P.kwargs"; expected "P2.kwargs"
self.m1(*kwargs, **args) # E: Argument 1 to "m1" of "C" has incompatible type "*P.kwargs"; expected "P.args" \
# E: Argument 2 to "m1" of "C" has incompatible type "**P.args"; expected "P.kwargs"
self.m3(*args, **kwargs) # E: Argument 1 to "m3" of "C" has incompatible type "*P.args"; expected "int" \
# E: Argument 2 to "m3" of "C" has incompatible type "**P.kwargs"; expected "int"
self.m4(*args, **kwargs) # E: Argument 1 to "m4" of "C" has incompatible type "*P.args"; expected "int" \
# E: Argument 2 to "m4" of "C" has incompatible type "**P.kwargs"; expected "int"
self.m1(*args, **args) # E: Argument 2 to "m1" of "C" has incompatible type "**P.args"; expected "P.kwargs"
self.m1(*kwargs, **kwargs) # E: Argument 1 to "m1" of "C" has incompatible type "*P.kwargs"; expected "P.args"
def m2(self, *args: P2.args, **kwargs: P2.kwargs) -> None:
pass
def m3(self, *args: int, **kwargs: int) -> None:
pass
def m4(self, x: int) -> None:
pass
[builtins fixtures/dict.pyi]
[case testParamSpecOverUnannotatedDecorator]
from typing import Callable, Iterator, TypeVar, ContextManager, Any
from typing_extensions import ParamSpec
from nonexistent import deco2 # type: ignore
T = TypeVar("T")
P = ParamSpec("P")
T_co = TypeVar("T_co", covariant=True)
class CM(ContextManager[T_co]):
def __call__(self, func: T) -> T: ...
def deco1(
func: Callable[P, Iterator[T]]) -> Callable[P, CM[T]]: ...
@deco1
@deco2
def f():
pass
reveal_type(f) # N: Revealed type is "def (*Any, **Any) -> __main__.CM[Any]"
with f() as x:
pass
[builtins fixtures/dict.pyi]
[typing fixtures/typing-full.pyi]