Skip to content

Move self argument checks to a later phase - after decorator application, if any #19490

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged

Conversation

sterliakov
Copy link
Collaborator

@sterliakov sterliakov commented Jul 23, 2025

Fixes #19392.
Fixes #18989.
Fixes #18720.
Fixes #13434 (correct support for staticmethod wrappers, but not for equivalent classmethods reported in #18968).

Deferring this check in presence of decorators allows decorators that perform non-trivial transformations (such as making methods from non-methods and vice versa).

@sterliakov
Copy link
Collaborator Author

Surprisingly there are a few more more related tickets, I'll go through them tomorrow.

This comment has been minimized.

@bzoracler
Copy link
Contributor

This is working towards a much-needed QOL change IMO - thank you.

But thinking about this problem - is some of the self-check procedure itself redundant? Given this example:

class A:
    def method() -> None: ...  # self-check error
    def method2(arg: str, /) -> None: ...  # self-check error

# mypy already picks these up; are the self-check errors above redundant?
A().method()  # Attribute function "method" with type "Callable[[], None]" does not accept self argument  [misc]
A().method2()  # Invalid self argument "A" to attribute function "method2" with type "Callable[[str], None]"

Removing part of the self-check would naturally allow descriptor method transforms (and thus solve the original issue). It would also allow skipping the typing ceremony in several cases, such as omitting @{class,static}method for methods that would never be accessed from an instance, or defining temporary/throwaway decorators in class bodies.

(Of course, an unannotated first positional argument is still implicitly Self-like.)

@sterliakov
Copy link
Collaborator Author

@bzoracler For me current behaviour (errors at the definition site) is superior by a huge margin. Tracing selftypes across modules is inconvenient, I really want mypy to say "hey, you're probably missing self here" as early as possible. They are redundant, but otherwise you may not notice missing self on unused methods (please don't ask me why do I care about unused methods...)

I know one and only one use case where this is still a problem (one-time decorators you mentioned). I don't really like when people do that, it takes a few more more seconds to parse in my head, but it's a common pattern that has some merit. We can make that an exception as well: do not emit these errors if func is later used as a decorator in the same class.

omitting @{class,static}method for methods that would never be accessed from an instance

Could you elaborate?

@bzoracler
Copy link
Contributor

omitting @{class,static}method for methods that would never be accessed from an instance

Forget the mention of @classmethod here, that was a mistake. Omitting @staticmethod isn't incredibly common, but @staticmethod is redundant for a class used as a static attribute and method holder where instances of the class are never created, so omitting @staticmethod cuts verbosity and saves an extra descriptor call path. (To be clear, I'm not supportive of using such a pattern; it's obviously non-Pythonic.)

Thinking about it a bit more, several other popular languages (C++, Java) don't use explicit self in the signature, so I can see that it does help many people to employ a missing self check at the definition site. Those same languages would also force declaration of static types from the first parameter, so it looks like an invalid self annotation would help the same group of people. I'll discard this idea for now.

@sterliakov
Copy link
Collaborator Author

zope.interface changes are correct, I have no idea why they weren't reported before, but now they are.

@sterliakov sterliakov marked this pull request as ready for review July 25, 2025 21:53

This comment has been minimized.

@sterliakov sterliakov requested a review from ilevkivskyi July 27, 2025 15:02
Copy link
Member

@ilevkivskyi ilevkivskyi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LG, this makes sense! I have few suggestions for extra tests.

This comment has been minimized.

@ilevkivskyi
Copy link
Member

@sterliakov The new zope errors are not correct. Previously they were correctly ignored because they were inside an untyped function. You probably need to add a self.in_checked_function() somewhere (like it was in semanal.py from where you moved that error).

@sterliakov
Copy link
Collaborator Author

Ough. Thanks! I decided to go with slightly different logic - only silence inside untyped function (same as self.in_checked_function but ignoring the func we are currently analyzing) iff the method is also untyped. This aligns with our checking of nested functions.

Copy link
Contributor

Diff from mypy_primer, showing the effect of this PR on open source code:

zope.interface (https://github.com/zopefoundation/zope.interface)
- src/zope/interface/common/numbers.py:42: error: Method must have at least one argument. Did you forget the "self" argument?  [misc]
- src/zope/interface/common/numbers.py:52: error: Method must have at least one argument. Did you forget the "self" argument?  [misc]
- src/zope/interface/common/collections.py:119: error: Method must have at least one argument. Did you forget the "self" argument?  [misc]
- src/zope/interface/common/collections.py:134: error: Method must have at least one argument. Did you forget the "self" argument?  [misc]
- src/zope/interface/common/collections.py:174: error: Method must have at least one argument. Did you forget the "self" argument?  [misc]
- src/zope/interface/common/collections.py:182: error: Method must have at least one argument. Did you forget the "self" argument?  [misc]

@ilevkivskyi ilevkivskyi merged commit ad76e16 into python:master Jul 28, 2025
20 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
3 participants
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy