diff --git a/django-stubs/db/models/functions/comparison.pyi b/django-stubs/db/models/functions/comparison.pyi index 58247e38f..68f287b49 100644 --- a/django-stubs/db/models/functions/comparison.pyi +++ b/django-stubs/db/models/functions/comparison.pyi @@ -9,10 +9,12 @@ class Cast(Func): ) -> None: ... class Coalesce(Func): ... + class Collate(Func): def __init__(self, expression: Any, collation: str) -> None: ... class Greatest(Func): ... + class JSONObject(Func): def __init__(self, **fields: Any) -> None: ... diff --git a/django-stubs/db/models/manager.pyi b/django-stubs/db/models/manager.pyi index 3ed250aaa..7dc395065 100644 --- a/django-stubs/db/models/manager.pyi +++ b/django-stubs/db/models/manager.pyi @@ -19,7 +19,9 @@ class BaseManager(QuerySet[_T]): def __init__(self) -> None: ... def deconstruct( self, - ) -> tuple[bool, str | None, str | None, tuple[Any, ...] | None, dict[str, Any] | None]: ... + ) -> tuple[ + bool, str | None, str | None, tuple[Any, ...] | None, dict[str, Any] | None + ]: ... def check(self, **kwargs: Any) -> list[Any]: ... @classmethod def from_queryset( diff --git a/django-stubs/http/cookie.pyi b/django-stubs/http/cookie.pyi index efa3fb93a..2f9214ac0 100644 --- a/django-stubs/http/cookie.pyi +++ b/django-stubs/http/cookie.pyi @@ -1,3 +1,5 @@ -from http.cookies import SimpleCookie as SimpleCookie +from http import cookies + +SimpleCookie = cookies.SimpleCookie[str] def parse_cookie(cookie: str) -> dict[str, str]: ... diff --git a/django-stubs/http/request.pyi b/django-stubs/http/request.pyi index 1b0fdd3f8..19211e86e 100644 --- a/django-stubs/http/request.pyi +++ b/django-stubs/http/request.pyi @@ -1,7 +1,6 @@ from collections.abc import Iterable, Mapping -from io import BytesIO from re import Pattern -from typing import Any, BinaryIO, overload +from typing import Any, BinaryIO, TypeVar, overload from typing_extensions import Self from django.contrib.auth.base_user import AbstractBaseUser @@ -19,7 +18,7 @@ from django.utils.datastructures import ( RAISE_ERROR: object = ... host_validation_re: Pattern[str] = ... -class UnreadablePostError(IOError): ... +class UnreadablePostError(OSError): ... class RawPostDataException(Exception): ... UploadHandlerList = ( @@ -27,14 +26,26 @@ UploadHandlerList = ( | ImmutableList[uploadhandler.FileUploadHandler] ) -class HttpHeaders(CaseInsensitiveMapping[str, str]): +T = TypeVar("T") + +class HttpHeaders(CaseInsensitiveMapping[str]): HTTP_PREFIX: str = ... UNPREFIXED_HEADERS: set[str] = ... def __init__(self, environ: Mapping[str, Any]) -> None: ... @classmethod def parse_header_name(cls, header: str) -> str | None: ... + @classmethod + def to_wsgi_name(cls, header: str) -> str: ... + @classmethod + def to_asgi_name(cls, header: str) -> str: ... + @classmethod + def to_wsgi_names(cls, headers: Mapping[str, T]) -> Mapping[str, T]: ... + @classmethod + def to_asgi_names(cls, headers: Mapping[str, T]) -> Mapping[str, T]: ... + +class MediaType: ... -class HttpRequest(BytesIO): +class HttpRequest: GET: QueryDict = ... POST: QueryDict = ... COOKIES: dict[str, str] = ... @@ -43,15 +54,13 @@ class HttpRequest(BytesIO): path: str = ... path_info: str = ... method: str | None = ... - resolver_match: ResolverMatch = ... + resolver_match: ResolverMatch | None = ... content_type: str | None = ... content_params: dict[str, str] | None = ... - user: AbstractBaseUser | AnonymousUser - site: Site - session: SessionBase - encoding: str | None = ... - upload_handlers: UploadHandlerList = ... def __init__(self) -> None: ... + @property + def accepted_types(self) -> list[MediaType]: ... + def accepts(self, media_type: str) -> bool: ... def get_host(self) -> str: ... def get_port(self) -> str: ... def get_full_path(self, force_append_slash: bool = ...) -> str: ... @@ -59,15 +68,19 @@ class HttpRequest(BytesIO): def get_signed_cookie( self, key: str, - default: Any = ..., + default: T = ..., salt: str = ..., max_age: int | None = ..., - ) -> str | None: ... + ) -> str | T: ... def get_raw_uri(self) -> str: ... def build_absolute_uri(self, location: str | None = ...) -> str: ... @property - def scheme(self) -> str | None: ... + def scheme(self) -> str: ... def is_secure(self) -> bool: ... + @property + def encoding(self) -> str: ... + @property + def upload_handlers(self) -> UploadHandlerList: ... def is_ajax(self) -> bool: ... def parse_file_upload( self, META: Mapping[str, Any], post_data: BinaryIO @@ -77,6 +90,16 @@ class HttpRequest(BytesIO): @property def body(self) -> bytes: ... def _load_post_and_files(self) -> None: ... + def close(self) -> None: ... + def read(self, *args: Any, **kwargs: Any) -> bytes: ... + def readline(self, *args: Any, **kwargs: Any) -> bytes: ... + def __iter__(self) -> Iterable[bytes]: ... + def readlines(self) -> list[bytes]: ... + + # Attributes added by commonly-used middleware + user: AbstractBaseUser | AnonymousUser + site: Site + session: SessionBase class QueryDict(MultiValueDict[str, str]): encoding: str = ... diff --git a/django-stubs/http/response.pyi b/django-stubs/http/response.pyi index 97e3a9a81..878e6529d 100644 --- a/django-stubs/http/response.pyi +++ b/django-stubs/http/response.pyi @@ -1,23 +1,28 @@ import datetime -from collections.abc import AsyncIterable, Iterable, Iterator +from collections.abc import AsyncIterable, AsyncIterator, Iterable, Iterator from io import BytesIO from json import JSONEncoder from typing import Any, overload +from typing_extensions import Never from django.core.handlers.wsgi import WSGIRequest from django.http.cookie import SimpleCookie from django.template import Context, Template from django.test.client import Client from django.urls import ResolverMatch +from django.utils.datastructures import CaseInsensitiveMapping + +class ResponseHeaders(CaseInsensitiveMapping[str]): + def pop(self, key: str, default: str | None = ...) -> str: ... + def setdefault(self, key: str, value: str) -> None: ... class BadHeaderError(ValueError): ... -class HttpResponseBase(Iterable[Any]): - status_code: int = ... - cookies: SimpleCookie[str] = ... - reason_phrase: str = ... - charset: str = ... - closed: bool = ... +class HttpResponseBase: + cookies: SimpleCookie + headers: ResponseHeaders + status_code: int + closed: bool def __init__( self, content_type: str | None = ..., @@ -25,6 +30,10 @@ class HttpResponseBase(Iterable[Any]): reason: str | None = ..., charset: str | None = ..., ) -> None: ... + @property + def reason_phrase(self) -> str: ... + @property + def charset(self) -> str: ... def serialize_headers(self) -> bytes: ... def __setitem__(self, header: str | bytes, value: str | bytes | int) -> None: ... def __delitem__(self, header: str | bytes) -> None: ... @@ -56,28 +65,30 @@ class HttpResponseBase(Iterable[Any]): ) -> None: ... def make_bytes(self, value: object) -> bytes: ... def close(self) -> None: ... - def write(self, content: str | bytes) -> None: ... def flush(self) -> None: ... - def tell(self) -> int: ... def readable(self) -> bool: ... def seekable(self) -> bool: ... def writable(self) -> bool: ... - def writelines(self, lines: Iterable[object]) -> Any: ... - def __iter__(self) -> Iterator[Any]: ... -class HttpResponse(HttpResponseBase): - content: Any +class HttpResponse(HttpResponseBase, Iterable[bytes]): csrf_cookie_set: bool redirect_chain: list[tuple[str, int]] sameorigin: bool test_server_port: str test_was_secure_request: bool xframe_options_exempt: bool - streaming: bool = ... - def __init__(self, content: object = ..., *args: Any, **kwargs: Any) -> None: ... + streaming: bool + def __init__(self, content: bytes = ..., *args: Any, **kwargs: Any) -> None: ... def serialize(self) -> bytes: ... @property - def url(self) -> str: ... + def content(self) -> bytes: ... + def __iter__(self) -> Iterator[bytes]: ... + def write(self, content: str | bytes) -> None: ... + def tell(self) -> int: ... + def getvalue(self) -> bytes: ... + def writable(self) -> bool: ... + def writelines(self, lines: Iterable[str | bytes]) -> None: ... + # Attributes assigned by monkey-patching in test client ClientHandler.__call__() wsgi_request: WSGIRequest # Attributes assigned by monkey-patching in test client Client.request() @@ -87,10 +98,9 @@ class HttpResponse(HttpResponseBase): context: Context resolver_match: ResolverMatch def json(self) -> Any: ... - def getvalue(self) -> bytes: ... -class StreamingHttpResponse(HttpResponseBase): - content: Any +class StreamingHttpResponse(HttpResponseBase, Iterable[bytes], AsyncIterable[bytes]): + streaming: bool streaming_content: Iterable[bytes] | AsyncIterable[bytes] def __init__( self, @@ -99,27 +109,25 @@ class StreamingHttpResponse(HttpResponseBase): **kwargs: Any ) -> None: ... def getvalue(self) -> bytes: ... + @property + def content(self) -> Never: ... + def __iter__(self) -> Iterator[bytes]: ... + def __aiter__(self) -> AsyncIterator[bytes]: ... class FileResponse(StreamingHttpResponse): - client: Client - context: None - file_to_stream: BytesIO | None - request: dict[str, str] - resolver_match: ResolverMatch - templates: list[Any] - wsgi_request: WSGIRequest - block_size: int = ... - as_attachment: bool = ... - filename: str = ... + block_size: int + as_attachment: bool + filename: str def __init__( self, *args: Any, as_attachment: bool = ..., filename: str = ..., **kwargs: Any ) -> None: ... def set_headers(self, filelike: BytesIO) -> None: ... - def json(self) -> dict[str, Any]: ... class HttpResponseRedirectBase(HttpResponse): allowed_schemes: list[str] = ... def __init__(self, redirect_to: str, *args: Any, **kwargs: Any) -> None: ... + @property + def url(self) -> str: ... class HttpResponseRedirect(HttpResponseRedirectBase): ... class HttpResponsePermanentRedirect(HttpResponseRedirectBase): ... diff --git a/django-stubs/test/client.pyi b/django-stubs/test/client.pyi index da5d5471b..5758239f1 100644 --- a/django-stubs/test/client.pyi +++ b/django-stubs/test/client.pyi @@ -44,7 +44,7 @@ _RequestData = Any | None class RequestFactory: json_encoder: type[JSONEncoder] defaults: dict[str, str] - cookies: SimpleCookie[str] + cookies: SimpleCookie errors: BytesIO def __init__( self, *, json_encoder: type[JSONEncoder] = ..., **defaults: Any diff --git a/django-stubs/test/testcases.pyi b/django-stubs/test/testcases.pyi index 583cb1401..89e2b7463 100644 --- a/django-stubs/test/testcases.pyi +++ b/django-stubs/test/testcases.pyi @@ -9,7 +9,7 @@ from django.core.servers.basehttp import ThreadedWSGIServer, WSGIRequestHandler from django.db import connections as connections # noqa: F401 from django.db.backends.sqlite3.base import DatabaseWrapper from django.db.models import Model -from django.db.models.query import _BaseQuerySet, ValuesQuerySet +from django.db.models.query import ValuesQuerySet, _BaseQuerySet from django.forms.fields import EmailField from django.http.response import HttpResponse, HttpResponseBase from django.template.base import Template diff --git a/django-stubs/utils/datastructures.pyi b/django-stubs/utils/datastructures.pyi index 5d701ebdc..17dca2fe9 100644 --- a/django-stubs/utils/datastructures.pyi +++ b/django-stubs/utils/datastructures.pyi @@ -76,9 +76,9 @@ class DictWrapper(dict[str, _V]): self, data: Iterable[tuple[str, _V]], func: Callable[[_V], _V], prefix: str ) -> None: ... -class CaseInsensitiveMapping(Mapping[_K, _V]): +class CaseInsensitiveMapping(Mapping[str, _V]): def __init__(self, data: Any) -> None: ... - def __getitem__(self, key: _K) -> Any: ... + def __getitem__(self, key: str) -> Any: ... def __len__(self) -> int: ... - def __iter__(self) -> Iterator[_K]: ... + def __iter__(self) -> Iterator[str]: ... def copy(self) -> Self: ...