Skip to content

Add special support for @django.cached_property needed in django-stubs #18959

New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Open
wants to merge 3 commits into
base: master
Choose a base branch
from

Conversation

sobolevn
Copy link
Member

@sobolevn sobolevn commented Apr 24, 2025

Hi!

We, in django-stubs, have a lot of usages of @cached_property decorator that is a part of django: https://docs.djangoproject.com/en/5.2/ref/utils/#django.utils.functional.cached_property

All usages of it we have to add to subtest/allowlist.txt, which is not great. In typing we reuse @functools.cached_property to have all the benefits of its inference: https://github.com/typeddjango/django-stubs/blob/ee8e8b11c37866969ff0406be20591a067dfa983/django-stubs/utils/functional.pyi#L3-L4

But, stubtest is not happy with this move: because in runtime objects have django.utils.functional.cached_property type and we see the following error:


error: django.http.response.HttpResponse.text is inconsistent, cannot reconcile @property on stub with runtime object
Stub: in file /home/runner/work/django-stubs/django-stubs/django-stubs/http/response.pyi:106
def (self: django.http.response.HttpResponse) -> builtins.str
Runtime:
<django.utils.functional.cached_property object at 0x7f7ce7704920>

So, we add all @django.utils.functional.cached_property usages to our allowlist.txt. There are LOTS of entries there: https://github.com/typeddjango/django-stubs/blob/ee8e8b11c37866969ff0406be20591a067dfa983/scripts/stubtest/allowlist.txt#L158-L425

Moreover, we have to always tell about this problem to new contributors on review :(

That's why I propose to special case this as we do with other property-likes.
I've tested locally and it works perfectly. I don't want to complicate the CI with django installation and special tests. So, I added # pragma: no cover to indicate that it is not tested.

mypy/stubtest.py Outdated
# 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)) != "<class 'django.utils.functional.cached_property'>":
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you think of using type(runtime).__name__ == "cached_property" as a heuristic? That way we're not as specific to one user.

Also out of curiosity, why can't django use @functools.cached_property directly?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also out of curiosity, why can't django use @functools.cached_property directly?

No idea 🤷

What do you think of using type(runtime).name == "cached_property" as a heuristic? That way we're not as specific to one user.

I like your idea better, because it does not call __repr__, which might have side-effects. Of course, .__name__ might also trigger some very complex cases, but they should be extrimelly rare.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why can't django use @functools.cached_property directly?

Django predates python 3.8 by many years, and probably there's little to no benefit from removing their in-house version. A lot (really a lot) of users import cached_property from Django, so they'll have to maintain an alias anyway.

@sobolevn
Copy link
Member Author

sobolevn commented May 4, 2025

I will give @JukkaL some time to re-review and will merge it in several days.

# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants