Skip to content

Commit aa285e3

Browse files
authored
Use correct pos-only arg formatting in pretty_callable (#13474)
1 parent d315403 commit aa285e3

12 files changed

+169
-52
lines changed

mypy/messages.py

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2377,6 +2377,7 @@ def [T <: int] f(self, x: int, y: T) -> None
23772377
"""
23782378
s = ""
23792379
asterisk = False
2380+
slash = False
23802381
for i in range(len(tp.arg_types)):
23812382
if s:
23822383
s += ", "
@@ -2394,23 +2395,29 @@ def [T <: int] f(self, x: int, y: T) -> None
23942395
s += format_type_bare(tp.arg_types[i])
23952396
if tp.arg_kinds[i].is_optional():
23962397
s += " = ..."
2398+
if (
2399+
not slash
2400+
and tp.arg_kinds[i].is_positional()
2401+
and name is None
2402+
and (
2403+
i == len(tp.arg_types) - 1
2404+
or (tp.arg_names[i + 1] is not None or not tp.arg_kinds[i + 1].is_positional())
2405+
)
2406+
):
2407+
s += ", /"
2408+
slash = True
23972409

23982410
# If we got a "special arg" (i.e: self, cls, etc...), prepend it to the arg list
23992411
if (
24002412
isinstance(tp.definition, FuncDef)
24012413
and tp.definition.name is not None
24022414
and hasattr(tp.definition, "arguments")
24032415
):
2404-
definition_args = [arg.variable.name for arg in tp.definition.arguments]
2405-
if (
2406-
definition_args
2407-
and tp.arg_names != definition_args
2408-
and len(definition_args) > 0
2409-
and definition_args[0]
2410-
):
2416+
definition_arg_names = [arg.variable.name for arg in tp.definition.arguments]
2417+
if len(definition_arg_names) > len(tp.arg_names) and definition_arg_names[0]:
24112418
if s:
24122419
s = ", " + s
2413-
s = definition_args[0] + s
2420+
s = definition_arg_names[0] + s
24142421
s = f"{tp.definition.name}({s})"
24152422
elif tp.name:
24162423
first_arg = tp.def_extras.get("first_arg")

test-data/unit/check-class-namedtuple.test

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -585,8 +585,8 @@ class Base(NamedTuple):
585585
reveal_type(self[T]) # N: Revealed type is "builtins.int" \
586586
# E: No overload variant of "__getitem__" of "tuple" matches argument type "object" \
587587
# N: Possible overload variants: \
588-
# N: def __getitem__(self, int) -> int \
589-
# N: def __getitem__(self, slice) -> Tuple[int, ...]
588+
# N: def __getitem__(self, int, /) -> int \
589+
# N: def __getitem__(self, slice, /) -> Tuple[int, ...]
590590
return self.x
591591
def bad_override(self) -> int:
592592
return self.x

test-data/unit/check-classes.test

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1897,12 +1897,12 @@ class B(A):
18971897
[out]
18981898
tmp/foo.pyi:5: error: Signature of "__add__" incompatible with supertype "A"
18991899
tmp/foo.pyi:5: note: Superclass:
1900-
tmp/foo.pyi:5: note: def __add__(self, int) -> int
1900+
tmp/foo.pyi:5: note: def __add__(self, int, /) -> int
19011901
tmp/foo.pyi:5: note: Subclass:
19021902
tmp/foo.pyi:5: note: @overload
1903-
tmp/foo.pyi:5: note: def __add__(self, int) -> int
1903+
tmp/foo.pyi:5: note: def __add__(self, int, /) -> int
19041904
tmp/foo.pyi:5: note: @overload
1905-
tmp/foo.pyi:5: note: def __add__(self, str) -> str
1905+
tmp/foo.pyi:5: note: def __add__(self, str, /) -> str
19061906
tmp/foo.pyi:5: note: Overloaded operator methods cannot have wider argument types in overrides
19071907

19081908
[case testOperatorMethodOverrideWideningArgumentType]
@@ -2012,16 +2012,16 @@ class B(A):
20122012
tmp/foo.pyi:8: error: Signature of "__add__" incompatible with supertype "A"
20132013
tmp/foo.pyi:8: note: Superclass:
20142014
tmp/foo.pyi:8: note: @overload
2015-
tmp/foo.pyi:8: note: def __add__(self, int) -> A
2015+
tmp/foo.pyi:8: note: def __add__(self, int, /) -> A
20162016
tmp/foo.pyi:8: note: @overload
2017-
tmp/foo.pyi:8: note: def __add__(self, str) -> A
2017+
tmp/foo.pyi:8: note: def __add__(self, str, /) -> A
20182018
tmp/foo.pyi:8: note: Subclass:
20192019
tmp/foo.pyi:8: note: @overload
2020-
tmp/foo.pyi:8: note: def __add__(self, int) -> A
2020+
tmp/foo.pyi:8: note: def __add__(self, int, /) -> A
20212021
tmp/foo.pyi:8: note: @overload
2022-
tmp/foo.pyi:8: note: def __add__(self, str) -> A
2022+
tmp/foo.pyi:8: note: def __add__(self, str, /) -> A
20232023
tmp/foo.pyi:8: note: @overload
2024-
tmp/foo.pyi:8: note: def __add__(self, type) -> A
2024+
tmp/foo.pyi:8: note: def __add__(self, type, /) -> A
20252025
tmp/foo.pyi:8: note: Overloaded operator methods cannot have wider argument types in overrides
20262026

20272027
[case testOverloadedOperatorMethodOverrideWithSwitchedItemOrder]

test-data/unit/check-ctypes.test

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ a[1] = ctypes.c_int(42)
1515
a[2] = MyCInt(42)
1616
a[3] = b"bytes" # E: No overload variant of "__setitem__" of "Array" matches argument types "int", "bytes" \
1717
# N: Possible overload variants: \
18-
# N: def __setitem__(self, int, Union[c_int, int]) -> None \
19-
# N: def __setitem__(self, slice, List[Union[c_int, int]]) -> None
18+
# N: def __setitem__(self, int, Union[c_int, int], /) -> None \
19+
# N: def __setitem__(self, slice, List[Union[c_int, int]], /) -> None
2020
for x in a:
2121
reveal_type(x) # N: Revealed type is "builtins.int"
2222
[builtins fixtures/floatdict.pyi]
@@ -38,13 +38,13 @@ reveal_type(mya[1:3]) # N: Revealed type is "builtins.list[__main__.MyCInt]"
3838
mya[0] = 42
3939
mya[1] = ctypes.c_int(42) # E: No overload variant of "__setitem__" of "Array" matches argument types "int", "c_int" \
4040
# N: Possible overload variants: \
41-
# N: def __setitem__(self, int, Union[MyCInt, int]) -> None \
42-
# N: def __setitem__(self, slice, List[Union[MyCInt, int]]) -> None
41+
# N: def __setitem__(self, int, Union[MyCInt, int], /) -> None \
42+
# N: def __setitem__(self, slice, List[Union[MyCInt, int]], /) -> None
4343
mya[2] = MyCInt(42)
4444
mya[3] = b"bytes" # E: No overload variant of "__setitem__" of "Array" matches argument types "int", "bytes" \
4545
# N: Possible overload variants: \
46-
# N: def __setitem__(self, int, Union[MyCInt, int]) -> None \
47-
# N: def __setitem__(self, slice, List[Union[MyCInt, int]]) -> None
46+
# N: def __setitem__(self, int, Union[MyCInt, int], /) -> None \
47+
# N: def __setitem__(self, slice, List[Union[MyCInt, int]], /) -> None
4848
for myx in mya:
4949
reveal_type(myx) # N: Revealed type is "__main__.MyCInt"
5050

@@ -71,8 +71,8 @@ mya[1] = ctypes.c_uint(42)
7171
mya[2] = MyCInt(42)
7272
mya[3] = b"bytes" # E: No overload variant of "__setitem__" of "Array" matches argument types "int", "bytes" \
7373
# N: Possible overload variants: \
74-
# N: def __setitem__(self, int, Union[MyCInt, int, c_uint]) -> None \
75-
# N: def __setitem__(self, slice, List[Union[MyCInt, int, c_uint]]) -> None
74+
# N: def __setitem__(self, int, Union[MyCInt, int, c_uint], /) -> None \
75+
# N: def __setitem__(self, slice, List[Union[MyCInt, int, c_uint]], /) -> None
7676
for myx in mya:
7777
reveal_type(myx) # N: Revealed type is "Union[__main__.MyCInt, builtins.int]"
7878
[builtins fixtures/floatdict.pyi]

test-data/unit/check-expressions.test

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -857,8 +857,8 @@ a[b]
857857
a[c]
858858
a[1] # E: No overload variant of "__getitem__" of "A" matches argument type "int" \
859859
# N: Possible overload variants: \
860-
# N: def __getitem__(self, B) -> int \
861-
# N: def __getitem__(self, C) -> str
860+
# N: def __getitem__(self, B, /) -> int \
861+
# N: def __getitem__(self, C, /) -> str
862862

863863
i, s = None, None # type: (int, str)
864864
if int():

test-data/unit/check-narrowing.test

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -436,8 +436,8 @@ else:
436436
weird_mixture: Union[KeyedTypedDict, KeyedNamedTuple]
437437
if weird_mixture["key"] is Key.B: # E: No overload variant of "__getitem__" of "tuple" matches argument type "str" \
438438
# N: Possible overload variants: \
439-
# N: def __getitem__(self, int) -> Literal[Key.C] \
440-
# N: def __getitem__(self, slice) -> Tuple[Literal[Key.C], ...]
439+
# N: def __getitem__(self, int, /) -> Literal[Key.C] \
440+
# N: def __getitem__(self, slice, /) -> Tuple[Literal[Key.C], ...]
441441
reveal_type(weird_mixture) # N: Revealed type is "Union[TypedDict('__main__.KeyedTypedDict', {'key': Literal[__main__.Key.B]}), Tuple[Literal[__main__.Key.C], fallback=__main__.KeyedNamedTuple]]"
442442
else:
443443
reveal_type(weird_mixture) # N: Revealed type is "Union[TypedDict('__main__.KeyedTypedDict', {'key': Literal[__main__.Key.B]}), Tuple[Literal[__main__.Key.C], fallback=__main__.KeyedNamedTuple]]"

test-data/unit/check-overloading.test

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -906,8 +906,8 @@ B() < B()
906906
A() < object() # E: Unsupported operand types for < ("A" and "object")
907907
B() < object() # E: No overload variant of "__lt__" of "B" matches argument type "object" \
908908
# N: Possible overload variants: \
909-
# N: def __lt__(self, B) -> int \
910-
# N: def __lt__(self, A) -> int
909+
# N: def __lt__(self, B, /) -> int \
910+
# N: def __lt__(self, A, /) -> int
911911

912912
[case testOverloadedForwardMethodAndCallingReverseMethod]
913913
from foo import *
@@ -925,8 +925,8 @@ A() + 1
925925
A() + B()
926926
A() + '' # E: No overload variant of "__add__" of "A" matches argument type "str" \
927927
# N: Possible overload variants: \
928-
# N: def __add__(self, A) -> int \
929-
# N: def __add__(self, int) -> int
928+
# N: def __add__(self, A, /) -> int \
929+
# N: def __add__(self, int, /) -> int
930930

931931
[case testOverrideOverloadSwapped]
932932
from foo import *
@@ -4738,12 +4738,12 @@ reveal_type(actually_b + Other()) # Note
47384738
[out]
47394739
main:12: error: Signature of "__add__" incompatible with supertype "A"
47404740
main:12: note: Superclass:
4741-
main:12: note: def __add__(self, A) -> A
4741+
main:12: note: def __add__(self, A, /) -> A
47424742
main:12: note: Subclass:
47434743
main:12: note: @overload
4744-
main:12: note: def __add__(self, Other) -> B
4744+
main:12: note: def __add__(self, Other, /) -> B
47454745
main:12: note: @overload
4746-
main:12: note: def __add__(self, A) -> A
4746+
main:12: note: def __add__(self, A, /) -> A
47474747
main:12: note: Overloaded operator methods cannot have wider argument types in overrides
47484748
main:32: note: Revealed type is "__main__.Other"
47494749

@@ -6494,6 +6494,23 @@ def foo(x: List[T]) -> str: ...
64946494
def foo(x: Sequence[int]) -> int: ...
64956495
[builtins fixtures/list.pyi]
64966496

6497+
# Also see `check-python38.test` for similar tests with `/` args:
6498+
[case testOverloadPositionalOnlyErrorMessageOldStyle]
6499+
from typing import overload
6500+
6501+
@overload
6502+
def foo(__a: int): ...
6503+
@overload
6504+
def foo(a: str): ...
6505+
def foo(a): ...
6506+
6507+
foo(a=1)
6508+
[out]
6509+
main:9: error: No overload variant of "foo" matches argument type "int"
6510+
main:9: note: Possible overload variants:
6511+
main:9: note: def foo(int, /) -> Any
6512+
main:9: note: def foo(a: str) -> Any
6513+
64976514
[case testOverloadUnionGenericBounds]
64986515
from typing import overload, TypeVar, Sequence, Union
64996516

test-data/unit/check-protocols.test

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2896,12 +2896,12 @@ c: Lst3[Str]
28962896
f(Lst3(c)) # E: Argument 1 to "f" has incompatible type "Lst3[Lst3[Str]]"; expected "GetItem[GetItem[Str]]" \
28972897
# N: Following member(s) of "Lst3[Lst3[Str]]" have conflicts: \
28982898
# N: Expected: \
2899-
# N: def __getitem__(self, int) -> GetItem[Str] \
2899+
# N: def __getitem__(self, int, /) -> GetItem[Str] \
29002900
# N: Got: \
29012901
# N: @overload \
2902-
# N: def __getitem__(self, slice) -> Lst3[Lst3[Str]] \
2902+
# N: def __getitem__(self, slice, /) -> Lst3[Lst3[Str]] \
29032903
# N: @overload \
2904-
# N: def __getitem__(self, bool) -> Lst3[Str]
2904+
# N: def __getitem__(self, bool, /) -> Lst3[Str]
29052905

29062906
[builtins fixtures/list.pyi]
29072907
[typing fixtures/typing-full.pyi]

test-data/unit/check-python38.test

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -576,3 +576,96 @@ class Bar:
576576
def f(self, a: Optional[str] = None, /, *, b: bool = False) -> None:
577577
...
578578
[builtins fixtures/bool.pyi]
579+
580+
[case testOverloadPositionalOnlyErrorMessage]
581+
from typing import overload
582+
583+
@overload
584+
def foo(a: int, /): ...
585+
@overload
586+
def foo(a: str): ...
587+
def foo(a): ...
588+
589+
foo(a=1)
590+
[out]
591+
main:9: error: No overload variant of "foo" matches argument type "int"
592+
main:9: note: Possible overload variants:
593+
main:9: note: def foo(int, /) -> Any
594+
main:9: note: def foo(a: str) -> Any
595+
596+
[case testOverloadPositionalOnlyErrorMessageAllTypes]
597+
from typing import overload
598+
599+
@overload
600+
def foo(a: int, /, b: int, *, c: int): ...
601+
@overload
602+
def foo(a: str, b: int, *, c: int): ...
603+
def foo(a, b, *, c): ...
604+
605+
foo(a=1)
606+
[out]
607+
main:9: error: No overload variant of "foo" matches argument type "int"
608+
main:9: note: Possible overload variants:
609+
main:9: note: def foo(int, /, b: int, *, c: int) -> Any
610+
main:9: note: def foo(a: str, b: int, *, c: int) -> Any
611+
612+
[case testOverloadPositionalOnlyErrorMessageMultiplePosArgs]
613+
from typing import overload
614+
615+
@overload
616+
def foo(a: int, b: int, c: int, /, d: str): ...
617+
@overload
618+
def foo(a: str, b: int, c: int, d: str): ...
619+
def foo(a, b, c, d): ...
620+
621+
foo(a=1)
622+
[out]
623+
main:9: error: No overload variant of "foo" matches argument type "int"
624+
main:9: note: Possible overload variants:
625+
main:9: note: def foo(int, int, int, /, d: str) -> Any
626+
main:9: note: def foo(a: str, b: int, c: int, d: str) -> Any
627+
628+
[case testOverloadPositionalOnlyErrorMessageMethod]
629+
from typing import overload
630+
631+
class Some:
632+
@overload
633+
def foo(self, __a: int): ...
634+
@overload
635+
def foo(self, a: float, /): ...
636+
@overload
637+
def foo(self, a: str): ...
638+
def foo(self, a): ...
639+
640+
Some().foo(a=1)
641+
[out]
642+
main:12: error: No overload variant of "foo" of "Some" matches argument type "int"
643+
main:12: note: Possible overload variants:
644+
main:12: note: def foo(self, int, /) -> Any
645+
main:12: note: def foo(self, float, /) -> Any
646+
main:12: note: def foo(self, a: str) -> Any
647+
648+
[case testOverloadPositionalOnlyErrorMessageClassMethod]
649+
from typing import overload
650+
651+
class Some:
652+
@overload
653+
@classmethod
654+
def foo(cls, __a: int): ...
655+
@overload
656+
@classmethod
657+
def foo(cls, a: float, /): ...
658+
@overload
659+
@classmethod
660+
def foo(cls, a: str): ...
661+
@classmethod
662+
def foo(cls, a): ...
663+
664+
Some.foo(a=1)
665+
[builtins fixtures/classmethod.pyi]
666+
[out]
667+
main:16: error: No overload variant of "foo" of "Some" matches argument type "int"
668+
main:16: note: Possible overload variants:
669+
main:16: note: def foo(cls, int, /) -> Any
670+
main:16: note: def foo(cls, float, /) -> Any
671+
main:16: note: def foo(cls, a: str) -> Any

test-data/unit/check-tuples.test

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1228,8 +1228,8 @@ y = ""
12281228
reveal_type(t[x]) # N: Revealed type is "Union[builtins.int, builtins.str]"
12291229
t[y] # E: No overload variant of "__getitem__" of "tuple" matches argument type "str" \
12301230
# N: Possible overload variants: \
1231-
# N: def __getitem__(self, int) -> object \
1232-
# N: def __getitem__(self, slice) -> Tuple[object, ...]
1231+
# N: def __getitem__(self, int, /) -> object \
1232+
# N: def __getitem__(self, slice, /) -> Tuple[object, ...]
12331233

12341234
[builtins fixtures/tuple.pyi]
12351235

test-data/unit/check-typeddict.test

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -478,9 +478,9 @@ fun2(a) # Error
478478
main:17: error: Argument 1 to "fun2" has incompatible type "A"; expected "StrIntMap"
479479
main:17: note: Following member(s) of "A" have conflicts:
480480
main:17: note: Expected:
481-
main:17: note: def __getitem__(self, str) -> int
481+
main:17: note: def __getitem__(self, str, /) -> int
482482
main:17: note: Got:
483-
main:17: note: def __getitem__(self, str) -> object
483+
main:17: note: def __getitem__(self, str, /) -> object
484484

485485
[case testTypedDictWithSimpleProtocolInference]
486486
from typing_extensions import Protocol, TypedDict

test-data/unit/pythoneval.test

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -660,8 +660,8 @@ a + 1
660660
[out]
661661
_testMapStr.py:4: error: No overload variant of "__add__" of "list" matches argument type "int"
662662
_testMapStr.py:4: note: Possible overload variants:
663-
_testMapStr.py:4: note: def __add__(self, List[str]) -> List[str]
664-
_testMapStr.py:4: note: def [_S] __add__(self, List[_S]) -> List[Union[_S, str]]
663+
_testMapStr.py:4: note: def __add__(self, List[str], /) -> List[str]
664+
_testMapStr.py:4: note: def [_S] __add__(self, List[_S], /) -> List[Union[_S, str]]
665665

666666
[case testRelativeImport]
667667
import typing
@@ -805,8 +805,8 @@ t + 1
805805
[out]
806806
_program.py:3: error: No overload variant of "__add__" of "tuple" matches argument type "int"
807807
_program.py:3: note: Possible overload variants:
808-
_program.py:3: note: def __add__(self, Tuple[str, ...]) -> Tuple[str, ...]
809-
_program.py:3: note: def [_T] __add__(self, Tuple[_T, ...]) -> Tuple[Union[str, _T], ...]
808+
_program.py:3: note: def __add__(self, Tuple[str, ...], /) -> Tuple[str, ...]
809+
_program.py:3: note: def [_T] __add__(self, Tuple[_T, ...], /) -> Tuple[Union[str, _T], ...]
810810

811811
[case testMultiplyTupleByIntegerReverse]
812812
n = 4
@@ -815,8 +815,8 @@ t + 1
815815
[out]
816816
_program.py:3: error: No overload variant of "__add__" of "tuple" matches argument type "int"
817817
_program.py:3: note: Possible overload variants:
818-
_program.py:3: note: def __add__(self, Tuple[str, ...]) -> Tuple[str, ...]
819-
_program.py:3: note: def [_T] __add__(self, Tuple[_T, ...]) -> Tuple[Union[str, _T], ...]
818+
_program.py:3: note: def __add__(self, Tuple[str, ...], /) -> Tuple[str, ...]
819+
_program.py:3: note: def [_T] __add__(self, Tuple[_T, ...], /) -> Tuple[Union[str, _T], ...]
820820

821821
[case testDictWithKeywordArgs]
822822
from typing import Dict, Any, List
@@ -1099,8 +1099,8 @@ _testTypedDictGet.py:8: note: Revealed type is "builtins.str"
10991099
_testTypedDictGet.py:9: note: Revealed type is "builtins.object"
11001100
_testTypedDictGet.py:10: error: All overload variants of "get" of "Mapping" require at least one argument
11011101
_testTypedDictGet.py:10: note: Possible overload variants:
1102-
_testTypedDictGet.py:10: note: def get(self, str) -> object
1103-
_testTypedDictGet.py:10: note: def [_T] get(self, str, default: object) -> object
1102+
_testTypedDictGet.py:10: note: def get(self, str, /) -> object
1103+
_testTypedDictGet.py:10: note: def [_T] get(self, str, /, default: object) -> object
11041104
_testTypedDictGet.py:12: note: Revealed type is "builtins.object"
11051105

11061106
[case testTypedDictMappingMethods]

0 commit comments

Comments
 (0)