Monkey-patching and extensions for django-stubs providing runtime type support for Django generic classes
—
The core functionality of django-stubs-ext that dynamically adds generic type support to Django classes at runtime. This system enables proper type parameterization for Django classes that don't natively support the __class_getitem__ method.
Applies runtime monkey-patches to Django classes for generic type support. This function should be called once in your Django application settings.
def monkeypatch(
extra_classes: Optional[Iterable[type]] = None,
include_builtins: bool = True
) -> None:
"""
Monkey patch Django as necessary to work properly with mypy.
Parameters:
- extra_classes: Optional iterable of additional classes to patch
- include_builtins: Whether to add reveal_type and reveal_locals helpers
Returns:
None
"""Basic usage in Django settings:
# In your Django settings file
import django_stubs_ext
django_stubs_ext.monkeypatch()With additional classes:
import django_stubs_ext
from my_app.models import CustomModel
# Patch additional classes
django_stubs_ext.monkeypatch(extra_classes=[CustomModel])Without mypy helpers:
import django_stubs_ext
# Skip adding reveal_type and reveal_locals to builtins
django_stubs_ext.monkeypatch(include_builtins=False)The following Django classes are automatically patched when appropriate for the detected Django version:
django.contrib.admin.ModelAdmindjango.views.generic.detail.SingleObjectMixindjango.views.generic.edit.FormMixindjango.views.generic.edit.DeletionMixindjango.views.generic.list.MultipleObjectMixindjango.contrib.admin.options.BaseModelAdmindjango.db.models.fields.Fielddjango.core.paginator.Paginatordjango.forms.formsets.BaseFormSetdjango.forms.models.BaseModelFormdjango.forms.models.BaseModelFormSetdjango.contrib.syndication.views.Feeddjango.contrib.sitemaps.Sitemapdjango.contrib.messages.views.SuccessMessageMixindjango.core.files.utils.FileProxyMixindjango.db.models.lookups.Lookupdjango.utils.connection.BaseConnectionHandlerdjango.db.models.expressions.ExpressionWrapperdjango.db.models.query.QuerySet (Django ≤ 3.1)django.db.models.manager.BaseManager (Django ≤ 3.1)django.db.models.fields.related.ForeignKey (Django ≤ 4.1)The monkey-patching system automatically detects your Django version and only applies patches needed for your specific version:
from django import VERSION
# Only patch classes that need it for the current Django version
suited_for_this_version = filter(
lambda spec: spec.version is None or VERSION[:2] <= spec.version,
_need_generic,
)When include_builtins=True (default), the following helpers are added to Python's builtins:
def reveal_type(obj: Any) -> None:
"""Mypy helper function for type inspection (no-op at runtime)."""
def reveal_locals() -> None:
"""Mypy helper function for local variable inspection (no-op at runtime)."""from typing import Any, Generic, Iterable, List, Optional, Tuple, Type, TypeVar
_T = TypeVar("_T")
_VersionSpec = Tuple[int, int]
class MPGeneric(Generic[_T]):
"""
Metadata container for generic classes needing monkeypatching.
The version param is optional, and None means version-independent patching.
"""
def __init__(self, cls: Type[_T], version: Optional[_VersionSpec] = None) -> None:
"""Set the data fields, basic constructor."""
def __repr__(self) -> str:
"""Better representation in tests and debug."""Install with Tessl CLI
npx tessl i tessl/pypi-django-stubs-ext