Skip to content

Commit 11166b7

Browse files
authored
[stubgen] Add @functools.cached_property support (#14981)
Closes #14980
1 parent 5005428 commit 11166b7

File tree

2 files changed

+67
-0
lines changed

2 files changed

+67
-0
lines changed

mypy/stubgen.py

+11
Original file line numberDiff line numberDiff line change
@@ -849,6 +849,9 @@ def process_name_expr_decorator(self, expr: NameExpr, context: Decorator) -> tup
849849
self.add_decorator("property")
850850
self.add_decorator("abc.abstractmethod")
851851
is_abstract = True
852+
elif self.refers_to_fullname(name, "functools.cached_property"):
853+
self.import_tracker.require_name(name)
854+
self.add_decorator(name)
852855
elif self.refers_to_fullname(name, OVERLOAD_NAMES):
853856
self.add_decorator(name)
854857
self.add_typing_import("overload")
@@ -894,6 +897,14 @@ def process_member_expr_decorator(
894897
self.import_tracker.require_name(expr.expr.name)
895898
self.add_decorator(f"{expr.expr.name}.{expr.name}")
896899
is_abstract = True
900+
elif expr.name == "cached_property" and isinstance(expr.expr, NameExpr):
901+
explicit_name = expr.expr.name
902+
reverse = self.import_tracker.reverse_alias.get(explicit_name)
903+
if reverse == "functools" or (reverse is None and explicit_name == "functools"):
904+
if reverse is not None:
905+
self.import_tracker.add_import(reverse, alias=explicit_name)
906+
self.import_tracker.require_name(explicit_name)
907+
self.add_decorator(f"{explicit_name}.{expr.name}")
897908
elif expr.name == "coroutine":
898909
if (
899910
isinstance(expr.expr, MemberExpr)

test-data/unit/stubgen.test

+56
Original file line numberDiff line numberDiff line change
@@ -319,6 +319,62 @@ class A:
319319
def f(self, x) -> None: ...
320320
def h(self) -> None: ...
321321

322+
[case testFunctoolsCachedProperty]
323+
import functools
324+
325+
class A:
326+
@functools.cached_property
327+
def x(self):
328+
return 'x'
329+
[out]
330+
import functools
331+
332+
class A:
333+
@functools.cached_property
334+
def x(self): ...
335+
336+
[case testFunctoolsCachedPropertyAlias]
337+
import functools as ft
338+
339+
class A:
340+
@ft.cached_property
341+
def x(self):
342+
return 'x'
343+
[out]
344+
import functools as ft
345+
346+
class A:
347+
@ft.cached_property
348+
def x(self): ...
349+
350+
[case testCachedProperty]
351+
from functools import cached_property
352+
353+
class A:
354+
@cached_property
355+
def x(self):
356+
return 'x'
357+
[out]
358+
from functools import cached_property
359+
360+
class A:
361+
@cached_property
362+
def x(self): ...
363+
364+
[case testCachedPropertyAlias]
365+
from functools import cached_property as cp
366+
367+
class A:
368+
@cp
369+
def x(self):
370+
return 'x'
371+
[out]
372+
from functools import cached_property as cp
373+
374+
class A:
375+
@cp
376+
def x(self): ...
377+
322378
[case testStaticMethod]
323379
class A:
324380
@staticmethod

0 commit comments

Comments
 (0)