| [case testTotalOrderingEqLt] |
| from functools import total_ordering |
| |
| @total_ordering |
| class Ord: |
| def __eq__(self, other: object) -> bool: |
| return False |
| |
| def __lt__(self, other: "Ord") -> bool: |
| return False |
| |
| reveal_type(Ord() < Ord()) # N: Revealed type is "builtins.bool" |
| reveal_type(Ord() <= Ord()) # N: Revealed type is "builtins.bool" |
| reveal_type(Ord() == Ord()) # N: Revealed type is "builtins.bool" |
| reveal_type(Ord() > Ord()) # N: Revealed type is "builtins.bool" |
| reveal_type(Ord() >= Ord()) # N: Revealed type is "builtins.bool" |
| |
| Ord() < 1 # E: Unsupported operand types for < ("Ord" and "int") |
| Ord() <= 1 # E: Unsupported operand types for <= ("Ord" and "int") |
| Ord() == 1 |
| Ord() > 1 # E: Unsupported operand types for > ("Ord" and "int") |
| Ord() >= 1 # E: Unsupported operand types for >= ("Ord" and "int") |
| [builtins fixtures/dict.pyi] |
| |
| [case testTotalOrderingLambda] |
| from functools import total_ordering |
| from typing import Any, Callable, ClassVar |
| |
| @total_ordering |
| class Ord: |
| __eq__: Callable[[Any, object], bool] = lambda self, other: False |
| __lt__: Callable[[Any, "Ord"], bool] = lambda self, other: False |
| |
| reveal_type(Ord() < Ord()) # N: Revealed type is "builtins.bool" |
| reveal_type(Ord() <= Ord()) # N: Revealed type is "builtins.bool" |
| reveal_type(Ord() == Ord()) # N: Revealed type is "builtins.bool" |
| reveal_type(Ord() > Ord()) # N: Revealed type is "builtins.bool" |
| reveal_type(Ord() >= Ord()) # N: Revealed type is "builtins.bool" |
| |
| Ord() < 1 # E: Argument 1 has incompatible type "int"; expected "Ord" |
| Ord() <= 1 # E: Unsupported operand types for <= ("Ord" and "int") |
| Ord() == 1 |
| Ord() > 1 # E: Unsupported operand types for > ("Ord" and "int") |
| Ord() >= 1 # E: Unsupported operand types for >= ("Ord" and "int") |
| [builtins fixtures/dict.pyi] |
| |
| [case testTotalOrderingNonCallable] |
| from functools import total_ordering |
| |
| @total_ordering |
| class Ord(object): |
| def __eq__(self, other: object) -> bool: |
| return False |
| |
| __lt__ = 5 |
| |
| Ord() <= Ord() # E: Unsupported left operand type for <= ("Ord") |
| Ord() > Ord() # E: "int" not callable |
| Ord() >= Ord() # E: Unsupported left operand type for >= ("Ord") |
| [builtins fixtures/dict.pyi] |
| |
| [case testTotalOrderingReturnNotBool] |
| from functools import total_ordering |
| |
| @total_ordering |
| class Ord: |
| def __eq__(self, other: object) -> bool: |
| return False |
| |
| def __lt__(self, other: "Ord") -> str: |
| return "blah" |
| |
| reveal_type(Ord() < Ord()) # N: Revealed type is "builtins.str" |
| reveal_type(Ord() <= Ord()) # N: Revealed type is "Any" |
| reveal_type(Ord() == Ord()) # N: Revealed type is "builtins.bool" |
| reveal_type(Ord() > Ord()) # N: Revealed type is "Any" |
| reveal_type(Ord() >= Ord()) # N: Revealed type is "Any" |
| [builtins fixtures/dict.pyi] |
| |
| [case testTotalOrderingAllowsAny] |
| from functools import total_ordering |
| |
| @total_ordering |
| class Ord: |
| def __eq__(self, other): |
| return False |
| |
| def __gt__(self, other): |
| return False |
| |
| reveal_type(Ord() < Ord()) # N: Revealed type is "Any" |
| Ord() <= Ord() # E: Unsupported left operand type for <= ("Ord") |
| reveal_type(Ord() == Ord()) # N: Revealed type is "Any" |
| reveal_type(Ord() > Ord()) # N: Revealed type is "Any" |
| Ord() >= Ord() # E: Unsupported left operand type for >= ("Ord") |
| |
| Ord() < 1 # E: Unsupported left operand type for < ("Ord") |
| Ord() <= 1 # E: Unsupported left operand type for <= ("Ord") |
| Ord() == 1 |
| Ord() > 1 |
| Ord() >= 1 # E: Unsupported left operand type for >= ("Ord") |
| [builtins fixtures/dict.pyi] |
| |
| [case testCachedProperty] |
| from functools import cached_property |
| class Parent: |
| @property |
| def f(self) -> str: pass |
| class Child(Parent): |
| @cached_property |
| def f(self) -> str: pass |
| @cached_property |
| def g(self) -> int: pass |
| @cached_property # E: Too many arguments for property |
| def h(self, arg) -> int: pass |
| reveal_type(Parent().f) # N: Revealed type is "builtins.str" |
| reveal_type(Child().f) # N: Revealed type is "builtins.str" |
| reveal_type(Child().g) # N: Revealed type is "builtins.int" |
| Child().f = "Hello World" |
| Child().g = "invalid" # E: Incompatible types in assignment (expression has type "str", variable has type "int") |
| [file functools.pyi] |
| import sys |
| from typing import TypeVar, Generic |
| _T = TypeVar('_T') |
| class cached_property(Generic[_T]): ... |
| [builtins fixtures/property.pyi] |
| |
| [case testTotalOrderingWithForwardReference] |
| from typing import Generic, Any, TypeVar |
| import functools |
| |
| T = TypeVar("T", bound="C") |
| |
| @functools.total_ordering |
| class D(Generic[T]): |
| def __lt__(self, other: Any) -> bool: |
| ... |
| |
| class C: |
| pass |
| |
| def f(d: D[C]) -> None: |
| reveal_type(d.__gt__) # N: Revealed type is "def (other: Any) -> builtins.bool" |
| |
| d: D[int] # E: Type argument "int" of "D" must be a subtype of "C" |
| [builtins fixtures/dict.pyi] |
| |
| [case testFunctoolsPartialBasic] |
| from typing import Callable |
| import functools |
| |
| def foo(a: int, b: str, c: int = 5) -> int: ... # N: "foo" defined here |
| |
| p1 = functools.partial(foo) |
| p1(1, "a", 3) # OK |
| p1(1, "a", c=3) # OK |
| p1(1, b="a", c=3) # OK |
| |
| reveal_type(p1) # N: Revealed type is "functools.partial[builtins.int]" |
| |
| def takes_callable_int(f: Callable[..., int]) -> None: ... |
| def takes_callable_str(f: Callable[..., str]) -> None: ... |
| takes_callable_int(p1) |
| takes_callable_str(p1) # E: Argument 1 to "takes_callable_str" has incompatible type "partial[int]"; expected "Callable[..., str]" \ |
| # N: "partial[int].__call__" has type "def __call__(__self, *args: Any, **kwargs: Any) -> int" |
| |
| p2 = functools.partial(foo, 1) |
| p2("a") # OK |
| p2("a", 3) # OK |
| p2("a", c=3) # OK |
| p2(1, 3) # E: Argument 1 to "foo" has incompatible type "int"; expected "str" |
| p2(1, "a", 3) # E: Too many arguments for "foo" \ |
| # E: Argument 1 to "foo" has incompatible type "int"; expected "str" \ |
| # E: Argument 2 to "foo" has incompatible type "str"; expected "int" |
| p2(a=1, b="a", c=3) # E: Unexpected keyword argument "a" for "foo" |
| |
| p3 = functools.partial(foo, b="a") |
| p3(1) # OK |
| p3(1, c=3) # OK |
| p3(a=1) # OK |
| p3(1, b="a", c=3) # OK, keywords can be clobbered |
| p3(1, 3) # E: Too many positional arguments for "foo" \ |
| # E: Argument 2 to "foo" has incompatible type "int"; expected "str" |
| |
| functools.partial(foo, "a") # E: Argument 1 to "foo" has incompatible type "str"; expected "int" |
| functools.partial(foo, b=1) # E: Argument "b" to "foo" has incompatible type "int"; expected "str" |
| functools.partial(foo, a=1, b=2, c=3) # E: Argument "b" to "foo" has incompatible type "int"; expected "str" |
| functools.partial(1) # E: "int" not callable \ |
| # E: Argument 1 to "partial" has incompatible type "int"; expected "Callable[..., Never]" |
| [builtins fixtures/dict.pyi] |
| |
| [case testFunctoolsPartialStar] |
| import functools |
| from typing import List |
| |
| def foo(a: int, b: str, *args: int, d: str, **kwargs: int) -> int: ... |
| |
| p1 = functools.partial(foo, 1, d="a", x=9) |
| p1("a", 2, 3, 4) # OK |
| p1("a", 2, 3, 4, d="a") # OK |
| p1("a", 2, 3, 4, "a") # E: Argument 5 to "foo" has incompatible type "str"; expected "int" |
| p1("a", 2, 3, 4, x="a") # E: Argument "x" to "foo" has incompatible type "str"; expected "int" |
| |
| p2 = functools.partial(foo, 1, "a") |
| p2(2, 3, 4, d="a") # OK |
| p2("a") # E: Missing named argument "d" for "foo" \ |
| # E: Argument 1 to "foo" has incompatible type "str"; expected "int" |
| p2(2, 3, 4) # E: Missing named argument "d" for "foo" |
| |
| functools.partial(foo, 1, "a", "b", "c", d="a") # E: Argument 3 to "foo" has incompatible type "str"; expected "int" \ |
| # E: Argument 4 to "foo" has incompatible type "str"; expected "int" |
| |
| def bar(*a: bytes, **k: int): |
| p1("a", 2, 3, 4, d="a", **k) |
| p1("a", d="a", **k) |
| p1("a", **k) # E: Argument 2 to "foo" has incompatible type "**dict[str, int]"; expected "str" |
| p1(**k) # E: Argument 1 to "foo" has incompatible type "**dict[str, int]"; expected "str" |
| p1(*a) # E: Expected iterable as variadic argument |
| |
| |
| def baz(a: int, b: int) -> int: ... |
| def test_baz(xs: List[int]): |
| p3 = functools.partial(baz, *xs) |
| p3() |
| p3(1) # E: Too many arguments for "baz" |
| |
| |
| [builtins fixtures/dict.pyi] |
| |
| [case testFunctoolsPartialGeneric] |
| from typing import TypeVar |
| import functools |
| |
| T = TypeVar("T") |
| U = TypeVar("U") |
| |
| def foo(a: T, b: T) -> T: ... |
| |
| p1 = functools.partial(foo, 1) |
| reveal_type(p1(2)) # N: Revealed type is "builtins.int" |
| p1("a") # E: Argument 1 to "foo" has incompatible type "str"; expected "int" |
| |
| p2 = functools.partial(foo, "a") |
| p2(1) # E: Argument 1 to "foo" has incompatible type "int"; expected "str" |
| reveal_type(p2("a")) # N: Revealed type is "builtins.str" |
| |
| def bar(a: T, b: U) -> U: ... |
| |
| p3 = functools.partial(bar, 1) |
| reveal_type(p3(2)) # N: Revealed type is "builtins.int" |
| reveal_type(p3("a")) # N: Revealed type is "builtins.str" |
| [builtins fixtures/dict.pyi] |
| |
| [case testFunctoolsPartialCallable] |
| from typing import Callable |
| import functools |
| |
| def main1(f: Callable[[int, str], int]) -> None: |
| p = functools.partial(f, 1) |
| p("a") # OK |
| p(1) # E: Argument 1 has incompatible type "int"; expected "str" |
| |
| functools.partial(f, a=1) # E: Unexpected keyword argument "a" |
| |
| class CallbackProto: |
| def __call__(self, a: int, b: str) -> int: ... |
| |
| def main2(f: CallbackProto) -> None: |
| p = functools.partial(f, b="a") |
| p(1) # OK |
| p("a") # E: Argument 1 to "__call__" of "CallbackProto" has incompatible type "str"; expected "int" |
| [builtins fixtures/dict.pyi] |
| |
| [case testFunctoolsPartialOverload] |
| from typing import overload |
| import functools |
| |
| @overload |
| def foo(a: int, b: str) -> int: ... |
| @overload |
| def foo(a: str, b: int) -> str: ... |
| def foo(*a, **k): ... |
| |
| p1 = functools.partial(foo) |
| reveal_type(p1(1, "a")) # N: Revealed type is "builtins.int" |
| reveal_type(p1("a", 1)) # N: Revealed type is "builtins.int" |
| p1(1, 2) # TODO: false negative |
| p1("a", "b") # TODO: false negative |
| [builtins fixtures/dict.pyi] |
| |
| [case testFunctoolsPartialTypeGuard] |
| import functools |
| from typing_extensions import TypeGuard |
| |
| def is_str_list(val: list[object]) -> TypeGuard[list[str]]: ... |
| |
| reveal_type(functools.partial(is_str_list, [1, 2, 3])) # N: Revealed type is "functools.partial[builtins.bool]" |
| reveal_type(functools.partial(is_str_list, [1, 2, 3])()) # N: Revealed type is "builtins.bool" |
| [builtins fixtures/dict.pyi] |
| |
| [case testFunctoolsPartialType] |
| import functools |
| from typing import Type |
| |
| class A: |
| def __init__(self, a: int, b: str) -> None: ... # N: "A" defined here |
| |
| p = functools.partial(A, 1) |
| reveal_type(p) # N: Revealed type is "functools.partial[__main__.A]" |
| |
| p("a") # OK |
| p(1) # E: Argument 1 to "A" has incompatible type "int"; expected "str" |
| p(z=1) # E: Unexpected keyword argument "z" for "A" |
| |
| def main(t: Type[A]) -> None: |
| p = functools.partial(t, 1) |
| reveal_type(p) # N: Revealed type is "functools.partial[__main__.A]" |
| |
| p("a") # OK |
| p(1) # E: Argument 1 to "A" has incompatible type "int"; expected "str" |
| p(z=1) # E: Unexpected keyword argument "z" for "A" |
| |
| [builtins fixtures/dict.pyi] |
| |
| [case testFunctoolsPartialTypeVarTuple] |
| import functools |
| import typing |
| Ts = typing.TypeVarTuple("Ts") |
| def foo(fn: typing.Callable[[typing.Unpack[Ts]], None], /, *arg: typing.Unpack[Ts], kwarg: str) -> None: ... |
| p = functools.partial(foo, kwarg="asdf") |
| |
| def bar(a: int, b: str, c: float) -> None: ... |
| p(bar, 1, "a", 3.0) # OK |
| p(bar, 1, "a", 3.0, kwarg="asdf") # OK |
| p(bar, 1, "a", "b") # E: Argument 1 to "foo" has incompatible type "Callable[[int, str, float], None]"; expected "Callable[[int, str, str], None]" |
| [builtins fixtures/dict.pyi] |
| |
| [case testFunctoolsPartialUnion] |
| import functools |
| from typing import Any, Callable, Union |
| |
| cls1: Any |
| cls2: Union[Any, Any] |
| reveal_type(functools.partial(cls1, 2)()) # N: Revealed type is "Any" |
| reveal_type(functools.partial(cls2, 2)()) # N: Revealed type is "Any" |
| |
| fn1: Union[Callable[[int], int], Callable[[int], int]] |
| reveal_type(functools.partial(fn1, 2)()) # N: Revealed type is "builtins.int" |
| |
| fn2: Union[Callable[[int], int], Callable[[int], str]] |
| reveal_type(functools.partial(fn2, 2)()) # N: Revealed type is "builtins.int | builtins.str" |
| |
| fn3: Union[Callable[[int], int], str] |
| reveal_type(functools.partial(fn3, 2)()) # E: "str" not callable \ |
| # N: Revealed type is "builtins.int" \ |
| # E: Argument 1 to "partial" has incompatible type "Callable[[int], int] | str"; expected "Callable[..., int]" |
| [builtins fixtures/tuple.pyi] |
| |
| [case testFunctoolsPartialUnionOfTypeAndCallable] |
| import functools |
| from typing import Callable, Union, Type |
| from typing_extensions import TypeAlias |
| |
| class FooBar: |
| def __init__(self, arg1: str) -> None: |
| pass |
| |
| def f1(t: Union[Type[FooBar], Callable[..., 'FooBar']]) -> None: |
| val = functools.partial(t) |
| |
| FooBarFunc: TypeAlias = Callable[..., 'FooBar'] |
| |
| def f2(t: Union[Type[FooBar], FooBarFunc]) -> None: |
| val = functools.partial(t) |
| [builtins fixtures/tuple.pyi] |
| |
| [case testFunctoolsPartialExplicitType] |
| from functools import partial |
| from typing import Type, TypeVar, Callable |
| |
| T = TypeVar("T") |
| def generic(string: str, integer: int, resulting_type: Type[T]) -> T: ... |
| |
| p: partial[str] = partial(generic, resulting_type=str) |
| q: partial[bool] = partial(generic, resulting_type=str) # E: Argument "resulting_type" to "generic" has incompatible type "type[str]"; expected "type[bool]" |
| |
| pc: Callable[..., str] = partial(generic, resulting_type=str) |
| qc: Callable[..., bool] = partial(generic, resulting_type=str) # E: Incompatible types in assignment (expression has type "partial[str]", variable has type "Callable[..., bool]") \ |
| # N: "partial[str].__call__" has type "def __call__(__self, *args: Any, **kwargs: Any) -> str" |
| [builtins fixtures/tuple.pyi] |
| |
| [case testFunctoolsPartialNestedPartial] |
| from functools import partial |
| from typing import Any |
| |
| def foo(x: int) -> int: ... |
| p = partial(partial, foo) |
| reveal_type(p()(1)) # N: Revealed type is "builtins.int" |
| p()("no") # E: Argument 1 to "foo" has incompatible type "str"; expected "int" |
| |
| q = partial(partial, partial, foo) |
| q()()("no") # E: Argument 1 to "foo" has incompatible type "str"; expected "int" |
| |
| r = partial(partial, foo, 1) |
| reveal_type(r()()) # N: Revealed type is "builtins.int" |
| [builtins fixtures/tuple.pyi] |
| |
| [case testFunctoolsPartialTypeObject] |
| import functools |
| from typing import Type, Generic, TypeVar |
| |
| class A: |
| def __init__(self, val: int) -> None: ... |
| |
| cls1: Type[A] |
| reveal_type(functools.partial(cls1, 2)()) # N: Revealed type is "__main__.A" |
| functools.partial(cls1, "asdf") # E: Argument 1 to "A" has incompatible type "str"; expected "int" |
| |
| T = TypeVar("T") |
| class B(Generic[T]): |
| def __init__(self, val: T) -> None: ... |
| |
| cls2: Type[B[int]] |
| reveal_type(functools.partial(cls2, 2)()) # N: Revealed type is "__main__.B[builtins.int]" |
| functools.partial(cls2, "asdf") # E: Argument 1 to "B" has incompatible type "str"; expected "int" |
| |
| def foo(cls3: Type[B[T]]): |
| reveal_type(functools.partial(cls3, "asdf")) # N: Revealed type is "functools.partial[__main__.B[T`-1]]" \ |
| # E: Argument 1 to "B" has incompatible type "str"; expected "T" |
| reveal_type(functools.partial(cls3, 2)()) # N: Revealed type is "__main__.B[T`-1]" \ |
| # E: Argument 1 to "B" has incompatible type "int"; expected "T" |
| [builtins fixtures/tuple.pyi] |
| |
| [case testFunctoolsPartialTypedDictUnpack] |
| from typing import TypedDict |
| from typing_extensions import Unpack |
| from functools import partial |
| |
| class D1(TypedDict, total=False): |
| a1: int |
| |
| def fn1(a1: int) -> None: ... # N: "fn1" defined here |
| def main1(**d1: Unpack[D1]) -> None: |
| partial(fn1, **d1)() |
| partial(fn1, **d1)(**d1) |
| partial(fn1, **d1)(a1=1) |
| partial(fn1, **d1)(a1="asdf") # E: Argument "a1" to "fn1" has incompatible type "str"; expected "int" |
| partial(fn1, **d1)(oops=1) # E: Unexpected keyword argument "oops" for "fn1" |
| |
| def fn2(**kwargs: Unpack[D1]) -> None: ... # N: "fn2" defined here |
| def main2(**d1: Unpack[D1]) -> None: |
| partial(fn2, **d1)() |
| partial(fn2, **d1)(**d1) |
| partial(fn2, **d1)(a1=1) |
| partial(fn2, **d1)(a1="asdf") # E: Argument "a1" to "fn2" has incompatible type "str"; expected "int" |
| partial(fn2, **d1)(oops=1) # E: Unexpected keyword argument "oops" for "fn2" |
| |
| class D2(TypedDict, total=False): |
| a1: int |
| a2: str |
| |
| class A2Good(TypedDict, total=False): |
| a2: str |
| class A2Bad(TypedDict, total=False): |
| a2: int |
| |
| def fn3(a1: int, a2: str) -> None: ... # N: "fn3" defined here |
| def main3(a2good: A2Good, a2bad: A2Bad, **d2: Unpack[D2]) -> None: |
| partial(fn3, **d2)() |
| partial(fn3, **d2)(a1=1, a2="asdf") |
| |
| partial(fn3, **d2)(**d2) |
| |
| partial(fn3, **d2)(a1="asdf") # E: Argument "a1" to "fn3" has incompatible type "str"; expected "int" |
| partial(fn3, **d2)(a1=1, a2="asdf", oops=1) # E: Unexpected keyword argument "oops" for "fn3" |
| |
| partial(fn3, **d2)(**a2good) |
| partial(fn3, **d2)(**a2bad) # E: Argument "a2" to "fn3" has incompatible type "int"; expected "str" |
| |
| def fn4(**kwargs: Unpack[D2]) -> None: ... # N: "fn4" defined here |
| def main4(a2good: A2Good, a2bad: A2Bad, **d2: Unpack[D2]) -> None: |
| partial(fn4, **d2)() |
| partial(fn4, **d2)(a1=1, a2="asdf") |
| |
| partial(fn4, **d2)(**d2) |
| |
| partial(fn4, **d2)(a1="asdf") # E: Argument "a1" to "fn4" has incompatible type "str"; expected "int" |
| partial(fn4, **d2)(a1=1, a2="asdf", oops=1) # E: Unexpected keyword argument "oops" for "fn4" |
| |
| partial(fn3, **d2)(**a2good) |
| partial(fn3, **d2)(**a2bad) # E: Argument "a2" to "fn3" has incompatible type "int"; expected "str" |
| |
| def main5(**d2: Unpack[D2]) -> None: |
| partial(fn1, **d2)() # E: Extra argument "a2" from **args for "fn1" |
| partial(fn2, **d2)() # E: Extra argument "a2" from **args for "fn2" |
| |
| def main6(a2good: A2Good, a2bad: A2Bad, **d1: Unpack[D1]) -> None: |
| partial(fn3, **d1)() # E: Missing positional argument "a1" in call to "fn3" |
| partial(fn3, **d1)("asdf") # E: Too many positional arguments for "fn3" \ |
| # E: Too few arguments for "fn3" \ |
| # E: Argument 1 to "fn3" has incompatible type "str"; expected "int" |
| partial(fn3, **d1)(a2="asdf") |
| partial(fn3, **d1)(**a2good) |
| partial(fn3, **d1)(**a2bad) # E: Argument "a2" to "fn3" has incompatible type "int"; expected "str" |
| |
| partial(fn4, **d1)() |
| partial(fn4, **d1)("asdf") # E: Too many positional arguments for "fn4" \ |
| # E: Argument 1 to "fn4" has incompatible type "str"; expected "int" |
| partial(fn4, **d1)(a2="asdf") |
| partial(fn4, **d1)(**a2good) |
| partial(fn4, **d1)(**a2bad) # E: Argument "a2" to "fn4" has incompatible type "int"; expected "str" |
| [builtins fixtures/dict.pyi] |
| [typing fixtures/typing-typeddict.pyi] |
| |
| |
| [case testFunctoolsPartialNestedGeneric] |
| from functools import partial |
| from typing import Generic, TypeVar, List |
| |
| T = TypeVar("T") |
| def get(n: int, args: List[T]) -> T: ... |
| first = partial(get, 0) |
| |
| x: List[str] |
| reveal_type(first(x)) # N: Revealed type is "builtins.str" |
| reveal_type(first([1])) # N: Revealed type is "builtins.int" |
| |
| first_kw = partial(get, n=0) |
| reveal_type(first_kw(args=[1])) # N: Revealed type is "builtins.int" |
| |
| # TODO: this is indeed invalid, but the error is incomprehensible. |
| first_kw([1]) # E: Too many positional arguments for "get" \ |
| # E: Too few arguments for "get" \ |
| # E: Argument 1 to "get" has incompatible type "list[int]"; expected "int" |
| [builtins fixtures/list.pyi] |
| |
| [case testFunctoolsPartialHigherOrder] |
| from functools import partial |
| from typing import Callable |
| |
| def fn(a: int, b: str, c: bytes) -> int: ... |
| |
| def callback1(fn: Callable[[str, bytes], int]) -> None: ... |
| def callback2(fn: Callable[[str, int], int]) -> None: ... |
| |
| callback1(partial(fn, 1)) |
| # TODO: false negative |
| # https://github.com/python/mypy/issues/17461 |
| callback2(partial(fn, 1)) |
| [builtins fixtures/tuple.pyi] |
| |
| [case testFunctoolsPartialClassObjectMatchingPartial] |
| from functools import partial |
| |
| class A: |
| def __init__(self, var: int, b: int, c: int) -> None: ... |
| |
| p = partial(A, 1) |
| reveal_type(p) # N: Revealed type is "functools.partial[__main__.A]" |
| p(1, "no") # E: Argument 2 to "A" has incompatible type "str"; expected "int" |
| |
| q: partial[A] = partial(A, 1) # OK |
| [builtins fixtures/tuple.pyi] |
| |
| [case testFunctoolsPartialTypeVarBound] |
| from typing import Callable, TypeVar, Type |
| import functools |
| |
| T = TypeVar("T", bound=Callable[[str, int], str]) |
| S = TypeVar("S", bound=Type[int]) |
| |
| def foo(f: T) -> T: |
| g = functools.partial(f, "foo") |
| return f |
| |
| def bar(f: S) -> S: |
| g = functools.partial(f, "foo") |
| return f |
| [builtins fixtures/primitives.pyi] |
| |
| [case testFunctoolsPartialAbstractType] |
| from abc import ABC, abstractmethod |
| from functools import partial |
| |
| class A(ABC): |
| def __init__(self) -> None: ... |
| @abstractmethod |
| def method(self) -> None: ... |
| |
| def f1(cls: type[A]) -> None: |
| cls() |
| partial_cls = partial(cls) |
| partial_cls() |
| |
| def f2() -> None: |
| A() # E: Cannot instantiate abstract class "A" with abstract attribute "method" |
| partial_cls = partial(A) # E: Cannot instantiate abstract class "A" with abstract attribute "method" |
| partial_cls() # E: Cannot instantiate abstract class "A" with abstract attribute "method" |
| [builtins fixtures/tuple.pyi] |
| |
| [case testFunctoolsPartialSelfType] |
| from functools import partial |
| from typing_extensions import Self |
| |
| class A: |
| def __init__(self, ts: float, msg: str) -> None: ... |
| |
| @classmethod |
| def from_msg(cls, msg: str) -> Self: |
| factory = partial(cls, ts=0) |
| return factory(msg=msg) |
| [builtins fixtures/tuple.pyi] |
| |
| [case testFunctoolsPartialTypeVarValues] |
| from functools import partial |
| from typing import TypeVar |
| |
| T = TypeVar("T", int, str) |
| |
| def f(x: int, y: T) -> T: |
| return y |
| |
| def g(x: T, y: int) -> T: |
| return x |
| |
| def h(x: T, y: T) -> T: |
| return x |
| |
| fp = partial(f, 1) |
| reveal_type(fp(1)) # N: Revealed type is "builtins.int" |
| reveal_type(fp("a")) # N: Revealed type is "builtins.str" |
| fp(object()) # E: Value of type variable "T" of "f" cannot be "object" |
| |
| gp = partial(g, 1) |
| reveal_type(gp(1)) # N: Revealed type is "builtins.int" |
| gp("a") # E: Argument 1 to "g" has incompatible type "str"; expected "int" |
| |
| hp = partial(h, 1) |
| reveal_type(hp(1)) # N: Revealed type is "builtins.int" |
| hp("a") # E: Argument 1 to "h" has incompatible type "str"; expected "int" |
| [builtins fixtures/tuple.pyi] |
| |
| [case testFunctoolsPartialOverloadedCallableProtocol] |
| from functools import partial |
| from typing import Callable, Protocol, overload |
| |
| class P(Protocol): |
| @overload |
| def __call__(self, x: int) -> int: ... |
| @overload |
| def __call__(self, x: str) -> str: ... |
| |
| def f(x: P): |
| reveal_type(partial(x, 1)()) # N: Revealed type is "builtins.int" |
| |
| # TODO: but this is incorrect, predating the functools.partial plugin |
| reveal_type(partial(x, "a")()) # N: Revealed type is "builtins.int" |
| [builtins fixtures/tuple.pyi] |
| |
| [case testFunctoolsPartialTypeVarErasure] |
| from typing import Callable, TypeVar, Union |
| from typing_extensions import ParamSpec, TypeVarTuple, Unpack |
| from functools import partial |
| |
| def use_int_callable(x: Callable[[int], int]) -> None: |
| pass |
| def use_func_callable( |
| x: Callable[ |
| [Callable[[int], None]], |
| Callable[[int], None], |
| ], |
| ) -> None: |
| pass |
| |
| Tc = TypeVar("Tc", int, str) |
| Tb = TypeVar("Tb", bound=Union[int, str]) |
| P = ParamSpec("P") |
| Ts = TypeVarTuple("Ts") |
| |
| def func_b(a: Tb, b: str) -> Tb: |
| return a |
| def func_c(a: Tc, b: str) -> Tc: |
| return a |
| |
| def func_fn(fn: Callable[P, Tc], b: str) -> Callable[P, Tc]: |
| return fn |
| def func_fn_unpack(fn: Callable[[Unpack[Ts]], Tc], b: str) -> Callable[[Unpack[Ts]], Tc]: |
| return fn |
| |
| # We should not leak stray typevars that aren't in scope: |
| reveal_type(partial(func_b, b="")) # N: Revealed type is "functools.partial[Any]" |
| reveal_type(partial(func_c, b="")) # N: Revealed type is "functools.partial[Any]" |
| reveal_type(partial(func_fn, b="")) # N: Revealed type is "functools.partial[def (*Any, **Any) -> Any]" |
| reveal_type(partial(func_fn_unpack, b="")) # N: Revealed type is "functools.partial[def (*Any) -> Any]" |
| |
| use_int_callable(partial(func_b, b="")) |
| use_func_callable(partial(func_b, b="")) |
| use_int_callable(partial(func_c, b="")) |
| use_func_callable(partial(func_c, b="")) |
| use_int_callable(partial(func_fn, b="")) # E: Argument 1 to "use_int_callable" has incompatible type "partial[def (*Any, **Any) -> Any]"; expected "Callable[[int], int]" \ |
| # N: "partial[def (*Any, **Any) -> Any].__call__" has type "def __call__(__self, *args: Any, **kwargs: Any) -> def (*Any, **Any) -> Any" |
| use_func_callable(partial(func_fn, b="")) |
| use_int_callable(partial(func_fn_unpack, b="")) # E: Argument 1 to "use_int_callable" has incompatible type "partial[def (*Any) -> Any]"; expected "Callable[[int], int]" \ |
| # N: "partial[def (*Any) -> Any].__call__" has type "def __call__(__self, *args: Any, **kwargs: Any) -> def (*Any) -> Any" |
| use_func_callable(partial(func_fn_unpack, b="")) |
| |
| # But we should not erase typevars that aren't bound by function |
| # passed to `partial`: |
| |
| def outer_b(arg: Tb) -> None: |
| |
| def inner(a: Tb, b: str) -> Tb: |
| return a |
| |
| reveal_type(partial(inner, b="")) # N: Revealed type is "functools.partial[Tb`-1]" |
| use_int_callable(partial(inner, b="")) # E: Argument 1 to "use_int_callable" has incompatible type "partial[Tb]"; expected "Callable[[int], int]" \ |
| # N: "partial[Tb].__call__" has type "def __call__(__self, *args: Any, **kwargs: Any) -> Tb" |
| |
| def outer_c(arg: Tc) -> None: |
| |
| def inner(a: Tc, b: str) -> Tc: |
| return a |
| |
| reveal_type(partial(inner, b="")) # N: Revealed type is "functools.partial[builtins.int]" \ |
| # N: Revealed type is "functools.partial[builtins.str]" |
| use_int_callable(partial(inner, b="")) # E: Argument 1 to "use_int_callable" has incompatible type "partial[str]"; expected "Callable[[int], int]" \ |
| # N: "partial[str].__call__" has type "def __call__(__self, *args: Any, **kwargs: Any) -> str" |
| [builtins fixtures/tuple.pyi] |