From 442cd5090bcb9e5513218cf54a8d85b88910eb8b Mon Sep 17 00:00:00 2001 From: Leo Ji Date: Wed, 1 Apr 2026 01:33:55 +0000 Subject: [PATCH] fix: clarify "Extra argument from **args" as "from **TypedDict" When a TypedDict is unpacked with ** and has extra keys that the callee does not accept, the error message referred to "**args": Extra argument "y" from **args for "func" The term "**args" is confusing because it looks like a *args/**kwargs variable name. Since the source is always a TypedDict (the function is named `too_many_arguments_from_typed_dict`), the message now reads: Extra argument "y" from **TypedDict for "func" Closes #20986 Made-with: Cursor --- mypy/messages.py | 2 +- test-data/unit/check-functools.test | 4 ++-- test-data/unit/check-typeddict.test | 4 ++-- test-data/unit/check-typevar-tuple.test | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/mypy/messages.py b/mypy/messages.py index 51bb0b7ee9be6..beb5100399234 100644 --- a/mypy/messages.py +++ b/mypy/messages.py @@ -957,7 +957,7 @@ def too_many_arguments_from_typed_dict( # Try to determine the name of the extra argument. for key in arg_type.items: if key not in callee.arg_names: - msg = f'Extra argument "{key}" from **args' + for_function(callee) + msg = f'Extra argument "{key}" from **TypedDict' + for_function(callee) break else: self.too_many_arguments(callee, context) diff --git a/test-data/unit/check-functools.test b/test-data/unit/check-functools.test index 77070d61a013c..6678fa8818750 100644 --- a/test-data/unit/check-functools.test +++ b/test-data/unit/check-functools.test @@ -491,8 +491,8 @@ def main4(a2good: A2Good, a2bad: A2Bad, **d2: Unpack[D2]) -> None: 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" + partial(fn1, **d2)() # E: Extra argument "a2" from **TypedDict for "fn1" + partial(fn2, **d2)() # E: Extra argument "a2" from **TypedDict for "fn2" def main6(a2good: A2Good, a2bad: A2Bad, **d1: Unpack[D1]) -> None: partial(fn3, **d1)() # E: Missing positional argument "a1" in call to "fn3" diff --git a/test-data/unit/check-typeddict.test b/test-data/unit/check-typeddict.test index 43fcf13e7be17..41ffe18a038df 100644 --- a/test-data/unit/check-typeddict.test +++ b/test-data/unit/check-typeddict.test @@ -1835,9 +1835,9 @@ a: A f1(**a) f2(**a) # E: Argument "y" to "f2" has incompatible type "str"; expected "int" f3(**a) # E: Argument "x" to "f3" has incompatible type "int"; expected "B" -f4(**a) # E: Extra argument "y" from **args for "f4" +f4(**a) # E: Extra argument "y" from **TypedDict for "f4" f5(**a) # E: Missing positional arguments "y", "z" in call to "f5" -f6(**a) # E: Extra argument "y" from **args for "f6" +f6(**a) # E: Extra argument "y" from **TypedDict for "f6" f1(1, **a) # E: "f1" gets multiple values for keyword argument "x" [builtins fixtures/dict.pyi] [typing fixtures/typing-typeddict.pyi] diff --git a/test-data/unit/check-typevar-tuple.test b/test-data/unit/check-typevar-tuple.test index 703653227e200..5495b9890760d 100644 --- a/test-data/unit/check-typevar-tuple.test +++ b/test-data/unit/check-typevar-tuple.test @@ -2251,7 +2251,7 @@ def test( **kwargs: Unpack[Keywords], ) -> T: if bool(): - func(*args, **kwargs) # E: Extra argument "a" from **args + func(*args, **kwargs) # E: Extra argument "a" from **TypedDict return func(*args) def test2( x: int,