Skip to content

Commit 560611a

Browse files
authored
[WebTest] Add stubs (#14541)
1 parent 7ae857f commit 560611a

8 files changed

Lines changed: 578 additions & 0 deletions

File tree

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# error: failed to find stub
2+
# ==========================
3+
# These modules have been migrated to external packages
4+
# and emit an `ImportError` if people try to use the
5+
# functions/classes defined within
6+
webtest.ext
7+
webtest.sel
8+
# Compatibility/utility modules for internal use that didn't
9+
# seem worth including in the stubs
10+
webtest.compat
11+
webtest.lint
12+
webtest.utils
13+
14+
# error: variable differs from runtime type
15+
# =========================================
16+
# Even though this can be `None`, it never should be during
17+
# normal use of WebTest, so it seems more pragmatic to treat
18+
# it as always non-`None`
19+
webtest.response.TestResponse.request

stubs/WebTest/METADATA.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
version = "3.0.*"
2+
upstream-repository = "https://github.com/Pylons/webtest"
3+
dependencies = ["beautifulsoup4", "types-waitress", "types-WebOb"]

stubs/WebTest/webtest/__init__.pyi

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
from webtest.app import AppError as AppError, TestApp as TestApp, TestRequest as TestRequest
2+
from webtest.forms import (
3+
Checkbox as Checkbox,
4+
Field as Field,
5+
Form as Form,
6+
Hidden as Hidden,
7+
Radio as Radio,
8+
Select as Select,
9+
Submit as Submit,
10+
Text as Text,
11+
Textarea as Textarea,
12+
Upload as Upload,
13+
)
14+
from webtest.response import TestResponse as TestResponse

stubs/WebTest/webtest/app.pyi

Lines changed: 206 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,206 @@
1+
import json
2+
from _typeshed import SupportsItems, SupportsKeysAndGetItem
3+
from _typeshed.wsgi import WSGIApplication, WSGIEnvironment
4+
from collections.abc import Iterable, Sequence
5+
from http.cookiejar import CookieJar, DefaultCookiePolicy
6+
from typing import Any, Generic, Literal, TypeAlias, TypeVar
7+
8+
from webob.request import BaseRequest
9+
from webtest.forms import File, Upload
10+
from webtest.response import TestResponse
11+
12+
# NOTE: While it is possible to pass different kinds of values depending on
13+
# the exact configuration of the request, it seems more robust to
14+
# restrict them to the types that are supported by all code paths.
15+
# I don't expect anyone to try to pass different kinds of values
16+
# in a non-JSON request.
17+
_ParamValue: TypeAlias = File | Upload | int | bytes | str
18+
_Params: TypeAlias = SupportsItems[str | bytes, _ParamValue] | Sequence[tuple[str | bytes, _ParamValue]]
19+
# NOTE: Using `Collection` rather than `Iterable` would probably be slightly
20+
# safer since WebTest will check this parameter for truthyness. But since
21+
# objects are truthy by default, this should only lead to issues in truly
22+
# exotic cases.
23+
_ExtraEnviron: TypeAlias = SupportsKeysAndGetItem[str, Any] | Iterable[tuple[str, Any]]
24+
_Files: TypeAlias = Sequence[tuple[str, str] | tuple[str, str, bytes]]
25+
_AppT = TypeVar("_AppT", bound=WSGIApplication, default=WSGIApplication)
26+
27+
__all__ = ["TestApp", "TestRequest"]
28+
29+
class AppError(Exception):
30+
def __init__(self, message: str, *args: object) -> None: ...
31+
32+
class CookiePolicy(DefaultCookiePolicy): ...
33+
34+
class TestRequest(BaseRequest):
35+
ResponseClass: type[TestResponse]
36+
__test__: Literal[False]
37+
38+
class TestApp(Generic[_AppT]):
39+
RequestClass: type[TestRequest]
40+
app: _AppT
41+
lint: bool
42+
relative_to: str | None
43+
extra_environ: WSGIEnvironment
44+
use_unicode: bool
45+
cookiejar: CookieJar
46+
JSONEncoder: json.JSONEncoder
47+
__test__: Literal[False]
48+
def __init__(
49+
self,
50+
app: _AppT,
51+
# NOTE: this extra_environ is different from the others and needs to
52+
# support __delitem__, it seems easiest to just treat this like
53+
# a regular WSGIEnvironment. The docs also say that this should
54+
# be a dictionary.
55+
extra_environ: WSGIEnvironment | None = None,
56+
relative_to: str | None = None,
57+
use_unicode: bool = True,
58+
cookiejar: CookieJar | None = None,
59+
parser_features: Sequence[str] | str | None = None,
60+
json_encoder: json.JSONEncoder | None = None,
61+
lint: bool = True,
62+
) -> None: ...
63+
def get_authorization(self) -> tuple[str, str | tuple[str, str]]: ...
64+
def set_authorization(self, value: tuple[str, str | tuple[str, str]]) -> None: ...
65+
66+
@property
67+
def authorization(self) -> tuple[str, str | tuple[str, str]]: ...
68+
@authorization.setter
69+
def authorization(self, value: tuple[str, str | tuple[str, str]]) -> None: ...
70+
71+
@property
72+
def cookies(self) -> dict[str, str | None]: ...
73+
def set_cookie(self, name: str, value: str | None) -> None: ...
74+
def reset(self) -> None: ...
75+
def set_parser_features(self, parser_features: Sequence[str] | str) -> None: ...
76+
def get(
77+
self,
78+
url: str,
79+
params: _Params | str | None = None,
80+
headers: dict[str, str] | None = None,
81+
extra_environ: _ExtraEnviron | None = None,
82+
status: int | str | None = None,
83+
expect_errors: bool = False,
84+
xhr: bool = False,
85+
) -> TestResponse: ...
86+
def post(
87+
self,
88+
url: str,
89+
params: _Params | str = "",
90+
headers: dict[str, str] | None = None,
91+
extra_environ: _ExtraEnviron | None = None,
92+
status: int | str | None = None,
93+
upload_files: _Files | None = None,
94+
expect_errors: bool = False,
95+
content_type: str | None = None,
96+
xhr: bool = False,
97+
) -> TestResponse: ...
98+
def put(
99+
self,
100+
url: str,
101+
params: _Params | str = "",
102+
headers: dict[str, str] | None = None,
103+
extra_environ: _ExtraEnviron | None = None,
104+
status: int | str | None = None,
105+
upload_files: _Files | None = None,
106+
expect_errors: bool = False,
107+
content_type: str | None = None,
108+
xhr: bool = False,
109+
) -> TestResponse: ...
110+
def patch(
111+
self,
112+
url: str,
113+
params: _Params | str = "",
114+
headers: dict[str, str] | None = None,
115+
extra_environ: _ExtraEnviron | None = None,
116+
status: int | str | None = None,
117+
upload_files: _Files | None = None,
118+
expect_errors: bool = False,
119+
content_type: str | None = None,
120+
xhr: bool = False,
121+
) -> TestResponse: ...
122+
def delete(
123+
self,
124+
url: str,
125+
params: _Params | str = "",
126+
headers: dict[str, str] | None = None,
127+
extra_environ: _ExtraEnviron | None = None,
128+
status: int | str | None = None,
129+
expect_errors: bool = False,
130+
content_type: str | None = None,
131+
xhr: bool = False,
132+
) -> TestResponse: ...
133+
def options(
134+
self,
135+
url: str,
136+
headers: dict[str, str] | None = None,
137+
extra_environ: _ExtraEnviron | None = None,
138+
status: int | str | None = None,
139+
expect_errors: bool = False,
140+
xhr: bool = False,
141+
) -> TestResponse: ...
142+
def head(
143+
self,
144+
url: str,
145+
params: _Params | str | None = None,
146+
headers: dict[str, str] | None = None,
147+
extra_environ: _ExtraEnviron | None = None,
148+
status: int | str | None = None,
149+
expect_errors: bool = False,
150+
xhr: bool = False,
151+
) -> TestResponse: ...
152+
def post_json(
153+
self,
154+
url: str,
155+
params: Any = ...,
156+
*,
157+
headers: dict[str, str] | None = None,
158+
extra_environ: _ExtraEnviron | None = None,
159+
status: int | str | None = None,
160+
expect_errors: bool = False,
161+
content_type: str | None = None,
162+
xhr: bool = False,
163+
) -> TestResponse: ...
164+
def put_json(
165+
self,
166+
url: str,
167+
params: Any = ...,
168+
*,
169+
headers: dict[str, str] | None = None,
170+
extra_environ: _ExtraEnviron | None = None,
171+
status: int | str | None = None,
172+
expect_errors: bool = False,
173+
content_type: str | None = None,
174+
xhr: bool = False,
175+
) -> TestResponse: ...
176+
def patch_json(
177+
self,
178+
url: str,
179+
params: Any = ...,
180+
*,
181+
headers: dict[str, str] | None = None,
182+
extra_environ: _ExtraEnviron | None = None,
183+
status: int | str | None = None,
184+
expect_errors: bool = False,
185+
content_type: str | None = None,
186+
xhr: bool = False,
187+
) -> TestResponse: ...
188+
def delete_json(
189+
self,
190+
url: str,
191+
params: Any = ...,
192+
*,
193+
headers: dict[str, str] | None = None,
194+
extra_environ: _ExtraEnviron | None = None,
195+
status: int | str | None = None,
196+
expect_errors: bool = False,
197+
content_type: str | None = None,
198+
xhr: bool = False,
199+
) -> TestResponse: ...
200+
def encode_multipart(self, params: Iterable[tuple[str | bytes, _ParamValue]], files: _Files) -> tuple[str, bytes]: ...
201+
def request(
202+
self, url_or_req: str | TestRequest, status: int | str | None = None, expect_errors: bool = False, **req_params: Any
203+
) -> TestResponse: ...
204+
def do_request(
205+
self, req: TestRequest, status: int | str | None = None, expect_errors: bool | None = None
206+
) -> TestResponse: ...

stubs/WebTest/webtest/debugapp.pyi

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
from _typeshed import StrOrBytesPath
2+
from _typeshed.wsgi import StartResponse, WSGIEnvironment
3+
from collections.abc import Iterable
4+
from typing import TypedDict, type_check_only
5+
from typing_extensions import Unpack
6+
7+
@type_check_only
8+
class _DebugAppParams(TypedDict, total=False):
9+
form: StrOrBytesPath | bytes | None
10+
show_form: bool
11+
12+
__all__ = ["DebugApp", "make_debug_app"]
13+
14+
class DebugApp:
15+
form: bytes | None
16+
show_form: bool
17+
def __init__(self, form: StrOrBytesPath | bytes | None = None, show_form: bool = False) -> None: ...
18+
def __call__(self, environ: WSGIEnvironment, start_response: StartResponse) -> Iterable[bytes]: ...
19+
20+
debug_app: DebugApp
21+
22+
def make_debug_app(global_conf: object, **local_conf: Unpack[_DebugAppParams]) -> DebugApp: ...

0 commit comments

Comments
 (0)