@@ -191,6 +191,7 @@ functools.partial(1) # E: "int" not callable \
191
191
192
192
[case testFunctoolsPartialStar]
193
193
import functools
194
+ from typing import List
194
195
195
196
def foo(a: int, b: str, *args: int, d: str, **kwargs: int) -> int: ...
196
197
@@ -215,6 +216,13 @@ def bar(*a: bytes, **k: int):
215
216
p1("a", **k) # E: Argument 2 to "foo" has incompatible type "**Dict[str, int]"; expected "str"
216
217
p1(**k) # E: Argument 1 to "foo" has incompatible type "**Dict[str, int]"; expected "str"
217
218
p1(*a) # E: List or tuple expected as variadic arguments
219
+
220
+
221
+ def baz(a: int, b: int) -> int: ...
222
+ def test_baz(xs: List[int]):
223
+ p3 = functools.partial(baz, *xs)
224
+ p3()
225
+ p3(1) # E: Too many arguments for "baz"
218
226
[builtins fixtures/dict.pyi]
219
227
220
228
[case testFunctoolsPartialGeneric]
@@ -408,33 +416,83 @@ def foo(cls3: Type[B[T]]):
408
416
from typing_extensions import TypedDict, Unpack
409
417
from functools import partial
410
418
411
- class Data(TypedDict, total=False):
412
- x: int
413
-
414
- def f(**kwargs: Unpack[Data]) -> None: ...
415
- def g(**kwargs: Unpack[Data]) -> None:
416
- partial(f, **kwargs)()
417
-
418
- class MoreData(TypedDict, total=False):
419
- x: int
420
- y: int
419
+ class D1(TypedDict, total=False):
420
+ a1: int
421
+
422
+ def fn1(a1: int) -> None: ... # N: "fn1" defined here
423
+ def main1(**d1: Unpack[D1]) -> None:
424
+ partial(fn1, **d1)()
425
+ partial(fn1, **d1)(**d1)
426
+ partial(fn1, **d1)(a1=1)
427
+ partial(fn1, **d1)(a1="asdf") # E: Argument "a1" to "fn1" has incompatible type "str"; expected "int"
428
+ partial(fn1, **d1)(oops=1) # E: Unexpected keyword argument "oops" for "fn1"
429
+
430
+ def fn2(**kwargs: Unpack[D1]) -> None: ... # N: "fn2" defined here
431
+ def main2(**d1: Unpack[D1]) -> None:
432
+ partial(fn2, **d1)()
433
+ partial(fn2, **d1)(**d1)
434
+ partial(fn2, **d1)(a1=1)
435
+ partial(fn2, **d1)(a1="asdf") # E: Argument "a1" to "fn2" has incompatible type "str"; expected "int"
436
+ partial(fn2, **d1)(oops=1) # E: Unexpected keyword argument "oops" for "fn2"
437
+
438
+ class D2(TypedDict, total=False):
439
+ a1: int
440
+ a2: str
441
+
442
+ class A2Good(TypedDict, total=False):
443
+ a2: str
444
+ class A2Bad(TypedDict, total=False):
445
+ a2: int
446
+
447
+ def fn3(a1: int, a2: str) -> None: ... # N: "fn3" defined here
448
+ def main3(a2good: A2Good, a2bad: A2Bad, **d2: Unpack[D2]) -> None:
449
+ partial(fn3, **d2)()
450
+ partial(fn3, **d2)(a1=1, a2="asdf")
451
+
452
+ partial(fn3, **d2)(**d2)
453
+
454
+ partial(fn3, **d2)(a1="asdf") # E: Argument "a1" to "fn3" has incompatible type "str"; expected "int"
455
+ partial(fn3, **d2)(a1=1, a2="asdf", oops=1) # E: Unexpected keyword argument "oops" for "fn3"
456
+
457
+ partial(fn3, **d2)(**a2good)
458
+ partial(fn3, **d2)(**a2bad) # E: Argument "a2" to "fn3" has incompatible type "int"; expected "str"
459
+
460
+ def fn4(**kwargs: Unpack[D2]) -> None: ... # N: "fn4" defined here
461
+ def main4(a2good: A2Good, a2bad: A2Bad, **d2: Unpack[D2]) -> None:
462
+ partial(fn4, **d2)()
463
+ partial(fn4, **d2)(a1=1, a2="asdf")
464
+
465
+ partial(fn4, **d2)(**d2)
466
+
467
+ partial(fn4, **d2)(a1="asdf") # E: Argument "a1" to "fn4" has incompatible type "str"; expected "int"
468
+ partial(fn4, **d2)(a1=1, a2="asdf", oops=1) # E: Unexpected keyword argument "oops" for "fn4"
469
+
470
+ partial(fn3, **d2)(**a2good)
471
+ partial(fn3, **d2)(**a2bad) # E: Argument "a2" to "fn3" has incompatible type "int"; expected "str"
472
+
473
+ def main5(**d2: Unpack[D2]) -> None:
474
+ partial(fn1, **d2)() # E: Extra argument "a2" from **args for "fn1"
475
+ partial(fn2, **d2)() # E: Extra argument "a2" from **args for "fn2"
476
+
477
+ def main6(a2good: A2Good, a2bad: A2Bad, **d1: Unpack[D1]) -> None:
478
+ partial(fn3, **d1)() # E: Missing positional argument "a1" in call to "fn3"
479
+ partial(fn3, **d1)("asdf") # E: Too many positional arguments for "fn3" \
480
+ # E: Too few arguments for "fn3" \
481
+ # E: Argument 1 to "fn3" has incompatible type "str"; expected "int"
482
+ partial(fn3, **d1)(a2="asdf")
483
+ partial(fn3, **d1)(**a2good)
484
+ partial(fn3, **d1)(**a2bad) # E: Argument "a2" to "fn3" has incompatible type "int"; expected "str"
485
+
486
+ partial(fn4, **d1)()
487
+ partial(fn4, **d1)("asdf") # E: Too many positional arguments for "fn4" \
488
+ # E: Argument 1 to "fn4" has incompatible type "str"; expected "int"
489
+ partial(fn4, **d1)(a2="asdf")
490
+ partial(fn4, **d1)(**a2good)
491
+ partial(fn4, **d1)(**a2bad) # E: Argument "a2" to "fn4" has incompatible type "int"; expected "str"
421
492
422
- def f_more(**kwargs: Unpack[MoreData]) -> None: ...
423
- def g_more(**kwargs: Unpack[MoreData]) -> None:
424
- partial(f_more, **kwargs)()
425
-
426
- class Good(TypedDict, total=False):
427
- y: int
428
- class Bad(TypedDict, total=False):
429
- y: str
430
-
431
- def h(**kwargs: Unpack[Data]) -> None:
432
- bad: Bad
433
- partial(f_more, **kwargs)(**bad) # E: Argument "y" to "f_more" has incompatible type "str"; expected "int"
434
- good: Good
435
- partial(f_more, **kwargs)(**good)
436
493
[builtins fixtures/dict.pyi]
437
494
495
+
438
496
[case testFunctoolsPartialNestedGeneric]
439
497
from functools import partial
440
498
from typing import Generic, TypeVar, List
@@ -456,6 +514,21 @@ first_kw([1]) # E: Too many positional arguments for "get" \
456
514
# E: Argument 1 to "get" has incompatible type "List[int]"; expected "int"
457
515
[builtins fixtures/list.pyi]
458
516
517
+ [case testFunctoolsPartialHigherOrder]
518
+ from functools import partial
519
+ from typing import Callable
520
+
521
+ def fn(a: int, b: str, c: bytes) -> int: ...
522
+
523
+ def callback1(fn: Callable[[str, bytes], int]) -> None: ...
524
+ def callback2(fn: Callable[[str, int], int]) -> None: ...
525
+
526
+ callback1(partial(fn, 1))
527
+ # TODO: false negative
528
+ # https://github.com/python/mypy/issues/17461
529
+ callback2(partial(fn, 1))
530
+ [builtins fixtures/tuple.pyi]
531
+
459
532
[case testFunctoolsPartialClassObjectMatchingPartial]
460
533
from functools import partial
461
534
0 commit comments