Skip to content
Merged
12 changes: 11 additions & 1 deletion mypy/checkexpr.py
Original file line number Diff line number Diff line change
Expand Up @@ -1485,7 +1485,17 @@ def check_call_expr_with_callee_type(
)
proper_callee = get_proper_type(callee_type)
if isinstance(e.callee, (NameExpr, MemberExpr)):
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)
and ((symbol := object_type.type.names.get(member)) is not None)
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
(node is None)
and (member is not None)
and isinstance(object_type, Instance)
and ((symbol := object_type.type.names.get(member)) is not None)
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
Collaborator Author

@tyralla tyralla Jan 16, 2025

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
Collaborator Author

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.

):
node = symbol.node
self.chk.warn_deprecated_overload_item(
node, e, target=callee_type, selftype=object_type
)
if isinstance(e.callee, RefExpr) and isinstance(proper_callee, CallableType):
# Cache it for find_isinstance_check()
if proper_callee.type_guard is not None:
Expand Down
39 changes: 39 additions & 0 deletions test-data/unit/check-deprecated.test
Original file line number Diff line number Diff line change
Expand Up @@ -377,6 +377,45 @@ for i in a: # E: function __main__.A.__iter__ is deprecated: no iteration
[builtins fixtures/tuple.pyi]


[case testDeprecatedOverloadedMethods]
# flags: --enable-error-code=deprecated

from typing import Iterator, Union
from typing_extensions import deprecated, overload

class A:
@overload
@deprecated("pass `str` instead")
def f(self, v: int) -> None: ...
@overload
def f(self, v: str) -> None: ...
def f(self, v: Union[int, str]) -> None: ...

@overload
def g(self, v: int) -> None: ...
@overload
@deprecated("pass `int` instead")
def g(self, v: str) -> None: ...
def g(self, v: Union[int, str]) -> None: ...

@overload
def h(self, v: int) -> A: ...
@overload
def h(self, v: str) -> A: ...
@deprecated("use `h2` instead")
def h(self, v: Union[int, str]) -> A: ...

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
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
Collaborator Author

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
Collaborator Author

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).

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

[builtins fixtures/tuple.pyi]


[case testDeprecatedOverloadedSpecialMethods]
# flags: --enable-error-code=deprecated

Expand Down
Loading