Skip to content

PEP 702 (@deprecated): "normal" overloaded methods - #18477

Merged
sobolevn merged 12 commits into
python:masterfrom
tyralla:narrowing/overloaded_normal_methods
Jan 28, 2025
Merged

PEP 702 (@deprecated): "normal" overloaded methods#18477
sobolevn merged 12 commits into
python:masterfrom
tyralla:narrowing/overloaded_normal_methods

Conversation

@tyralla

Copy link
Copy Markdown
Collaborator

Fixes#18474

It seems I covered overloaded functions, descriptors, and special methods so far but completely forgot about "normal" methods (thanks to @sobolevn for pointing this out). This addition should do the trick.

tyrallaand others added 2 commits January 15, 2025 21:38
Fixespython#18474
It seems I covered overloaded functions, descriptors, and special methods so far but completely forgot about "normal" methods (thanks to @sobolevn for pointing this out). This addition should do the trick.
@github-actions

This comment has been minimized.

@sobolevnsobolevn left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thanks! What about @staticmethod and @classmethod?

Comment threadmypy/checkexpr.py Outdated
Comment on lines +1490 to +1493
(node is None)
and (member is not None)
and isinstance(object_type, Instance)
and ((symbol := object_type.type.names.get(member)) is not None)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
(nodeisNone)
and(memberisnotNone)
andisinstance(object_type, Instance)
and ((symbol:=object_type.type.names.get(member)) isnotNone)
nodeisNone
andmemberisnotNone
andisinstance(object_type, Instance)
and (symbol:=object_type.type.names.get(member)) isnotNone

@tyrallatyrallaJan 16, 2025

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

I will have a look at it later.

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

It became a one-liner followed by a loop.

@tyralla

Copy link
Copy Markdown
CollaboratorAuthor

Inheritance is also an issue: If the (overloaded) function is defined by a base class of object_type, object_type.type.names.get(member) cannot work.

The base class is not directly available. Going through the MRO might be necessary (at least for static methods).

…ods' into narrowing/overloaded_normal_methods
# Conflicts:
#	mypy/checkexpr.py
@tyralla

Copy link
Copy Markdown
CollaboratorAuthor

@sobolevn: classmethod already worked, staticmethod not (needed to skip bind_self). Inheritance now also works. Searching through the MRO makes it even nastier, in my opinion, but I found no other place where all information is directly available.

@github-actions

This comment has been minimized.

@tyralla
tyralla requested a review from sobolevnJanuary 17, 2025 17:53
Comment threadtest-data/unit/check-deprecated.test Outdated
Comment threadtest-data/unit/check-deprecated.test
@github-actions

This comment has been minimized.

@tyralla
tyralla requested a review from sobolevnJanuary 19, 2025 06:54

@sobolevnsobolevn left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thanks! Just two minor nitpicks :)

Comment threadmypy/checker.py Outdated
Comment threadmypy/checkexpr.py Outdated

a = A()
a.f(1) # E: overload def (self: __main__.A, v: builtins.int) of function __main__.A.f is deprecated: pass `str` instead
a.f("x")

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I would also test this case:

Suggested change
a.f("x")
a.f("x")
int_or_str: Union[int, str]
a.f(int_or_str)

It should not raise if all is good.

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

It does not raise a warning, but why do you think it should not?

(There is not even a warning for a.h, where the implementation is marked as deprecated, which is inconsistent with how functions are handled.)

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

(There is not even a warning for a.h, where the implementation is marked as deprecated, which is inconsistent with how functions are handled.)

I made it consistent in c95f936. However, I added the in my opinion missing warnings to the test case, to prevent us from merging this too early by accident. I am curious to hear why you think the current behaviour is correct. (regarding int_or_str).

tyrallaand others added 3 commits January 19, 2025 21:40
Co-authored-by: sobolevn <mail@sobolevn.me>
Co-authored-by: sobolevn <mail@sobolevn.me>
@github-actions

This comment has been minimized.

…n analysing "normal" methods (like we do when in other cases).
@github-actions

This comment has been minimized.

@tyralla
tyralla requested a review from sobolevnJanuary 20, 2025 06:09

@sobolevnsobolevn left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

There's a failing test now, please take a look. From the brief looks it is related to the Union type change.

It is unspecified in https://typing.readthedocs.io/en/latest/spec/directives.html#deprecated so we can ping @JelleZijlstra to see if that is correct.

@tyralla

Copy link
Copy Markdown
CollaboratorAuthor

Yes, the test now fails intentionally (as written somewhere above). I will wait for Jelle's response and adjust either warn_deprecated_overload_item or the TestDeprecatedOverloadedInstanceMethods test case afterwards

@hauntsaninja

hauntsaninja commented Jan 26, 2025

Copy link
Copy Markdown
Collaborator

I think it would make sense to issue the warning for the union, since that's the "sound" thing to do. I also checked against pyanalyze and pyright (since they were the reference impl's for PEP 702) and both of them issue a warning. pyanalyze is by Jelle, so that's probably his opinion on this

(If we do this, we should also add a test case for overloaded functions — mypy doesn't currently complain about passing a union that matches a deprecated overload and whatever we decide to do, we should be consistent)

@JelleZijlstra

Copy link
Copy Markdown
Member

Just so I understand correctly, the question is about whether code like this should warn about the deprecation:

from typing import overload
from warnings import deprecated
@overload
@deprecated("use str")
def f(x: int) -> str: ...
@overload
def f(x: str) -> str: ...
def f(x: int | str) -> str:
return str(x)
def caller(x: int | str):
f(x)

And my answer is yes (as Shantanu surmised above). My rule of thumb is: if there would be an error if the deprecation was carried out (i.e., the int overload was removed), then there should be a deprecation warning now.

@tyralla

Copy link
Copy Markdown
CollaboratorAuthor

Thank you very much for sharing your opinions on this. I will adjust warn_deprecated_overload_item tomorrow and add corresponding test cases for overloaded functions and descriptors.

@github-actions

This comment has been minimized.

@tyralla

Copy link
Copy Markdown
CollaboratorAuthor

Hmm, things are a little different (and eventually more complicated) than I expected. I have to study the responses of check_overload_call in more detail to (hopefully) cover all possible cases. I removed the int_or_str tests so that we do not mix-up things and the current state can be merged (according the the first review) as is (and eventually be cherry-picked into Mypy 1.15?).

I hope to propose a fix for Unions in the next few days.

Comment threadmypy/checkexpr.py Outdated
self.chk.warn_deprecated_overload_item(e.callee.node, e, target=callee_type)
node = e.callee.node
if node is None and member is not None and isinstance(object_type, Instance):
for base in object_type.type.mro:

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.

nit: I think we can use object_type.type.get(member)

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

You're right, I adjusted it.

@github-actions

Copy link
Copy Markdown
Contributor

According to mypy_primer, this change doesn't affect type check results on a corpus of open source code. ✅

@sobolevnsobolevn left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thank you! Let's continue the Union work in the next PR.

@sobolevn
sobolevn merged commit 93d1ce4 into python:masterJan 28, 2025
x612skm pushed a commit to x612skm/mypy-dev that referenced this pull request Feb 24, 2025
Fixespython#18474
It seems I covered overloaded functions, descriptors, and special
methods so far but completely forgot about "normal" methods (thanks to
@sobolevn for pointing this out). This addition should do the trick.
---------
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: sobolevn <mail@sobolevn.me>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

topic-overloadstopic-pep-702PEP 702, @deprecated

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Overloaded deprecated method use is not reported

5 participants

@tyralla@hauntsaninja@JelleZijlstra@sobolevn@cdce8p