11import datetime
2- from collections .abc import Awaitable , Callable , Iterable , Mapping , Sequence
3- from io import BytesIO
2+ from collections .abc import Awaitable , Callable , Iterable , Iterator , Mapping , Sequence
43from re import Pattern
54from typing import Any , BinaryIO , Literal , NoReturn , TypeAlias , TypeVar , overload , type_check_only
65
@@ -36,7 +35,7 @@ class HttpHeaders(CaseInsensitiveMapping[str]):
3635 @classmethod
3736 def to_asgi_names (cls , headers : Mapping [str , Any ]) -> dict [str , Any ]: ...
3837
39- class HttpRequest ( BytesIO ) :
38+ class HttpRequest :
4039 GET : _ImmutableQueryDict
4140 POST : _ImmutableQueryDict
4241 COOKIES : dict [str , str ]
@@ -104,7 +103,12 @@ class HttpRequest(BytesIO):
104103 def body (self ) -> bytes : ...
105104 def _load_post_and_files (self ) -> None : ...
106105 def accepts (self , media_type : str ) -> bool : ...
107- def readlines (self ) -> list [bytes ]: ... # type: ignore[override]
106+ def close (self ) -> None : ...
107+ # File-like and iterator interface, a minimal subset of BytesIO.
108+ def read (self , n : int = - 1 , / ) -> bytes : ...
109+ def readline (self , limit : int = - 1 , / ) -> bytes : ...
110+ def __iter__ (self ) -> Iterator [bytes ]: ...
111+ def readlines (self ) -> list [bytes ]: ...
108112
109113@type_check_only
110114class _MutableHttpRequest (HttpRequest ):
@@ -113,36 +117,49 @@ class _MutableHttpRequest(HttpRequest):
113117
114118_Z = TypeVar ("_Z" )
115119
116- class QueryDict (MultiValueDict [str , str ]):
120+ # mypy uses mro to pick between `__init__` and `__new__` for return types and will prefers `__init__` over `__new__`
121+ # in case of a tie. So to be able to specialize type via `__new__` (which is required for pyright to work),
122+ # we need to use an intermediary class for the `__init__` method.
123+ # See https://github.com/python/mypy/issues/17251
124+ # https://github.com/python/mypy/blob/c724a6a806655f94d0c705a7121e3d671eced96d/mypy/typeops.py#L148-L149
125+ class _QueryDictMixin :
126+ def __init__ (
127+ self ,
128+ query_string : str | bytes | None = ...,
129+ mutable : bool = ...,
130+ encoding : str | None = ...,
131+ ) -> None : ...
132+
133+ class QueryDict (_QueryDictMixin , MultiValueDict [str , str ]):
117134 _mutable : bool
118135 # We can make it mutable only by specifying `mutable=True`.
119136 # It can be done a) with kwarg and b) with pos. arg. `overload` has
120137 # some problems with args/kwargs + Literal, so two signatures are required.
121138 # ('querystring', True, [...])
122139 @overload
123- def __init__ (
124- self : QueryDict ,
140+ def __new__ (
141+ cls ,
125142 query_string : str | bytes | None ,
126143 mutable : Literal [True ],
127144 encoding : str | None = ...,
128- ) -> None : ...
145+ ) -> QueryDict : ...
129146 # ([querystring='string',] mutable=True, [...])
130147 @overload
131- def __init__ (
132- self : QueryDict ,
148+ def __new__ (
149+ cls ,
133150 * ,
134- mutable : Literal [True ],
135151 query_string : str | bytes | None = ...,
152+ mutable : Literal [True ],
136153 encoding : str | None = ...,
137- ) -> None : ...
154+ ) -> QueryDict : ...
138155 # Otherwise it's immutable
139156 @overload
140- def __init__ ( # type: ignore[misc]
141- self : _ImmutableQueryDict ,
157+ def __new__ (
158+ cls ,
142159 query_string : str | bytes | None = ...,
143- mutable : bool = ...,
160+ mutable : Literal [ False ] = ...,
144161 encoding : str | None = ...,
145- ) -> None : ...
162+ ) -> _ImmutableQueryDict : ...
146163 @classmethod
147164 def fromkeys ( # type: ignore[override]
148165 cls ,
@@ -161,11 +178,11 @@ class QueryDict(MultiValueDict[str, str]):
161178 def setlistdefault (self , key : str | bytes , default_list : list [str ] | None = ...) -> list [str ]: ...
162179 def appendlist (self , key : str | bytes , value : str | bytes ) -> None : ...
163180 # Fake signature (because *args is used in source, but it fails with more that 1 argument)
181+ @overload # type:ignore[override]
182+ def pop (self , key : str | bytes , / ) -> list [str ]: ...
164183 @overload
165- def pop (self , key : str | bytes , / ) -> str : ...
166- @overload
167- def pop (self , key : str | bytes , default : str | _Z = ..., / ) -> str | _Z : ...
168- def popitem (self ) -> tuple [str , str ]: ...
184+ def pop (self , key : str | bytes , default : str | _Z = ..., / ) -> list [str ] | _Z : ...
185+ def popitem (self ) -> tuple [str , list [str ]]: ... # type:ignore[override]
169186 def clear (self ) -> None : ...
170187 def setdefault (self , key : str | bytes , default : str | bytes | None = ...) -> str : ...
171188 def copy (self ) -> QueryDict : ...
0 commit comments