Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 53c7bb2

Browse files
authored
Show warning if self / cls arguments are missing (#11317)
Closes #11309
1 parent 9aaeef5 commit 53c7bb2

12 files changed

Lines changed: 76 additions & 13 deletions

mypy/messages.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -649,6 +649,7 @@ def missing_named_argument(self, callee: CallableType, context: Context, name: s
649649
def too_many_arguments(self, callee: CallableType, context: Context) -> None:
650650
msg = 'Too many arguments' + for_function(callee)
651651
self.fail(msg, context, code=codes.CALL_ARG)
652+
self.maybe_note_about_special_args(callee, context)
652653

653654
def too_many_arguments_from_typed_dict(self,
654655
callee: CallableType,
@@ -668,6 +669,18 @@ def too_many_positional_arguments(self, callee: CallableType,
668669
context: Context) -> None:
669670
msg = 'Too many positional arguments' + for_function(callee)
670671
self.fail(msg, context)
672+
self.maybe_note_about_special_args(callee, context)
673+
674+
def maybe_note_about_special_args(self, callee: CallableType, context: Context) -> None:
675+
# https://github.com/python/mypy/issues/11309
676+
first_arg = callee.def_extras.get('first_arg')
677+
if first_arg and first_arg not in {'self', 'cls', 'mcs'}:
678+
self.note(
679+
'Looks like the first special argument in a method '
680+
'is not named "self", "cls", or "mcs", '
681+
'maybe it is missing?',
682+
context,
683+
)
671684

672685
def unexpected_keyword_argument(self, callee: CallableType, name: str, arg_type: Type,
673686
context: Context) -> None:

mypy/typeops.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
copy_type, TypeAliasType, TypeQuery, ParamSpecType
1818
)
1919
from mypy.nodes import (
20-
FuncBase, FuncItem, OverloadedFuncDef, TypeInfo, ARG_STAR, ARG_STAR2, ARG_POS,
20+
FuncBase, FuncItem, FuncDef, OverloadedFuncDef, TypeInfo, ARG_STAR, ARG_STAR2, ARG_POS,
2121
Expression, StrExpr, Var, Decorator, SYMBOL_FUNCBASE_TYPES
2222
)
2323
from mypy.maptype import map_instance_to_supertype
@@ -572,6 +572,8 @@ def callable_type(fdef: FuncItem, fallback: Instance,
572572
line=fdef.line,
573573
column=fdef.column,
574574
implicit=True,
575+
# We need this for better error messages, like missing `self` note:
576+
definition=fdef if isinstance(fdef, FuncDef) else None,
575577
)
576578

577579

mypy/types.py

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1059,9 +1059,16 @@ def __init__(self,
10591059
# after serialization, but it is useful in error messages.
10601060
# TODO: decide how to add more info here (file, line, column)
10611061
# without changing interface hash.
1062-
self.def_extras = {'first_arg': definition.arguments[0].variable.name
1063-
if definition.arg_names and definition.info and
1064-
not definition.is_static else None}
1062+
self.def_extras = {
1063+
'first_arg': (
1064+
definition.arguments[0].variable.name
1065+
if (getattr(definition, 'arguments', None)
1066+
and definition.arg_names
1067+
and definition.info
1068+
and not definition.is_static)
1069+
else None
1070+
),
1071+
}
10651072
else:
10661073
self.def_extras = {}
10671074
self.type_guard = type_guard

test-data/unit/check-abstract.test

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -446,7 +446,7 @@ class A(I):
446446
[out]
447447
main:10: error: Signature of "g" incompatible with supertype "I"
448448
main:10: note: Superclass:
449-
main:10: note: def g(x: Any) -> Any
449+
main:10: note: def g(self, x: Any) -> Any
450450
main:10: note: Subclass:
451451
main:10: note: def g(self, x: Any, y: Any) -> None
452452

test-data/unit/check-callable.test

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -506,3 +506,42 @@ reveal_type(_TYPE) # N: Revealed type is "def (x: Any) -> builtins.type"
506506
_TYPE('bar')
507507

508508
[builtins fixtures/callable.pyi]
509+
510+
[case testErrorMessageAboutSelf]
511+
# https://github.com/python/mypy/issues/11309
512+
class Some:
513+
def method(self, a) -> None: pass
514+
@classmethod
515+
def cls_method(cls, a) -> None: pass
516+
@staticmethod
517+
def st_method(a) -> None: pass
518+
519+
def bad_method(a) -> None: pass
520+
@classmethod
521+
def bad_cls_method(a) -> None: pass
522+
@staticmethod
523+
def bad_st_method() -> None: pass
524+
525+
s: Some
526+
527+
s.method(1)
528+
s.cls_method(1)
529+
Some.cls_method(1)
530+
s.st_method(1)
531+
Some.st_method(1)
532+
533+
s.method(1, 2) # E: Too many arguments for "method" of "Some"
534+
s.cls_method(1, 2) # E: Too many arguments for "cls_method" of "Some"
535+
Some.cls_method(1, 2) # E: Too many arguments for "cls_method" of "Some"
536+
s.st_method(1, 2) # E: Too many arguments for "st_method" of "Some"
537+
Some.st_method(1, 2) # E: Too many arguments for "st_method" of "Some"
538+
539+
s.bad_method(1) # E: Too many arguments for "bad_method" of "Some" \
540+
# N: Looks like the first special argument in a method is not named "self", "cls", or "mcs", maybe it is missing?
541+
s.bad_cls_method(1) # E: Too many arguments for "bad_cls_method" of "Some" \
542+
# N: Looks like the first special argument in a method is not named "self", "cls", or "mcs", maybe it is missing?
543+
Some.bad_cls_method(1) # E: Too many arguments for "bad_cls_method" of "Some" \
544+
# N: Looks like the first special argument in a method is not named "self", "cls", or "mcs", maybe it is missing?
545+
s.bad_st_method(1) # E: Too many arguments for "bad_st_method" of "Some"
546+
Some.bad_st_method(1) # E: Too many arguments for "bad_st_method" of "Some"
547+
[builtins fixtures/callable.pyi]

test-data/unit/check-classes.test

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2835,7 +2835,7 @@ C(foo='') # E: Argument "foo" to "C" has incompatible type "str"; expected "Opti
28352835

28362836
[case testConstructInstanceWithDynamicallyTyped__new__]
28372837
class C:
2838-
def __new__(cls, foo):
2838+
def __new__(cls, foo): # N: "C" defined here
28392839
obj = object.__new__(cls)
28402840
return obj
28412841

test-data/unit/check-columns.test

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ def foobar(): pass
135135
[builtins fixtures/module.pyi]
136136

137137
[case testColumnUnexpectedOrMissingKeywordArg]
138-
def f(): pass
138+
def f(): pass # N:1: "f" defined here
139139
# TODO: Point to "x" instead
140140
(f(x=1)) # E:2: Unexpected keyword argument "x" for "f"
141141
def g(*, x: int) -> None: pass
@@ -402,7 +402,7 @@ from typing import TypeVar, List
402402

403403
T = TypeVar('T', int, str)
404404

405-
def g(x): pass
405+
def g(x): pass # N:1: "g" defined here
406406

407407
def f(x: T) -> T:
408408
(x.bad) # E:6: "int" has no attribute "bad" \

test-data/unit/check-dynamic-typing.test

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -730,7 +730,7 @@ class A(B):
730730
[out]
731731
main:5: error: Signature of "f" incompatible with supertype "B"
732732
main:5: note: Superclass:
733-
main:5: note: def f(x: Any, y: Any) -> Any
733+
main:5: note: def f(self, x: Any, y: Any) -> Any
734734
main:5: note: Subclass:
735735
main:5: note: def f(self, x: A) -> None
736736

test-data/unit/check-incremental.test

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2886,7 +2886,7 @@ tmp/m/a.py:1: error: Unsupported operand types for + ("int" and "str")
28862886

28872887
[case testDisallowAnyExprIncremental]
28882888
# cmd: mypy -m main
2889-
# flags: --disallow-any-expr
2889+
# flags: --disallow-any-expr
28902890

28912891
[file ns.py]
28922892
class Namespace:

test-data/unit/check-kwargs.test

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -252,7 +252,7 @@ class B: pass
252252

253253
[case testCallingDynamicallyTypedFunctionWithKeywordArgs]
254254
import typing
255-
def f(x, y=A()): pass
255+
def f(x, y=A()): pass # N: "f" defined here
256256
f(x=A(), y=A())
257257
f(y=A(), x=A())
258258
f(y=A()) # E: Missing positional argument "x" in call to "f"

0 commit comments

Comments
 (0)