diff --git a/django-stubs/contrib/admin/options.pyi b/django-stubs/contrib/admin/options.pyi index 64cfb44a0..3434fe3fe 100644 --- a/django-stubs/contrib/admin/options.pyi +++ b/django-stubs/contrib/admin/options.pyi @@ -65,10 +65,10 @@ class _FieldOpts(_OptionalFieldOpts, total=True): _FieldsetSpec: TypeAlias = _ListOrTuple[tuple[_StrOrPromise | None, _FieldOpts]] _ListFilterT: TypeAlias = ( type[ListFilter] - | Field + | Field[Any, Any] | str - | tuple[Field | str, type[FieldListFilter]] - | list[Field | str | type[FieldListFilter]] + | tuple[Field[Any, Any] | str, type[FieldListFilter]] + | list[Field[Any, Any] | str | type[FieldListFilter]] ) # Generic type specifically for models, for use in BaseModelAdmin and subclasses @@ -119,7 +119,7 @@ class BaseModelAdmin(Generic[_ModelT]): def get_readonly_fields(self, request: HttpRequest, obj: _ModelT | None = ...) -> _ListOrTuple[str]: ... def get_prepopulated_fields(self, request: HttpRequest, obj: _ModelT | None = ...) -> dict[str, Sequence[str]]: ... def get_queryset(self, request: HttpRequest) -> QuerySet[_ModelT]: ... - def get_sortable_by(self, request: HttpRequest) -> _DisplayT: ... + def get_sortable_by(self, request: HttpRequest) -> _DisplayT[_ModelT]: ... def lookup_allowed(self, lookup: str, value: str) -> bool: ... def to_field_allowed(self, request: HttpRequest, to_field: str) -> bool: ... def has_add_permission(self, request: HttpRequest) -> bool: ... @@ -133,8 +133,8 @@ _ModelAdmin = TypeVar("_ModelAdmin", bound=ModelAdmin) _ActionCallable: TypeAlias = Callable[[_ModelAdmin, HttpRequest, QuerySet[_ModelT]], HttpResponseBase | None] class ModelAdmin(BaseModelAdmin[_ModelT]): - list_display: _DisplayT - list_display_links: _DisplayT | None + list_display: _DisplayT[_ModelT] + list_display_links: _DisplayT[_ModelT] | None list_filter: _ListOrTuple[_ListFilterT] list_select_related: bool | _ListOrTuple[str] list_per_page: int @@ -200,8 +200,8 @@ class ModelAdmin(BaseModelAdmin[_ModelT]): self, request: HttpRequest, default_choices: list[tuple[str, str]] = ... ) -> list[tuple[str, str]]: ... def get_action(self, action: Callable | str) -> tuple[Callable[..., str], str, str] | None: ... - def get_list_display(self, request: HttpRequest) -> _DisplayT: ... - def get_list_display_links(self, request: HttpRequest, list_display: _DisplayT) -> _DisplayT: ... + def get_list_display(self, request: HttpRequest) -> _DisplayT[_ModelT]: ... + def get_list_display_links(self, request: HttpRequest, list_display: _DisplayT[_ModelT]) -> _DisplayT[_ModelT]: ... def get_list_filter(self, request: HttpRequest) -> _ListOrTuple[_ListFilterT]: ... def get_list_select_related(self, request: HttpRequest) -> bool | _ListOrTuple[str]: ... def get_search_fields(self, request: HttpRequest) -> _ListOrTuple[str]: ... diff --git a/django-stubs/contrib/admin/sites.pyi b/django-stubs/contrib/admin/sites.pyi index 12cf76526..b4138e99b 100644 --- a/django-stubs/contrib/admin/sites.pyi +++ b/django-stubs/contrib/admin/sites.pyi @@ -1,6 +1,6 @@ import sys from collections.abc import Callable, Iterable -from typing import Any +from typing import Any, TypeVar from django.apps.config import AppConfig from django.contrib.admin.options import ModelAdmin @@ -24,6 +24,7 @@ else: all_sites: MutableSet[AdminSite] +_ViewType = TypeVar("_ViewType", bound=Callable[..., HttpResponse]) _ActionCallback: TypeAlias = Callable[[ModelAdmin, HttpRequest, QuerySet], TemplateResponse | None] class AlreadyRegistered(Exception): ... @@ -61,11 +62,11 @@ class AdminSite: def is_registered(self, model: type[Model]) -> bool: ... def add_action(self, action: _ActionCallback, name: str | None = ...) -> None: ... def disable_action(self, name: str) -> None: ... - def get_action(self, name: str) -> Callable: ... + def get_action(self, name: str) -> _ActionCallback: ... @property def actions(self) -> Iterable[tuple[str, _ActionCallback]]: ... def has_permission(self, request: HttpRequest) -> bool: ... - def admin_view(self, view: Callable, cacheable: bool = ...) -> Callable: ... + def admin_view(self, view: _ViewType, cacheable: bool = ...) -> _ViewType: ... def get_urls(self) -> list[URLResolver | URLPattern]: ... @property def urls(self) -> tuple[list[URLResolver | URLPattern], str, str]: ... diff --git a/django-stubs/core/cache/__init__.pyi b/django-stubs/core/cache/__init__.pyi index ed6f98eca..e1a5a8fd1 100644 --- a/django-stubs/core/cache/__init__.pyi +++ b/django-stubs/core/cache/__init__.pyi @@ -9,7 +9,7 @@ from .backends.base import InvalidCacheKey as InvalidCacheKey DEFAULT_CACHE_ALIAS: str -class CacheHandler(BaseConnectionHandler): +class CacheHandler(BaseConnectionHandler[BaseCache]): settings_name: str exception_class: type[Exception] def create_connection(self, alias: str) -> BaseCache: ... diff --git a/django-stubs/db/models/fields/json.pyi b/django-stubs/db/models/fields/json.pyi index 109ab8d3a..3da0f590b 100644 --- a/django-stubs/db/models/fields/json.pyi +++ b/django-stubs/db/models/fields/json.pyi @@ -1,6 +1,6 @@ import json from collections.abc import Callable -from typing import Any, ClassVar +from typing import Any, ClassVar, TypeVar from django.db.backends.base.base import BaseDatabaseWrapper from django.db.models import lookups @@ -14,7 +14,12 @@ from typing_extensions import Self from . import Field from .mixins import CheckFieldDefaultMixin -class JSONField(CheckFieldDefaultMixin, Field): +# __set__ value type +_ST = TypeVar("_ST", contravariant=True, default=Any) +# __get__ return type +_GT = TypeVar("_GT", covariant=True, default=Any) + +class JSONField(CheckFieldDefaultMixin, Field[_ST, _GT]): encoder: type[json.JSONEncoder] | None decoder: type[json.JSONDecoder] | None def __init__( diff --git a/django-stubs/db/models/manager.pyi b/django-stubs/db/models/manager.pyi index 63dbc52f7..d6a58029b 100644 --- a/django-stubs/db/models/manager.pyi +++ b/django-stubs/db/models/manager.pyi @@ -1,5 +1,5 @@ import datetime -from collections.abc import AsyncIterator, Collection, Iterable, Iterator, MutableMapping, Sequence +from collections.abc import AsyncIterator, Callable, Collection, Iterable, Iterator, MutableMapping, Sequence from typing import Any, Generic, NoReturn, TypeVar, overload from django.db.models.base import Model @@ -12,6 +12,7 @@ from django_stubs_ext import ValuesQuerySet _T = TypeVar("_T", bound=Model, covariant=True) class BaseManager(Generic[_T]): + cache: Callable[[], Self] # django-cacheops creation_counter: int auto_created: bool use_in_migrations: bool diff --git a/django-stubs/shortcuts.pyi b/django-stubs/shortcuts.pyi index 1e352e86b..4c4fbe4c9 100644 --- a/django-stubs/shortcuts.pyi +++ b/django-stubs/shortcuts.pyi @@ -20,15 +20,15 @@ class SupportsGetAbsoluteUrl(Protocol): @overload def redirect( - to: Callable | str | SupportsGetAbsoluteUrl, *args: Any, permanent: Literal[True], **kwargs: Any + to: Callable[..., Any] | str | SupportsGetAbsoluteUrl, *args: Any, permanent: Literal[True], **kwargs: Any ) -> HttpResponsePermanentRedirect: ... @overload def redirect( - to: Callable | str | SupportsGetAbsoluteUrl, *args: Any, permanent: Literal[False] = ..., **kwargs: Any + to: Callable[..., Any] | str | SupportsGetAbsoluteUrl, *args: Any, permanent: Literal[False] = ..., **kwargs: Any ) -> HttpResponseRedirect: ... @overload def redirect( - to: Callable | str | SupportsGetAbsoluteUrl, *args: Any, permanent: bool, **kwargs: Any + to: Callable[..., Any] | str | SupportsGetAbsoluteUrl, *args: Any, permanent: bool, **kwargs: Any ) -> HttpResponseRedirect | HttpResponsePermanentRedirect: ... _T = TypeVar("_T", bound=Model) diff --git a/django-stubs/urls/base.pyi b/django-stubs/urls/base.pyi index 2dd53f88b..e2b8dd904 100644 --- a/django-stubs/urls/base.pyi +++ b/django-stubs/urls/base.pyi @@ -1,11 +1,12 @@ from collections.abc import Callable, Sequence from typing import Any, Literal +from django.http.response import HttpResponse from django.urls.resolvers import ResolverMatch def resolve(path: str, urlconf: str | None = ...) -> ResolverMatch: ... def reverse( - viewname: Callable | str | None, + viewname: Callable[..., HttpResponse] | str | None, urlconf: str | None = ..., args: Sequence[Any] | None = ..., kwargs: dict[str, Any] | None = ..., diff --git a/django-stubs/utils/decorators.pyi b/django-stubs/utils/decorators.pyi index 40c1d8252..42177efab 100644 --- a/django-stubs/utils/decorators.pyi +++ b/django-stubs/utils/decorators.pyi @@ -1,18 +1,23 @@ from collections.abc import Callable, Iterable -from typing import TypeVar +from typing import Any, TypeVar +from django.http.response import HttpResponseBase from django.utils.deprecation import MiddlewareMixin from django.views.generic.base import View +from typing_extensions import TypeAlias -_T = TypeVar("_T", bound=View | Callable) # Any callable -_CallableType = TypeVar("_CallableType", bound=Callable) +_ViewType = TypeVar("_ViewType", bound=View | Callable[..., Any]) # Any callable +_CallableType = TypeVar("_CallableType", bound=Callable[..., Any]) +_DECORATOR: TypeAlias = Callable[..., Callable[..., HttpResponseBase] | Callable[..., Callable[..., HttpResponseBase]]] classonlymethod = classmethod -def method_decorator(decorator: Callable | Iterable[Callable], name: str = ...) -> Callable[[_T], _T]: ... -def decorator_from_middleware_with_args(middleware_class: type) -> Callable: ... -def decorator_from_middleware(middleware_class: type) -> Callable: ... -def make_middleware_decorator(middleware_class: type[MiddlewareMixin]) -> Callable: ... +def method_decorator( + decorator: _DECORATOR | Iterable[_DECORATOR], name: str = ... +) -> Callable[[_ViewType], _ViewType]: ... +def decorator_from_middleware_with_args(middleware_class: type) -> _DECORATOR: ... +def decorator_from_middleware(middleware_class: type) -> _DECORATOR: ... +def make_middleware_decorator(middleware_class: type[MiddlewareMixin]) -> _DECORATOR: ... def sync_and_async_middleware(func: _CallableType) -> _CallableType: ... def sync_only_middleware(func: _CallableType) -> _CallableType: ... def async_only_middleware(func: _CallableType) -> _CallableType: ...