From 92cce1f944c3e179fc6ca80ce4c4ee4c6742e4c6 Mon Sep 17 00:00:00 2001 From: hauntsaninja Date: Fri, 10 Nov 2023 18:28:10 -0800 Subject: [PATCH] stubtest: special case final and deprecated We should probably lean into the type checker harder here Fixes #14950 Fixes https://github.com/python/typeshed/pull/11009#issuecomment-1805013903 --- mypy/stubtest.py | 7 +++++++ mypy/test/teststubtest.py | 19 +++++++++++++++++++ mypy/types.py | 3 +++ 3 files changed, 29 insertions(+) diff --git a/mypy/stubtest.py b/mypy/stubtest.py index e80ea4eac71f..ae410ff2ba6b 100644 --- a/mypy/stubtest.py +++ b/mypy/stubtest.py @@ -1215,6 +1215,12 @@ def _resolve_funcitem_from_decorator(dec: nodes.OverloadPart) -> nodes.FuncItem def apply_decorator_to_funcitem( decorator: nodes.Expression, func: nodes.FuncItem ) -> nodes.FuncItem | None: + if ( + isinstance(decorator, nodes.CallExpr) + and isinstance(decorator.callee, nodes.RefExpr) + and decorator.callee.fullname in mypy.types.DEPRECATED_TYPE_NAMES + ): + return func if not isinstance(decorator, nodes.RefExpr): return None if not decorator.fullname: @@ -1223,6 +1229,7 @@ def apply_decorator_to_funcitem( if ( decorator.fullname in ("builtins.staticmethod", "abc.abstractmethod") or decorator.fullname in mypy.types.OVERLOAD_NAMES + or decorator.fullname in mypy.types.FINAL_DECORATOR_NAMES ): return func if decorator.fullname == "builtins.classmethod": diff --git a/mypy/test/teststubtest.py b/mypy/test/teststubtest.py index a52d9ef5de31..0c1817202f1f 100644 --- a/mypy/test/teststubtest.py +++ b/mypy/test/teststubtest.py @@ -71,6 +71,8 @@ class Sequence(Iterable[_T_co]): ... class Tuple(Sequence[_T_co]): ... class NamedTuple(tuple[Any, ...]): ... def overload(func: _T) -> _T: ... +def deprecated(__msg: str) -> Callable[[_T], _T]: ... +def final(func: _T) -> _T: ... """ stubtest_builtins_stub = """ @@ -630,6 +632,23 @@ def f5(__b: str) -> str: ... runtime="def f5(x, /): pass", error=None, ) + yield Case( + stub=""" + from typing import deprecated, final + class Foo: + @overload + @final + def f6(self, __a: int) -> int: ... + @overload + @deprecated("evil") + def f6(self, __b: str) -> str: ... + """, + runtime=""" + class Foo: + def f6(self, x, /): pass + """, + error=None, + ) @collect_cases def test_property(self) -> Iterator[Case]: diff --git a/mypy/types.py b/mypy/types.py index 43003a9a22b6..b100cf569086 100644 --- a/mypy/types.py +++ b/mypy/types.py @@ -119,6 +119,9 @@ # Supported Annotated type names. ANNOTATED_TYPE_NAMES: Final = ("typing.Annotated", "typing_extensions.Annotated") +# Supported @deprecated type names +DEPRECATED_TYPE_NAMES: Final = ("typing.deprecated", "typing_extensions.deprecated") + # We use this constant in various places when checking `tuple` subtyping: TUPLE_LIKE_INSTANCE_NAMES: Final = ( "builtins.tuple",