Monkey-patching and extensions for django-stubs providing runtime type support for Django generic classes
npx @tessl/cli install tessl/pypi-django-stubs-ext@4.2.0Runtime extensions and monkey-patching functionality for the django-stubs type stubs package. This package enables advanced typing features for Django framework classes that cannot be implemented through static type stubs alone, providing runtime support for generic Django classes and comprehensive type annotations.
pip install django-stubs-extdjango, typing-extensionsimport django_stubs_extSpecific functionality:
from django_stubs_ext import monkeypatch
from django_stubs_ext import QuerySetAny, ValuesQuerySet, WithAnnotations, Annotations
from django_stubs_ext import AnyAttrAllowed, StrPromise, StrOrPromiseimport django_stubs_ext
# Apply monkey-patches once in your Django settings
django_stubs_ext.monkeypatch()
# Use type aliases for better type checking
from django_stubs_ext import QuerySetAny, WithAnnotations
from django.db import models
from django.db.models import Count, Case, When
from typing import TypedDict
# Example model with annotations
class User(models.Model):
name = models.CharField(max_length=100)
email = models.EmailField()
last_login = models.DateTimeField(null=True, blank=True)
class UserStats(TypedDict):
count: int
active: bool
# Type-annotated QuerySet with custom annotations
annotated_queryset: WithAnnotations[User, UserStats] = User.objects.annotate(
count=Count('id'),
active=Case(When(last_login__isnull=False, then=True), default=False)
)The package consists of three main components:
__class_getitem__ methods to Django classes that need generic type supportThe monkey-patching system is version-aware, automatically detecting the Django version at runtime and applying only the necessary patches to ensure compatibility across multiple Django versions.
Core functionality for patching Django generic classes to support type parameterization. This enables proper type checking for Django classes that don't natively support generic syntax.
def monkeypatch(
extra_classes: Optional[Iterable[type]] = None,
include_builtins: bool = True
) -> None:
"""Apply runtime monkey-patches to Django classes for generic type support."""Specialized type aliases for Django QuerySets that provide better type safety and IDE support when working with query results and values() calls.
QuerySetAny = QuerySet # Type alias for generic QuerySet with any model
ValuesQuerySet = QuerySet # Type alias for QuerySet with values() callsType-safe containers and annotations for Django model annotations, enabling proper typing of models with computed fields and aggregations.
class Annotations[_Annotations]:
"""Generic container for TypedDict-style model annotations."""
WithAnnotations = Annotated[_T, Annotations[_Annotations]]
"""Annotated type combining Django models with their annotation types."""Type aliases for Django's Promise-based string handling system, providing proper type safety for lazy string evaluation and internationalization.
StrPromise = Promise # Django Promise string type
StrOrPromise = Union[str, StrPromise] # Union of str and Promise typesProtocol definitions for flexible attribute access and typed base classes for Django components like Model.Meta and database routers.
class AnyAttrAllowed(Protocol):
"""Protocol for classes allowing arbitrary attribute access."""
def __getattr__(self, item: str) -> Any: ...
def __setattr__(self, item: str, value: Any) -> None: ...from typing import Any, Generic, Iterable, Mapping, Optional, Protocol, TypeVar, Union
from typing_extensions import Annotated
from django.db.models.base import Model
_T = TypeVar("_T", bound=Model)
_Annotations = TypeVar("_Annotations", covariant=True, bound=Mapping[str, Any])