mirror of
https://github.com/davidhalter/django-stubs.git
synced 2025-12-15 00:07:09 +08:00
* WIP: django_stubs_ext: monkeypatch `reveal_{type,locals}` into builtins
Fixes https://github.com/typeddjango/django-stubs/issues/590
* fixup! WIP: django_stubs_ext: monkeypatch `reveal_{type,locals}` into builtins
* fixup! fixup! WIP: django_stubs_ext: monkeypatch `reveal_{type,locals}` into builtins
* Update patch.py
Co-authored-by: Nikita Sobolev <mail@sobolevn.me>
67 lines
2.3 KiB
Python
67 lines
2.3 KiB
Python
import builtins
|
|
from typing import Any, Generic, List, Optional, Tuple, Type, TypeVar
|
|
|
|
from django import VERSION as VERSION
|
|
from django.contrib.admin import ModelAdmin
|
|
from django.contrib.admin.options import BaseModelAdmin
|
|
from django.db.models.fields import Field
|
|
from django.db.models.manager import BaseManager
|
|
from django.db.models.query import QuerySet
|
|
from django.views.generic.edit import FormMixin
|
|
|
|
_T = TypeVar("_T")
|
|
_VersionSpec = Tuple[int, int]
|
|
|
|
|
|
class MPGeneric(Generic[_T]):
|
|
"""Create a data class to hold metadata about the gneric classes needing monkeypatching.
|
|
|
|
The `version` param is optional, and a value of `None` means that the monkeypatch is
|
|
version-independent.
|
|
|
|
This is slightly overkill for our purposes, but useful for future-proofing against any
|
|
possible issues we may run into with this method.
|
|
"""
|
|
|
|
def __init__(self, cls: Type[_T], version: Optional[_VersionSpec] = None):
|
|
"""Set the data fields, basic constructor."""
|
|
self.version = version
|
|
self.cls = cls
|
|
|
|
def __repr__(self) -> str:
|
|
"""Better representation in tests and debug."""
|
|
return "<MPGeneric: {}, versions={}>".format(self.cls, self.version or "all")
|
|
|
|
|
|
# certain django classes need to be generic, but lack the __class_getitem__ dunder needed to
|
|
# annotate them: https://github.com/typeddjango/django-stubs/issues/507
|
|
# this list stores them so `monkeypatch` can fix them when called
|
|
_need_generic: List[MPGeneric[Any]] = [
|
|
MPGeneric(ModelAdmin),
|
|
MPGeneric(FormMixin),
|
|
MPGeneric(BaseModelAdmin),
|
|
MPGeneric(Field),
|
|
# These types do have native `__class_getitem__` method since django 3.1:
|
|
MPGeneric(QuerySet, (3, 1)),
|
|
MPGeneric(BaseManager, (3, 1)),
|
|
]
|
|
|
|
|
|
def monkeypatch() -> None:
|
|
"""Monkey patch django as necessary to work properly with mypy."""
|
|
|
|
# Add the __class_getitem__ dunder.
|
|
suited_for_this_version = filter(
|
|
lambda spec: spec.version is None or VERSION[:2] <= spec.version,
|
|
_need_generic,
|
|
)
|
|
for el in suited_for_this_version:
|
|
el.cls.__class_getitem__ = classmethod(lambda cls, *args, **kwargs: cls)
|
|
|
|
# Define mypy builtins, to not cause NameError during setting up Django.
|
|
builtins.reveal_type = lambda _: None
|
|
builtins.reveal_locals = lambda: None
|
|
|
|
|
|
__all__ = ["monkeypatch"]
|