From 0602811ed4393fbd4be8d49e64f307759b4eea6a Mon Sep 17 00:00:00 2001 From: sobolevn Date: Thu, 24 Apr 2025 10:43:52 +0300 Subject: [PATCH 1/3] Add special support for `@django.cached_property` needed in `django-stubs` --- mypy/stubtest.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/mypy/stubtest.py b/mypy/stubtest.py index ab29d9dca4b8..f4b806be854b 100644 --- a/mypy/stubtest.py +++ b/mypy/stubtest.py @@ -1256,6 +1256,21 @@ def verify_paramspecexpr( return +def _is_django_cached_property(runtime: Any) -> bool: # pragma: no cover + # This is a special case for + # https://docs.djangoproject.com/en/5.2/ref/utils/#django.utils.functional.cached_property + # This is needed in `django-stubs` project: + # https://github.com/typeddjango/django-stubs + try: + from django.utils.functional import cached_property # type: ignore[import-not-found] + except Exception: + return False + try: + return isinstance(runtime, cached_property) and bool(runtime.func) + except Exception: + return False + + def _verify_readonly_property(stub: nodes.Decorator, runtime: Any) -> Iterator[str]: assert stub.func.is_property if isinstance(runtime, property): @@ -1264,6 +1279,9 @@ def _verify_readonly_property(stub: nodes.Decorator, runtime: Any) -> Iterator[s if isinstance(runtime, functools.cached_property): yield from _verify_final_method(stub.func, runtime.func, MISSING) return + if _is_django_cached_property(runtime): + yield from _verify_final_method(stub.func, runtime.func, MISSING) + return if inspect.isdatadescriptor(runtime): # It's enough like a property... return From da4fefec5d71ce36ae082e0d46484e23571ed4dd Mon Sep 17 00:00:00 2001 From: sobolevn Date: Fri, 2 May 2025 20:36:23 +0300 Subject: [PATCH 2/3] Address review, use `repr` instead --- mypy/stubtest.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/mypy/stubtest.py b/mypy/stubtest.py index f4b806be854b..e98c1d39d546 100644 --- a/mypy/stubtest.py +++ b/mypy/stubtest.py @@ -1261,12 +1261,10 @@ def _is_django_cached_property(runtime: Any) -> bool: # pragma: no cover # https://docs.djangoproject.com/en/5.2/ref/utils/#django.utils.functional.cached_property # This is needed in `django-stubs` project: # https://github.com/typeddjango/django-stubs - try: - from django.utils.functional import cached_property # type: ignore[import-not-found] - except Exception: + if repr(type(runtime)) != "": return False try: - return isinstance(runtime, cached_property) and bool(runtime.func) + return bool(runtime.func) except Exception: return False From 736669272a74328b7c7be80010102a4391c9042f Mon Sep 17 00:00:00 2001 From: sobolevn Date: Sun, 4 May 2025 19:23:33 +0300 Subject: [PATCH 3/3] Update stubtest.py --- mypy/stubtest.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mypy/stubtest.py b/mypy/stubtest.py index e98c1d39d546..3fe28d416727 100644 --- a/mypy/stubtest.py +++ b/mypy/stubtest.py @@ -1261,7 +1261,7 @@ def _is_django_cached_property(runtime: Any) -> bool: # pragma: no cover # https://docs.djangoproject.com/en/5.2/ref/utils/#django.utils.functional.cached_property # This is needed in `django-stubs` project: # https://github.com/typeddjango/django-stubs - if repr(type(runtime)) != "": + if type(runtime).__name__ != "cached_property": return False try: return bool(runtime.func)