Skip to content

Commit 2632ea3

Browse files
authored
stubtest: Add support for cached_property (#17626)
Fixes #17625
1 parent 3f8c6cb commit 2632ea3

File tree

2 files changed

+103
-0
lines changed

2 files changed

+103
-0
lines changed

mypy/stubtest.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1224,6 +1224,9 @@ def _verify_readonly_property(stub: nodes.Decorator, runtime: Any) -> Iterator[s
12241224
if isinstance(runtime, property):
12251225
yield from _verify_final_method(stub.func, runtime.fget, MISSING)
12261226
return
1227+
if isinstance(runtime, functools.cached_property):
1228+
yield from _verify_final_method(stub.func, runtime.func, MISSING)
1229+
return
12271230
if inspect.isdatadescriptor(runtime):
12281231
# It's enough like a property...
12291232
return

mypy/test/teststubtest.py

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -893,6 +893,106 @@ class FineAndDandy:
893893
error=None,
894894
)
895895

896+
@collect_cases
897+
def test_cached_property(self) -> Iterator[Case]:
898+
yield Case(
899+
stub="""
900+
from functools import cached_property
901+
class Good:
902+
@cached_property
903+
def read_only_attr(self) -> int: ...
904+
@cached_property
905+
def read_only_attr2(self) -> int: ...
906+
""",
907+
runtime="""
908+
import functools as ft
909+
from functools import cached_property
910+
class Good:
911+
@cached_property
912+
def read_only_attr(self): return 1
913+
@ft.cached_property
914+
def read_only_attr2(self): return 1
915+
""",
916+
error=None,
917+
)
918+
yield Case(
919+
stub="""
920+
from functools import cached_property
921+
class Bad:
922+
@cached_property
923+
def f(self) -> int: ...
924+
""",
925+
runtime="""
926+
class Bad:
927+
def f(self) -> int: return 1
928+
""",
929+
error="Bad.f",
930+
)
931+
yield Case(
932+
stub="""
933+
from functools import cached_property
934+
class GoodCachedAttr:
935+
@cached_property
936+
def f(self) -> int: ...
937+
""",
938+
runtime="""
939+
class GoodCachedAttr:
940+
f = 1
941+
""",
942+
error=None,
943+
)
944+
yield Case(
945+
stub="""
946+
from functools import cached_property
947+
class BadCachedAttr:
948+
@cached_property
949+
def f(self) -> str: ...
950+
""",
951+
runtime="""
952+
class BadCachedAttr:
953+
f = 1
954+
""",
955+
error="BadCachedAttr.f",
956+
)
957+
yield Case(
958+
stub="""
959+
from functools import cached_property
960+
from typing import final
961+
class FinalGood:
962+
@cached_property
963+
@final
964+
def attr(self) -> int: ...
965+
""",
966+
runtime="""
967+
from functools import cached_property
968+
from typing import final
969+
class FinalGood:
970+
@cached_property
971+
@final
972+
def attr(self):
973+
return 1
974+
""",
975+
error=None,
976+
)
977+
yield Case(
978+
stub="""
979+
from functools import cached_property
980+
class FinalBad:
981+
@cached_property
982+
def attr(self) -> int: ...
983+
""",
984+
runtime="""
985+
from functools import cached_property
986+
from typing_extensions import final
987+
class FinalBad:
988+
@cached_property
989+
@final
990+
def attr(self):
991+
return 1
992+
""",
993+
error="FinalBad.attr",
994+
)
995+
896996
@collect_cases
897997
def test_var(self) -> Iterator[Case]:
898998
yield Case(stub="x1: int", runtime="x1 = 5", error=None)

0 commit comments

Comments
 (0)