Skip to content

Commit 4494f82

Browse files
authored
Accept lazy strings as path in APIRequestFactory and APIClient http methods (#825)
* Add failing tests * Accept lazy strings as path in APIRequestFactory and APIClient * Keep suppression comments in the right place * Remove parametrized to speed up tests
1 parent 56e621f commit 4494f82

File tree

2 files changed

+69
-13
lines changed

2 files changed

+69
-13
lines changed

rest_framework-stubs/test.pyi

Lines changed: 42 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ from django.test import testcases
1212
from django.test.client import Client as DjangoClient
1313
from django.test.client import ClientHandler
1414
from django.test.client import RequestFactory as DjangoRequestFactory
15+
from django_stubs_ext import StrOrPromise
1516
from rest_framework.authtoken.models import Token
1617
from rest_framework.request import Request
1718
from rest_framework.response import _MonkeyPatchedResponse
@@ -58,29 +59,55 @@ class APIRequestFactory(DjangoRequestFactory):
5859
renderer_classes: Any
5960
def __init__(self, enforce_csrf_checks: bool = ..., **defaults: Any) -> None: ...
6061
def request(self, **kwargs: Any) -> Request: ... # type: ignore[override]
61-
def get(self, path: str, data: _GetDataType = ..., **extra: Any) -> Request: ... # type: ignore[override]
62+
def get(self, path: StrOrPromise, data: _GetDataType = ..., **extra: Any) -> Request: ... # type: ignore[override]
6263
def post( # type: ignore[override]
63-
self, path: str, data: Any | None = ..., format: str | None = ..., content_type: str | None = ..., **extra: Any
64+
self,
65+
path: StrOrPromise,
66+
data: Any | None = ...,
67+
format: str | None = ...,
68+
content_type: str | None = ...,
69+
**extra: Any,
6470
) -> Request: ...
6571
def put( # type: ignore[override]
66-
self, path: str, data: Any | None = ..., format: str | None = ..., content_type: str | None = ..., **extra: Any
72+
self,
73+
path: StrOrPromise,
74+
data: Any | None = ...,
75+
format: str | None = ...,
76+
content_type: str | None = ...,
77+
**extra: Any,
6778
) -> Request: ...
6879
def patch( # type: ignore[override]
69-
self, path: str, data: Any | None = ..., format: str | None = ..., content_type: str | None = ..., **extra: Any
80+
self,
81+
path: StrOrPromise,
82+
data: Any | None = ...,
83+
format: str | None = ...,
84+
content_type: str | None = ...,
85+
**extra: Any,
7086
) -> Request: ...
7187
def delete( # type: ignore[override]
72-
self, path: str, data: Any | None = ..., format: str | None = ..., content_type: str | None = ..., **extra: Any
88+
self,
89+
path: StrOrPromise,
90+
data: Any | None = ...,
91+
format: str | None = ...,
92+
content_type: str | None = ...,
93+
**extra: Any,
7394
) -> Request: ...
7495
def options( # type: ignore[override]
7596
self,
76-
path: str,
97+
path: StrOrPromise,
7798
data: dict[str, str] | str | None = ...,
7899
format: str | None = ...,
79100
content_type: Any | None = ...,
80101
**extra: Any,
81102
) -> Request: ...
82103
def generic( # type: ignore[override]
83-
self, method: str, path: str, data: str = ..., content_type: str = ..., secure: bool = ..., **extra: Any
104+
self,
105+
method: str,
106+
path: StrOrPromise,
107+
data: str = ...,
108+
content_type: str = ...,
109+
secure: bool = ...,
110+
**extra: Any,
84111
) -> Request: ...
85112

86113
class ForceAuthClientHandler(ClientHandler):
@@ -93,10 +120,12 @@ class APIClient(APIRequestFactory, DjangoClient):
93120
self, user: AnonymousUser | AbstractBaseUser | None = ..., token: Token | None = ...
94121
) -> None: ...
95122
def request(self, **kwargs: Any) -> _MonkeyPatchedResponse: ... # type: ignore[override]
96-
def get(self, path: str, data: _GetDataType = ..., follow: bool = ..., **extra: Any) -> _MonkeyPatchedResponse: ... # type: ignore[override]
123+
def get( # type: ignore[override]
124+
self, path: StrOrPromise, data: _GetDataType = ..., follow: bool = ..., **extra: Any
125+
) -> _MonkeyPatchedResponse: ...
97126
def post( # type: ignore[override]
98127
self,
99-
path: str,
128+
path: StrOrPromise,
100129
data: Any | None = ...,
101130
format: str | None = ...,
102131
content_type: str | None = ...,
@@ -105,7 +134,7 @@ class APIClient(APIRequestFactory, DjangoClient):
105134
) -> _MonkeyPatchedResponse: ...
106135
def put( # type: ignore[override]
107136
self,
108-
path: str,
137+
path: StrOrPromise,
109138
data: Any | None = ...,
110139
format: str | None = ...,
111140
content_type: str | None = ...,
@@ -114,7 +143,7 @@ class APIClient(APIRequestFactory, DjangoClient):
114143
) -> _MonkeyPatchedResponse: ...
115144
def patch( # type: ignore[override]
116145
self,
117-
path: str,
146+
path: StrOrPromise,
118147
data: Any | None = ...,
119148
format: str | None = ...,
120149
content_type: str | None = ...,
@@ -123,7 +152,7 @@ class APIClient(APIRequestFactory, DjangoClient):
123152
) -> _MonkeyPatchedResponse: ...
124153
def delete( # type: ignore[override]
125154
self,
126-
path: str,
155+
path: StrOrPromise,
127156
data: Any | None = ...,
128157
format: str | None = ...,
129158
content_type: str | None = ...,
@@ -132,7 +161,7 @@ class APIClient(APIRequestFactory, DjangoClient):
132161
) -> _MonkeyPatchedResponse: ...
133162
def options( # type: ignore[override]
134163
self,
135-
path: str,
164+
path: StrOrPromise,
136165
data: dict[str, str] | str = ...,
137166
format: str | None = ...,
138167
content_type: Any | None = ...,

tests/typecheck/test_test.yml

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,30 @@
2525
reveal_type(self.client) # N: Revealed type is "django.test.client.Client"
2626
response = self.client.get('/', format="json")
2727
self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
28+
29+
- case: test_requestfactory_http_verbs
30+
main: |
31+
from django.urls import reverse_lazy
32+
from rest_framework import test, status
33+
34+
url = reverse_lazy("api:example")
35+
request_factory = test.APIRequestFactory()
36+
request_factory.get(url)
37+
request_factory.post(url)
38+
request_factory.put(url)
39+
request_factory.patch(url)
40+
request_factory.delete(url)
41+
request_factory.generic("get", url)
42+
43+
- case: test_apiclient_http_verbs
44+
main: |
45+
from django.urls import reverse_lazy
46+
from rest_framework import test, status
47+
48+
url = reverse_lazy("api:example")
49+
client = test.APIClient()
50+
client.get(url)
51+
client.post(url)
52+
client.put(url)
53+
client.patch(url)
54+
client.delete(url)

0 commit comments

Comments
 (0)