Skip to content

Commit 3e12bf3

Browse files
committed
Improves some types in app.pyi based on review
1 parent 0968386 commit 3e12bf3

1 file changed

Lines changed: 51 additions & 33 deletions

File tree

stubs/WebTest/webtest/app.pyi

Lines changed: 51 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,27 @@
11
import json
2-
from _typeshed.wsgi import WSGIApplication
3-
from collections.abc import Mapping, Sequence
2+
from _typeshed import SupportsItems, SupportsKeysAndGetItem
3+
from _typeshed.wsgi import WSGIApplication, WSGIEnvironment
4+
from collections.abc import Iterable, Sequence
45
from http.cookiejar import CookieJar, DefaultCookiePolicy
56
from typing import Any, Generic, Literal, TypeVar
67
from typing_extensions import TypeAlias
78

89
from webob.request import BaseRequest
10+
from webtest.forms import File, Upload
911
from webtest.response import TestResponse
1012

13+
# NOTE: While it is possible to pass different kinds of values depending on
14+
# the exact configuration of the request, it seems more robust to
15+
# restrict them to the types that are supported by all code paths.
16+
# I don't expect anyone to try to pass different kinds of values
17+
# in a non-JSON request.
18+
_ParamValue: TypeAlias = File | Upload | int | bytes | str
19+
_Params: TypeAlias = SupportsItems[str | bytes, _ParamValue] | Sequence[tuple[str | bytes, _ParamValue]]
20+
# NOTE: Using `Collection` rather than `Iterable` would probably be slightly
21+
# safer since WebTest will check this parameter for truthyness. But since
22+
# objects are truthy by default, this should only lead to issues in truly
23+
# exotic cases.
24+
_ExtraEnviron: TypeAlias = SupportsKeysAndGetItem[str, Any] | Iterable[tuple[str, Any]]
1125
_Files: TypeAlias = Sequence[tuple[str, str] | tuple[str, str, bytes]]
1226
_AppT = TypeVar("_AppT", bound=WSGIApplication, default=WSGIApplication)
1327

@@ -27,15 +41,19 @@ class TestApp(Generic[_AppT]):
2741
app: _AppT
2842
lint: bool
2943
relative_to: str | None
30-
extra_environ: dict[str, Any]
44+
extra_environ: WSGIEnvironment
3145
use_unicode: bool
3246
cookiejar: CookieJar
3347
JSONEncoder: json.JSONEncoder
3448
__test__: Literal[False]
3549
def __init__(
3650
self,
3751
app: _AppT,
38-
extra_environ: dict[str, Any] | None = None,
52+
# NOTE: this extra_environ is different from the others and needs to
53+
# support __delitem__, it seems easiest to just treat this like
54+
# a regular WSGIEnvironment. The docs also say that this should
55+
# be a dictionary.
56+
extra_environ: WSGIEnvironment | None = None,
3957
relative_to: str | None = None,
4058
use_unicode: bool = True,
4159
cookiejar: CookieJar | None = None,
@@ -57,19 +75,19 @@ class TestApp(Generic[_AppT]):
5775
def get(
5876
self,
5977
url: str,
60-
params: Mapping[str, str] | str | None = None,
61-
headers: Mapping[str, str] | None = None,
62-
extra_environ: Mapping[str, Any] | None = None,
78+
params: _Params | str | None = None,
79+
headers: dict[str, str] | None = None,
80+
extra_environ: _ExtraEnviron | None = None,
6381
status: int | str | None = None,
6482
expect_errors: bool = False,
6583
xhr: bool = False,
6684
) -> TestResponse: ...
6785
def post(
6886
self,
6987
url: str,
70-
params: Mapping[str, str] | str = "",
71-
headers: Mapping[str, str] | None = None,
72-
extra_environ: Mapping[str, Any] | None = None,
88+
params: _Params | str = "",
89+
headers: dict[str, str] | None = None,
90+
extra_environ: _ExtraEnviron | None = None,
7391
status: int | str | None = None,
7492
upload_files: _Files | None = None,
7593
expect_errors: bool = False,
@@ -79,9 +97,9 @@ class TestApp(Generic[_AppT]):
7997
def put(
8098
self,
8199
url: str,
82-
params: Mapping[str, str] | str = "",
83-
headers: Mapping[str, str] | None = None,
84-
extra_environ: Mapping[str, Any] | None = None,
100+
params: _Params | str = "",
101+
headers: dict[str, str] | None = None,
102+
extra_environ: _ExtraEnviron | None = None,
85103
status: int | str | None = None,
86104
upload_files: _Files | None = None,
87105
expect_errors: bool = False,
@@ -91,9 +109,9 @@ class TestApp(Generic[_AppT]):
91109
def patch(
92110
self,
93111
url: str,
94-
params: Mapping[str, str] | str = "",
95-
headers: Mapping[str, str] | None = None,
96-
extra_environ: Mapping[str, Any] | None = None,
112+
params: _Params | str = "",
113+
headers: dict[str, str] | None = None,
114+
extra_environ: _ExtraEnviron | None = None,
97115
status: int | str | None = None,
98116
upload_files: _Files | None = None,
99117
expect_errors: bool = False,
@@ -103,9 +121,9 @@ class TestApp(Generic[_AppT]):
103121
def delete(
104122
self,
105123
url: str,
106-
params: Mapping[str, str] | str = "",
107-
headers: Mapping[str, str] | None = None,
108-
extra_environ: Mapping[str, Any] | None = None,
124+
params: _Params | str = "",
125+
headers: dict[str, str] | None = None,
126+
extra_environ: _ExtraEnviron | None = None,
109127
status: int | str | None = None,
110128
expect_errors: bool = False,
111129
content_type: str | None = None,
@@ -114,18 +132,18 @@ class TestApp(Generic[_AppT]):
114132
def options(
115133
self,
116134
url: str,
117-
headers: Mapping[str, str] | None = None,
118-
extra_environ: Mapping[str, Any] | None = None,
135+
headers: dict[str, str] | None = None,
136+
extra_environ: _ExtraEnviron | None = None,
119137
status: int | str | None = None,
120138
expect_errors: bool = False,
121139
xhr: bool = False,
122140
) -> TestResponse: ...
123141
def head(
124142
self,
125143
url: str,
126-
params: Mapping[str, str] | str | None = None,
127-
headers: Mapping[str, str] | None = None,
128-
extra_environ: Mapping[str, Any] | None = None,
144+
params: _Params | str | None = None,
145+
headers: dict[str, str] | None = None,
146+
extra_environ: _ExtraEnviron | None = None,
129147
status: int | str | None = None,
130148
expect_errors: bool = False,
131149
xhr: bool = False,
@@ -135,8 +153,8 @@ class TestApp(Generic[_AppT]):
135153
url: str,
136154
params: Any = ...,
137155
*,
138-
headers: Mapping[str, str] | None = None,
139-
extra_environ: Mapping[str, Any] | None = None,
156+
headers: dict[str, str] | None = None,
157+
extra_environ: _ExtraEnviron | None = None,
140158
status: int | str | None = None,
141159
expect_errors: bool = False,
142160
content_type: str | None = None,
@@ -147,8 +165,8 @@ class TestApp(Generic[_AppT]):
147165
url: str,
148166
params: Any = ...,
149167
*,
150-
headers: Mapping[str, str] | None = None,
151-
extra_environ: Mapping[str, Any] | None = None,
168+
headers: dict[str, str] | None = None,
169+
extra_environ: _ExtraEnviron | None = None,
152170
status: int | str | None = None,
153171
expect_errors: bool = False,
154172
content_type: str | None = None,
@@ -159,8 +177,8 @@ class TestApp(Generic[_AppT]):
159177
url: str,
160178
params: Any = ...,
161179
*,
162-
headers: Mapping[str, str] | None = None,
163-
extra_environ: Mapping[str, Any] | None = None,
180+
headers: dict[str, str] | None = None,
181+
extra_environ: _ExtraEnviron | None = None,
164182
status: int | str | None = None,
165183
expect_errors: bool = False,
166184
content_type: str | None = None,
@@ -171,14 +189,14 @@ class TestApp(Generic[_AppT]):
171189
url: str,
172190
params: Any = ...,
173191
*,
174-
headers: Mapping[str, str] | None = None,
175-
extra_environ: Mapping[str, Any] | None = None,
192+
headers: dict[str, str] | None = None,
193+
extra_environ: _ExtraEnviron | None = None,
176194
status: int | str | None = None,
177195
expect_errors: bool = False,
178196
content_type: str | None = None,
179197
xhr: bool = False,
180198
) -> TestResponse: ...
181-
def encode_multipart(self, params: Sequence[tuple[str, str]], files: _Files) -> tuple[str, bytes]: ...
199+
def encode_multipart(self, params: Iterable[tuple[str | bytes, _ParamValue]], files: _Files) -> tuple[str, bytes]: ...
182200
def request(
183201
self, url_or_req: str | TestRequest, status: int | str | None = None, expect_errors: bool = False, **req_params: Any
184202
) -> TestResponse: ...

0 commit comments

Comments
 (0)