Skip to content

Bind self-types in checkmember for decorated classmethods - #19025

Merged
JukkaL merged 3 commits into
python:masterfrom
sterliakov:bugfix/gh-19023-classmethod-self-decorated
Jun 13, 2025
Merged

JukkaL merged 3 commits into
python:masterfrom
sterliakov:bugfix/gh-19023-classmethod-self-decorated

Conversation

@sterliakov

Copy link
Copy Markdown
Collaborator

Fixes #19023. Fixes #18993.

@github-actions

This comment has been minimized.

@sterliakov
sterliakov marked this pull request as ready for review May 4, 2025 16:29
@sterliakov

Copy link
Copy Markdown
Collaborator Author

Okay, the steam/enums.py change is OK: there's unsupported @classproperty wrapped with a bunch of ignore comments and with unsupported ternary up the inheritance chain, enum magic doesn't work well there.

@A5rocks A5rocks left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I have a question but the results of this make sense. It's annoying to have type vars floating around!

Comment thread mypy/checkmember.py
t, isuper, is_classmethod, is_staticmethod, mx.self_type, original_vars=original_vars
)
if is_decorated and not is_staticmethod:
t = expand_self_type_if_needed(

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I don't quite understand why we need to put this self type expansion here. Specifically: this branch is only for decorators. Shouldn't whatever is applying the decorators handle self types instead?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

This function handles lookup on classes, we bind self types here for everything that can reasonably contain them as this is the latest moment possible (see Var branch above). Consider a decorator that preserves function signature applied to a def method(self) -> Self. Applying the decorator still yields a Self-returning callable, which is the best representation until we actually want to show it or apply it to something, when Self loses its semantic meaning. Otherwise, for example, that method will be impossible to cleanly override in subclasses.

@A5rocks A5rocks May 11, 2025 •

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Alright that makes sense then. I didn't realize when this function was called. (fyi I'm unable to resolve things, so you'll have to.)

@A5rocks A5rocks left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Still not completely sure this is the right place, but this works and I'm not sure where else would be better.

Comment thread mypy/checkmember.py
t, isuper, is_classmethod, is_staticmethod, mx.self_type, original_vars=original_vars
)
if is_decorated and not is_staticmethod:
t = expand_self_type_if_needed(

@A5rocks A5rocks May 11, 2025 •

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Alright that makes sense then. I didn't realize when this function was called. (fyi I'm unable to resolve things, so you'll have to.)

@github-actions

Copy link
Copy Markdown
Contributor

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

steam.py (https://github.com/Gobot1234/steam.py)
+ steam/enums.py:322: error: Incompatible return value type (got "int", expected "Self")  [return-value]
- steam/state.py:2439: error: Argument 2 to "__get__" of "classproperty" has incompatible type "type[Awardable[int]]"; expected "type[Self]"  [arg-type]
+ steam/state.py:2439: error: Argument 2 to "__get__" of "classproperty" has incompatible type "type[Awardable[int]]"; expected "type[type[Awardable[int]]]"  [arg-type]

@JukkaL
JukkaL merged commit 6c3c4a7 into python:master Jun 13, 2025
@ilevkivskyi

Copy link
Copy Markdown
Member

Merging this broke ~everything, as is_staticmethod is not defined in that function anymore. @JukkaL or @sterliakov could you please take a look?

(As a side note it would be good to have a test that triggers that is_staticmethod check.)

@A5rocks

A5rocks commented Jun 13, 2025

Copy link
Copy Markdown
Collaborator

I would recommend adding a merge queue to make it impossible for that kind of thing to happen but unfortunately GitHub's merge queue implementation doesn't let you choose between squashing and merge commit when merging, and we need both...

@ilevkivskyi

Copy link
Copy Markdown
Member

FWIW I am going to force-merge #19293 now.

Btw yet another missing test case is something like this

class C:
    @some_trivial_deco
    def meth(self) -> Self: ...
    @classmethod
    def other_meth(cls) -> Self
        reveal_type(cls.meth)
        return cls().meth()

@sterliakov could you please add both (the one from previous comment and this one)?

@sterliakov

Copy link
Copy Markdown
Collaborator Author

Oops, thank you @ilevkivskyi, I also opened a PR to fix the merge conflict, but you were faster... I'll repurpose it for adding those tests then.

ilevkivskyi added a commit that referenced this pull request Aug 3, 2025
As requested by @ilevkivskyi in #19025

---------

Co-authored-by: Ivan Levkivskyi <levkivskyi@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

4 participants