Repository: python/mypy
Pull request: More helpful error for missing self
Fixes #14385

Problem statement:
Method must have at least one argument [misc]
I have the following code:
```

class SpreadsheetInterface(ABC):
    
    @abstractmethod
    def is_page_account():
        pass
```

But im receiving an error aside of the code 

Method must have at least one argument [misc]

How do i fix this message?

Hints from issue discussion:
`def is_page_account(self):`
I'm new to Python using OOP, so I missed this error, thanks!
Sure, happy to help! Just opened a PR to improve the error message here: https://github.com/python/mypy/pull/14386
this is awesome! Congrats!

Commit message: lint

Patch to review:
diff --git a/mypy/semanal.py b/mypy/semanal.py
index 51310e4f3e4d..f4068ac6c26e 100644
--- a/mypy/semanal.py
+++ b/mypy/semanal.py
@@ -947,7 +947,10 @@ def prepare_method_signature(self, func: FuncDef, info: TypeInfo, has_self_type:
             if func.name in ["__init_subclass__", "__class_getitem__"]:
                 func.is_class = True
             if not func.arguments:
-                self.fail("Method must have at least one argument", func)
+                self.fail(
+                    "Method must have at least one argument. Did you forget the self argument?",
+                    func,
+                )
             elif isinstance(functype, CallableType):
                 self_type = get_proper_type(functype.arg_types[0])
                 if isinstance(self_type, AnyType):
diff --git a/test-data/unit/check-classes.test b/test-data/unit/check-classes.test
index 8784c73c5b17..06896e5358de 100644
--- a/test-data/unit/check-classes.test
+++ b/test-data/unit/check-classes.test
@@ -2901,7 +2901,7 @@ b.bad = 'a'  # E: Incompatible types in assignment (expression has type "str", v
 from typing import Any
 
 class Test:
-    def __setattr__() -> None: ...  # E: Method must have at least one argument # E: Invalid signature "Callable[[], None]" for "__setattr__"
+    def __setattr__() -> None: ...  # E: Method must have at least one argument. Did you forget the self argument? # E: Invalid signature "Callable[[], None]" for "__setattr__"
 t = Test()
 t.crash = 'test'  # E: "Test" has no attribute "crash"
 
@@ -7120,7 +7120,7 @@ reveal_type(Foo().y)  # N: Revealed type is "builtins.list[Any]"
 # flags: --check-untyped-defs
 
 class Foo:
-    def bad():  # E: Method must have at least one argument
+    def bad():  # E: Method must have at least one argument. Did you forget the self argument?
         self.x = 0  # E: Name "self" is not defined
 
 [case testTypeAfterAttributeAccessWithDisallowAnyExpr]
diff --git a/test-data/unit/check-functions.test b/test-data/unit/check-functions.test
index ae6424f743be..38e3e584065e 100644
--- a/test-data/unit/check-functions.test
+++ b/test-data/unit/check-functions.test
@@ -2708,7 +2708,7 @@ class A:
     @dec
     def e(self) -> int: pass
     @property
-    def g() -> int: pass   # E: Method must have at least one argument
+    def g() -> int: pass   # E: Method must have at least one argument. Did you forget the self argument?
     @property
     def h(self, *args, **kwargs) -> int: pass   # OK
 [builtins fixtures/property.pyi]
diff --git a/test-data/unit/check-super.test b/test-data/unit/check-super.test
index 6537f563a99c..d72bf8638f11 100644
--- a/test-data/unit/check-super.test
+++ b/test-data/unit/check-super.test
@@ -365,7 +365,7 @@ class A:
     def f(self) -> None: pass
 
 class B(A):
-    def g() -> None: # E: Method must have at least one argument
+    def g() -> None: # E: Method must have at least one argument. Did you forget the self argument?
         super().f() # E: super() requires one or more positional arguments in enclosing function
     def h(self) -> None:
         def a() -> None:
diff --git a/test-data/unit/fine-grained.test b/test-data/unit/fine-grained.test
index 1a318b52a082..779697930b69 100644
--- a/test-data/unit/fine-grained.test
+++ b/test-data/unit/fine-grained.test
@@ -1586,11 +1586,11 @@ class A:
 [file b.py.3]
 2
 [out]
-a.py:3: error: Method must have at least one argument
+a.py:3: error: Method must have at least one argument. Did you forget the self argument?
 ==
-a.py:3: error: Method must have at least one argument
+a.py:3: error: Method must have at least one argument. Did you forget the self argument?
 ==
-a.py:3: error: Method must have at least one argument
+a.py:3: error: Method must have at least one argument. Did you forget the self argument?
 
 [case testBaseClassDeleted]
 import m
@@ -2007,11 +2007,11 @@ class A:
 class A:
     def foo(self) -> int: pass
 [out]
-a.py:2: error: Method must have at least one argument
+a.py:2: error: Method must have at least one argument. Did you forget the self argument?
 ==
-a.py:2: error: Method must have at least one argument
+a.py:2: error: Method must have at least one argument. Did you forget the self argument?
 ==
-a.py:2: error: Method must have at least one argument
+a.py:2: error: Method must have at least one argument. Did you forget the self argument?
 ==
 
 [case testPreviousErrorInMethodSemanal2]
diff --git a/test-data/unit/semanal-errors.test b/test-data/unit/semanal-errors.test
index 5697d473414e..3f34f0748a7a 100644
--- a/test-data/unit/semanal-errors.test
+++ b/test-data/unit/semanal-errors.test
@@ -542,7 +542,7 @@ import typing
 class A:
   def f(): pass
 [out]
-main:3: error: Method must have at least one argument
+main:3: error: Method must have at least one argument. Did you forget the self argument?
 
 [case testInvalidBaseClass]
 import typing
@@ -564,8 +564,8 @@ class A:
   def f() -> None: pass
   def g(): pass
 [out]
-main:3: error: Method must have at least one argument
-main:4: error: Method must have at least one argument
+main:3: error: Method must have at least one argument. Did you forget the self argument?
+main:4: error: Method must have at least one argument. Did you forget the self argument?
 
 [case testMultipleMethodDefinition]
 import typing


Code review comments:
diff_hunk: @@ -947,7 +947,10 @@ def prepare_method_signature(self, func: FuncDef, info: TypeInfo, has_self_type:
             if func.name in ["__init_subclass__", "__class_getitem__"]:
                 func.is_class = True
             if not func.arguments:
-                self.fail("Method must have at least one argument", func)
+                self.fail(
+                    "Method must have at least one argument. Did you forget the self argument?",
path: mypy/semanal.py
text: @user1:
```suggestion
                    'Method must have at least one argument. Did you forget the "self" argument?',
```
I believe our convention is to put code samples in quotes in error messages.