Skip to content

Commit 1efa5da

Browse files
committed
address review comments, extract follow flag checks in a separate test case
Signed-off-by: Oleg Hoefling <[email protected]>
1 parent 44b7999 commit 1efa5da

File tree

2 files changed

+102
-9
lines changed

2 files changed

+102
-9
lines changed

django-stubs/test/client.pyi

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import sys
21
from io import BytesIO
32
from json import JSONEncoder
43
from types import TracebackType
@@ -32,11 +31,7 @@ from django.http.response import HttpResponseBase
3231
from django.template.base import Template
3332
from django.test.utils import ContextList
3433
from django.urls import ResolverMatch
35-
36-
if sys.version_info >= (3, 8):
37-
from typing import Literal
38-
else:
39-
from typing_extensions import Literal
34+
from typing_extensions import Literal
4035

4136
BOUNDARY: str = ...
4237
MULTIPART_CONTENT: str = ...
@@ -176,6 +171,10 @@ class Client(ClientMixin, _RequestFactory[_MonkeyPatchedWSGIResponse]):
176171
def get(
177172
self, path: str, data: Any = ..., follow: Literal[True] = ..., secure: bool = ..., **extra: Any
178173
) -> _MonkeyPatchedWSGIResponseRedirect: ...
174+
@overload
175+
def get(
176+
self, path: str, data: Any = ..., follow: bool = ..., secure: bool = ..., **extra: Any
177+
) -> _MonkeyPatchedWSGIResponse: ...
179178
@overload # type: ignore
180179
def post(
181180
self,
@@ -196,6 +195,10 @@ class Client(ClientMixin, _RequestFactory[_MonkeyPatchedWSGIResponse]):
196195
secure: bool = ...,
197196
**extra: Any
198197
) -> _MonkeyPatchedWSGIResponseRedirect: ...
198+
@overload
199+
def post(
200+
self, path: str, data: Any = ..., content_type: str = ..., follow: bool = ..., secure: bool = ..., **extra: Any
201+
) -> _MonkeyPatchedWSGIResponse: ...
199202
@overload # type: ignore
200203
def head(
201204
self, path: str, data: Any = ..., follow: Literal[False] = ..., secure: bool = ..., **extra: Any
@@ -204,6 +207,10 @@ class Client(ClientMixin, _RequestFactory[_MonkeyPatchedWSGIResponse]):
204207
def head(
205208
self, path: str, data: Any = ..., follow: Literal[True] = ..., secure: bool = ..., **extra: Any
206209
) -> _MonkeyPatchedWSGIResponseRedirect: ...
210+
@overload
211+
def head(
212+
self, path: str, data: Any = ..., follow: bool = ..., secure: bool = ..., **extra: Any
213+
) -> _MonkeyPatchedWSGIResponse: ...
207214
@overload # type: ignore
208215
def trace(
209216
self, path: str, data: Any = ..., follow: Literal[False] = ..., secure: bool = ..., **extra: Any
@@ -212,6 +219,10 @@ class Client(ClientMixin, _RequestFactory[_MonkeyPatchedWSGIResponse]):
212219
def trace(
213220
self, path: str, data: Any = ..., follow: Literal[True] = ..., secure: bool = ..., **extra: Any
214221
) -> _MonkeyPatchedWSGIResponseRedirect: ...
222+
@overload
223+
def trace(
224+
self, path: str, data: Any = ..., follow: bool = ..., secure: bool = ..., **extra: Any
225+
) -> _MonkeyPatchedWSGIResponse: ...
215226
@overload # type: ignore
216227
def put(
217228
self,
@@ -232,6 +243,10 @@ class Client(ClientMixin, _RequestFactory[_MonkeyPatchedWSGIResponse]):
232243
secure: bool = ...,
233244
**extra: Any
234245
) -> _MonkeyPatchedWSGIResponseRedirect: ...
246+
@overload
247+
def put(
248+
self, path: str, data: Any = ..., content_type: str = ..., follow: bool = ..., secure: bool = ..., **extra: Any
249+
) -> _MonkeyPatchedWSGIResponse: ...
235250
@overload # type: ignore
236251
def patch(
237252
self,
@@ -252,6 +267,10 @@ class Client(ClientMixin, _RequestFactory[_MonkeyPatchedWSGIResponse]):
252267
secure: bool = ...,
253268
**extra: Any
254269
) -> _MonkeyPatchedWSGIResponseRedirect: ...
270+
@overload
271+
def patch(
272+
self, path: str, data: Any = ..., content_type: str = ..., follow: bool = ..., secure: bool = ..., **extra: Any
273+
) -> _MonkeyPatchedWSGIResponse: ...
255274
@overload # type: ignore
256275
def delete(
257276
self,
@@ -272,6 +291,10 @@ class Client(ClientMixin, _RequestFactory[_MonkeyPatchedWSGIResponse]):
272291
secure: bool = ...,
273292
**extra: Any
274293
) -> _MonkeyPatchedWSGIResponseRedirect: ...
294+
@overload
295+
def delete(
296+
self, path: str, data: Any = ..., content_type: str = ..., follow: bool = ..., secure: bool = ..., **extra: Any
297+
) -> _MonkeyPatchedWSGIResponse: ...
275298

276299
class AsyncClient(ClientMixin, _AsyncRequestFactory[Awaitable[_MonkeyPatchedASGIResponse]]):
277300
handler: AsyncClientHandler

tests/typecheck/test/test_client.yml

Lines changed: 73 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,7 @@
99
reveal_type(response.client) # N: Revealed type is "django.test.client.Client"
1010
reveal_type(response.context) # N: Revealed type is "Union[django.test.utils.ContextList, builtins.dict[builtins.str, Any]]"
1111
reveal_type(response.content) # N: Revealed type is "builtins.bytes"
12-
response.redirect_chain # E: "_MonkeyPatchedWSGIResponse" has no attribute "redirect_chain"
1312
response.json()
14-
redirected_response = client.get('foo', follow=True)
15-
reveal_type(redirected_response.redirect_chain) # N: Revealed type is "builtins.list[Tuple[builtins.str, builtins.int]]"
1613
- case: async_client_methods
1714
main: |
1815
from django.test.client import AsyncClient
@@ -37,3 +34,76 @@
3734
async_factory = AsyncRequestFactory()
3835
async_request = async_factory.get('foo')
3936
reveal_type(async_request) # N: Revealed type is "django.core.handlers.asgi.ASGIRequest"
37+
- case: client_follow_flag
38+
main: |
39+
from django.test.client import Client
40+
client = Client()
41+
response = client.get('foo')
42+
response.redirect_chain # E: "_MonkeyPatchedWSGIResponse" has no attribute "redirect_chain"
43+
response = client.get('foo', follow=False)
44+
response.redirect_chain # E: "_MonkeyPatchedWSGIResponse" has no attribute "redirect_chain"
45+
response = client.get('foo', follow=True)
46+
reveal_type(response.redirect_chain) # N: Revealed type is "builtins.list[Tuple[builtins.str, builtins.int]]"
47+
x: bool
48+
response = client.get('foo', follow=x)
49+
response.redirect_chain # E: "_MonkeyPatchedWSGIResponse" has no attribute "redirect_chain"
50+
51+
response = client.post('foo')
52+
response.redirect_chain # E: "_MonkeyPatchedWSGIResponse" has no attribute "redirect_chain"
53+
response = client.post('foo', follow=False)
54+
response.redirect_chain # E: "_MonkeyPatchedWSGIResponse" has no attribute "redirect_chain"
55+
response = client.post('foo', follow=True)
56+
reveal_type(response.redirect_chain) # N: Revealed type is "builtins.list[Tuple[builtins.str, builtins.int]]"
57+
x: bool
58+
response = client.post('foo', follow=x)
59+
response.redirect_chain # E: "_MonkeyPatchedWSGIResponse" has no attribute "redirect_chain"
60+
61+
response = client.head('foo')
62+
response.redirect_chain # E: "_MonkeyPatchedWSGIResponse" has no attribute "redirect_chain"
63+
response = client.head('foo', follow=False)
64+
response.redirect_chain # E: "_MonkeyPatchedWSGIResponse" has no attribute "redirect_chain"
65+
response = client.head('foo', follow=True)
66+
reveal_type(response.redirect_chain) # N: Revealed type is "builtins.list[Tuple[builtins.str, builtins.int]]"
67+
x: bool
68+
response = client.head('foo', follow=x)
69+
response.redirect_chain # E: "_MonkeyPatchedWSGIResponse" has no attribute "redirect_chain"
70+
71+
response = client.trace('foo')
72+
response.redirect_chain # E: "_MonkeyPatchedWSGIResponse" has no attribute "redirect_chain"
73+
response = client.trace('foo', follow=False)
74+
response.redirect_chain # E: "_MonkeyPatchedWSGIResponse" has no attribute "redirect_chain"
75+
response = client.trace('foo', follow=True)
76+
reveal_type(response.redirect_chain) # N: Revealed type is "builtins.list[Tuple[builtins.str, builtins.int]]"
77+
x: bool
78+
response = client.trace('foo', follow=x)
79+
response.redirect_chain # E: "_MonkeyPatchedWSGIResponse" has no attribute "redirect_chain"
80+
81+
response = client.put('foo')
82+
response.redirect_chain # E: "_MonkeyPatchedWSGIResponse" has no attribute "redirect_chain"
83+
response = client.put('foo', follow=False)
84+
response.redirect_chain # E: "_MonkeyPatchedWSGIResponse" has no attribute "redirect_chain"
85+
response = client.put('foo', follow=True)
86+
reveal_type(response.redirect_chain) # N: Revealed type is "builtins.list[Tuple[builtins.str, builtins.int]]"
87+
x: bool
88+
response = client.put('foo', follow=x)
89+
response.redirect_chain # E: "_MonkeyPatchedWSGIResponse" has no attribute "redirect_chain"
90+
91+
response = client.patch('foo')
92+
response.redirect_chain # E: "_MonkeyPatchedWSGIResponse" has no attribute "redirect_chain"
93+
response = client.patch('foo', follow=False)
94+
response.redirect_chain # E: "_MonkeyPatchedWSGIResponse" has no attribute "redirect_chain"
95+
response = client.patch('foo', follow=True)
96+
reveal_type(response.redirect_chain) # N: Revealed type is "builtins.list[Tuple[builtins.str, builtins.int]]"
97+
x: bool
98+
response = client.patch('foo', follow=x)
99+
response.redirect_chain # E: "_MonkeyPatchedWSGIResponse" has no attribute "redirect_chain"
100+
101+
response = client.delete('foo')
102+
response.redirect_chain # E: "_MonkeyPatchedWSGIResponse" has no attribute "redirect_chain"
103+
response = client.delete('foo', follow=False)
104+
response.redirect_chain # E: "_MonkeyPatchedWSGIResponse" has no attribute "redirect_chain"
105+
response = client.delete('foo', follow=True)
106+
reveal_type(response.redirect_chain) # N: Revealed type is "builtins.list[Tuple[builtins.str, builtins.int]]"
107+
x: bool
108+
response = client.delete('foo', follow=x)
109+
response.redirect_chain # E: "_MonkeyPatchedWSGIResponse" has no attribute "redirect_chain"

0 commit comments

Comments
 (0)