Skip to content

Commit 7e68e3a

Browse files
tyrallapre-commit-ci[bot]sobolevn
authored andcommitted
PEP 702 (@deprecated): "normal" overloaded methods (python#18477)
Fixes python#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 <[email protected]>
1 parent a79aae0 commit 7e68e3a

File tree

3 files changed

+174
-2
lines changed

3 files changed

+174
-2
lines changed

mypy/checker.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -7873,7 +7873,7 @@ def warn_deprecated_overload_item(
78737873
if isinstance(item, Decorator) and isinstance(
78747874
candidate := item.func.type, CallableType
78757875
):
7876-
if selftype is not None:
7876+
if selftype is not None and not node.is_static:
78777877
candidate = bind_self(candidate, selftype)
78787878
if candidate == target:
78797879
self.warn_deprecated(item.func, context)

mypy/checkexpr.py

+8-1
Original file line numberDiff line numberDiff line change
@@ -1485,7 +1485,14 @@ def check_call_expr_with_callee_type(
14851485
)
14861486
proper_callee = get_proper_type(callee_type)
14871487
if isinstance(e.callee, (NameExpr, MemberExpr)):
1488-
self.chk.warn_deprecated_overload_item(e.callee.node, e, target=callee_type)
1488+
node = e.callee.node
1489+
if node is None and member is not None and isinstance(object_type, Instance):
1490+
if (symbol := object_type.type.get(member)) is not None:
1491+
node = symbol.node
1492+
self.chk.check_deprecated(node, e)
1493+
self.chk.warn_deprecated_overload_item(
1494+
node, e, target=callee_type, selftype=object_type
1495+
)
14891496
if isinstance(e.callee, RefExpr) and isinstance(proper_callee, CallableType):
14901497
# Cache it for find_isinstance_check()
14911498
if proper_callee.type_guard is not None:

test-data/unit/check-deprecated.test

+165
Original file line numberDiff line numberDiff line change
@@ -377,6 +377,171 @@ for i in a: # E: function __main__.A.__iter__ is deprecated: no iteration
377377
[builtins fixtures/tuple.pyi]
378378

379379

380+
[case testDeprecatedOverloadedInstanceMethods]
381+
# flags: --enable-error-code=deprecated
382+
383+
from typing import Iterator, Union
384+
from typing_extensions import deprecated, overload
385+
386+
class A:
387+
@overload
388+
@deprecated("pass `str` instead")
389+
def f(self, v: int) -> None: ...
390+
@overload
391+
def f(self, v: str) -> None: ...
392+
def f(self, v: Union[int, str]) -> None: ...
393+
394+
@overload
395+
def g(self, v: int) -> None: ...
396+
@overload
397+
@deprecated("pass `int` instead")
398+
def g(self, v: str) -> None: ...
399+
def g(self, v: Union[int, str]) -> None: ...
400+
401+
@overload
402+
def h(self, v: int) -> A: ...
403+
@overload
404+
def h(self, v: str) -> A: ...
405+
@deprecated("use `h2` instead")
406+
def h(self, v: Union[int, str]) -> A: ...
407+
408+
class B(A): ...
409+
410+
a = A()
411+
a.f(1) # E: overload def (self: __main__.A, v: builtins.int) of function __main__.A.f is deprecated: pass `str` instead
412+
a.f("x")
413+
a.g(1)
414+
a.g("x") # E: overload def (self: __main__.A, v: builtins.str) of function __main__.A.g is deprecated: pass `int` instead
415+
a.h(1) # E: function __main__.A.h is deprecated: use `h2` instead
416+
a.h("x") # E: function __main__.A.h is deprecated: use `h2` instead
417+
418+
b = B()
419+
b.f(1) # E: overload def (self: __main__.A, v: builtins.int) of function __main__.A.f is deprecated: pass `str` instead
420+
b.f("x")
421+
b.g(1)
422+
b.g("x") # E: overload def (self: __main__.A, v: builtins.str) of function __main__.A.g is deprecated: pass `int` instead
423+
b.h(1) # E: function __main__.A.h is deprecated: use `h2` instead
424+
b.h("x") # E: function __main__.A.h is deprecated: use `h2` instead
425+
426+
[builtins fixtures/tuple.pyi]
427+
428+
429+
[case testDeprecatedOverloadedClassMethods]
430+
# flags: --enable-error-code=deprecated
431+
432+
from typing import Iterator, Union
433+
from typing_extensions import deprecated, overload
434+
435+
class A:
436+
@overload
437+
@classmethod
438+
@deprecated("pass `str` instead")
439+
def f(cls, v: int) -> None: ...
440+
@overload
441+
@classmethod
442+
def f(cls, v: str) -> None: ...
443+
@classmethod
444+
def f(cls, v: Union[int, str]) -> None: ...
445+
446+
@overload
447+
@classmethod
448+
def g(cls, v: int) -> None: ...
449+
@overload
450+
@classmethod
451+
@deprecated("pass `int` instead")
452+
def g(cls, v: str) -> None: ...
453+
@classmethod
454+
def g(cls, v: Union[int, str]) -> None: ...
455+
456+
@overload
457+
@classmethod
458+
def h(cls, v: int) -> A: ...
459+
@overload
460+
@classmethod
461+
def h(cls, v: str) -> A: ...
462+
@deprecated("use `h2` instead")
463+
@classmethod
464+
def h(cls, v: Union[int, str]) -> A: ...
465+
466+
class B(A): ...
467+
468+
a = A()
469+
a.f(1) # E: overload def (cls: type[__main__.A], v: builtins.int) of function __main__.A.f is deprecated: pass `str` instead
470+
a.f("x")
471+
a.g(1)
472+
a.g("x") # E: overload def (cls: type[__main__.A], v: builtins.str) of function __main__.A.g is deprecated: pass `int` instead
473+
a.h(1) # E: function __main__.A.h is deprecated: use `h2` instead
474+
a.h("x") # E: function __main__.A.h is deprecated: use `h2` instead
475+
476+
b = B()
477+
b.f(1) # E: overload def (cls: type[__main__.A], v: builtins.int) of function __main__.A.f is deprecated: pass `str` instead
478+
b.f("x")
479+
b.g(1)
480+
b.g("x") # E: overload def (cls: type[__main__.A], v: builtins.str) of function __main__.A.g is deprecated: pass `int` instead
481+
b.h(1) # E: function __main__.A.h is deprecated: use `h2` instead
482+
b.h("x") # E: function __main__.A.h is deprecated: use `h2` instead
483+
484+
[builtins fixtures/tuple.pyi]
485+
486+
487+
[case testDeprecatedOverloadedStaticMethods]
488+
# flags: --enable-error-code=deprecated
489+
490+
from typing import Iterator, Union
491+
from typing_extensions import deprecated, overload
492+
493+
class A:
494+
@overload
495+
@staticmethod
496+
@deprecated("pass `str` instead")
497+
def f(v: int) -> None: ...
498+
@overload
499+
@staticmethod
500+
def f(v: str) -> None: ...
501+
@staticmethod
502+
def f(v: Union[int, str]) -> None: ...
503+
504+
@overload
505+
@staticmethod
506+
def g(v: int) -> None: ...
507+
@overload
508+
@staticmethod
509+
@deprecated("pass `int` instead")
510+
def g(v: str) -> None: ...
511+
@staticmethod
512+
def g(v: Union[int, str]) -> None: ...
513+
514+
@overload
515+
@staticmethod
516+
def h(v: int) -> A: ...
517+
@overload
518+
@staticmethod
519+
def h(v: str) -> A: ...
520+
@deprecated("use `h2` instead")
521+
@staticmethod
522+
def h(v: Union[int, str]) -> A: ...
523+
524+
class B(A): ...
525+
526+
a = A()
527+
a.f(1) # E: overload def (v: builtins.int) of function __main__.A.f is deprecated: pass `str` instead
528+
a.f("x")
529+
a.g(1)
530+
a.g("x") # E: overload def (v: builtins.str) of function __main__.A.g is deprecated: pass `int` instead
531+
a.h(1) # E: function __main__.A.h is deprecated: use `h2` instead
532+
a.h("x") # E: function __main__.A.h is deprecated: use `h2` instead
533+
534+
b = B()
535+
b.f(1) # E: overload def (v: builtins.int) of function __main__.A.f is deprecated: pass `str` instead
536+
b.f("x")
537+
b.g(1)
538+
b.g("x") # E: overload def (v: builtins.str) of function __main__.A.g is deprecated: pass `int` instead
539+
b.h(1) # E: function __main__.A.h is deprecated: use `h2` instead
540+
b.h("x") # E: function __main__.A.h is deprecated: use `h2` instead
541+
542+
[builtins fixtures/classmethod.pyi]
543+
544+
380545
[case testDeprecatedOverloadedSpecialMethods]
381546
# flags: --enable-error-code=deprecated
382547

0 commit comments

Comments
 (0)