Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add deprecation warning to timeout in TestClient #2841

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ filterwarnings = [
"error",
"ignore: run_until_first_complete is deprecated and will be removed in a future version.:DeprecationWarning",
"ignore: starlette.middleware.wsgi is deprecated and will be removed in a future release.*:DeprecationWarning",
"ignore: The `timeout` argument doesn't work, is deprecated, and will be removed in future versions.*:DeprecationWarning",
"ignore: Async generator 'starlette.requests.Request.stream' was garbage collected before it had been exhausted.*:ResourceWarning",
"ignore: Use 'content=<...>' to upload raw bytes/text content.:DeprecationWarning",
]
Expand Down
52 changes: 36 additions & 16 deletions starlette/testclient.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import math
import sys
import typing
import warnings
from concurrent.futures import Future
from types import GeneratorType
from urllib.parse import unquote, urljoin
Expand Down Expand Up @@ -409,6 +410,17 @@ def _portal_factory(self) -> typing.Generator[anyio.abc.BlockingPortal, None, No
with anyio.from_thread.start_blocking_portal(**self.async_backend) as portal:
yield portal

def _handle_timeout(
self,
timeout: httpx._types.TimeoutTypes | None,
) -> httpx._types.TimeoutTypes | httpx._client.UseClientDefault:
default_timeout: httpx._types.TimeoutTypes | httpx._client.UseClientDefault = httpx._client.USE_CLIENT_DEFAULT
if timeout is not None:
message = "The `timeout` argument doesn't work, is deprecated, and will be removed in future versions."
warnings.warn(message, DeprecationWarning)
return timeout
return default_timeout

def request( # type: ignore[override]
self,
method: str,
Expand All @@ -423,9 +435,10 @@ def request( # type: ignore[override]
cookies: httpx._types.CookieTypes | None = None,
auth: httpx._types.AuthTypes | httpx._client.UseClientDefault = httpx._client.USE_CLIENT_DEFAULT,
follow_redirects: bool | httpx._client.UseClientDefault = httpx._client.USE_CLIENT_DEFAULT,
timeout: httpx._types.TimeoutTypes | httpx._client.UseClientDefault = httpx._client.USE_CLIENT_DEFAULT,
timeout: httpx._types.TimeoutTypes | None = None,
extensions: dict[str, typing.Any] | None = None,
) -> httpx.Response:
_timeout = self._handle_timeout(timeout)
url = self._merge_url(url)
return super().request(
method,
Expand All @@ -439,7 +452,7 @@ def request( # type: ignore[override]
cookies=cookies,
auth=auth,
follow_redirects=follow_redirects,
timeout=timeout,
timeout=_timeout,
extensions=extensions,
)

Expand All @@ -452,17 +465,18 @@ def get( # type: ignore[override]
cookies: httpx._types.CookieTypes | None = None,
auth: httpx._types.AuthTypes | httpx._client.UseClientDefault = httpx._client.USE_CLIENT_DEFAULT,
follow_redirects: bool | httpx._client.UseClientDefault = httpx._client.USE_CLIENT_DEFAULT,
timeout: httpx._types.TimeoutTypes | httpx._client.UseClientDefault = httpx._client.USE_CLIENT_DEFAULT,
timeout: httpx._types.TimeoutTypes | None = None,
extensions: dict[str, typing.Any] | None = None,
) -> httpx.Response:
_timeout = self._handle_timeout(timeout)
return super().get(
url,
params=params,
headers=headers,
cookies=cookies,
auth=auth,
follow_redirects=follow_redirects,
timeout=timeout,
timeout=_timeout,
extensions=extensions,
)

Expand All @@ -475,17 +489,18 @@ def options( # type: ignore[override]
cookies: httpx._types.CookieTypes | None = None,
auth: httpx._types.AuthTypes | httpx._client.UseClientDefault = httpx._client.USE_CLIENT_DEFAULT,
follow_redirects: bool | httpx._client.UseClientDefault = httpx._client.USE_CLIENT_DEFAULT,
timeout: httpx._types.TimeoutTypes | httpx._client.UseClientDefault = httpx._client.USE_CLIENT_DEFAULT,
timeout: httpx._types.TimeoutTypes | None = None,
extensions: dict[str, typing.Any] | None = None,
) -> httpx.Response:
_timeout = self._handle_timeout(timeout)
return super().options(
url,
params=params,
headers=headers,
cookies=cookies,
auth=auth,
follow_redirects=follow_redirects,
timeout=timeout,
timeout=_timeout,
extensions=extensions,
)

Expand All @@ -498,17 +513,18 @@ def head( # type: ignore[override]
cookies: httpx._types.CookieTypes | None = None,
auth: httpx._types.AuthTypes | httpx._client.UseClientDefault = httpx._client.USE_CLIENT_DEFAULT,
follow_redirects: bool | httpx._client.UseClientDefault = httpx._client.USE_CLIENT_DEFAULT,
timeout: httpx._types.TimeoutTypes | httpx._client.UseClientDefault = httpx._client.USE_CLIENT_DEFAULT,
timeout: httpx._types.TimeoutTypes | None = None,
extensions: dict[str, typing.Any] | None = None,
) -> httpx.Response:
_timeout = self._handle_timeout(timeout)
return super().head(
url,
params=params,
headers=headers,
cookies=cookies,
auth=auth,
follow_redirects=follow_redirects,
timeout=timeout,
timeout=_timeout,
extensions=extensions,
)

Expand All @@ -525,9 +541,10 @@ def post( # type: ignore[override]
cookies: httpx._types.CookieTypes | None = None,
auth: httpx._types.AuthTypes | httpx._client.UseClientDefault = httpx._client.USE_CLIENT_DEFAULT,
follow_redirects: bool | httpx._client.UseClientDefault = httpx._client.USE_CLIENT_DEFAULT,
timeout: httpx._types.TimeoutTypes | httpx._client.UseClientDefault = httpx._client.USE_CLIENT_DEFAULT,
timeout: httpx._types.TimeoutTypes | None = None,
extensions: dict[str, typing.Any] | None = None,
) -> httpx.Response:
_timeout = self._handle_timeout(timeout)
return super().post(
url,
content=content,
Expand All @@ -539,7 +556,7 @@ def post( # type: ignore[override]
cookies=cookies,
auth=auth,
follow_redirects=follow_redirects,
timeout=timeout,
timeout=_timeout,
extensions=extensions,
)

Expand All @@ -556,9 +573,10 @@ def put( # type: ignore[override]
cookies: httpx._types.CookieTypes | None = None,
auth: httpx._types.AuthTypes | httpx._client.UseClientDefault = httpx._client.USE_CLIENT_DEFAULT,
follow_redirects: bool | httpx._client.UseClientDefault = httpx._client.USE_CLIENT_DEFAULT,
timeout: httpx._types.TimeoutTypes | httpx._client.UseClientDefault = httpx._client.USE_CLIENT_DEFAULT,
timeout: httpx._types.TimeoutTypes | None = None,
extensions: dict[str, typing.Any] | None = None,
) -> httpx.Response:
_timeout = self._handle_timeout(timeout)
return super().put(
url,
content=content,
Expand All @@ -570,7 +588,7 @@ def put( # type: ignore[override]
cookies=cookies,
auth=auth,
follow_redirects=follow_redirects,
timeout=timeout,
timeout=_timeout,
extensions=extensions,
)

Expand All @@ -587,9 +605,10 @@ def patch( # type: ignore[override]
cookies: httpx._types.CookieTypes | None = None,
auth: httpx._types.AuthTypes | httpx._client.UseClientDefault = httpx._client.USE_CLIENT_DEFAULT,
follow_redirects: bool | httpx._client.UseClientDefault = httpx._client.USE_CLIENT_DEFAULT,
timeout: httpx._types.TimeoutTypes | httpx._client.UseClientDefault = httpx._client.USE_CLIENT_DEFAULT,
timeout: httpx._types.TimeoutTypes | None = None,
extensions: dict[str, typing.Any] | None = None,
) -> httpx.Response:
_timeout = self._handle_timeout(timeout)
return super().patch(
url,
content=content,
Expand All @@ -601,7 +620,7 @@ def patch( # type: ignore[override]
cookies=cookies,
auth=auth,
follow_redirects=follow_redirects,
timeout=timeout,
timeout=_timeout,
extensions=extensions,
)

Expand All @@ -614,17 +633,18 @@ def delete( # type: ignore[override]
cookies: httpx._types.CookieTypes | None = None,
auth: httpx._types.AuthTypes | httpx._client.UseClientDefault = httpx._client.USE_CLIENT_DEFAULT,
follow_redirects: bool | httpx._client.UseClientDefault = httpx._client.USE_CLIENT_DEFAULT,
timeout: httpx._types.TimeoutTypes | httpx._client.UseClientDefault = httpx._client.USE_CLIENT_DEFAULT,
timeout: httpx._types.TimeoutTypes | None = None,
extensions: dict[str, typing.Any] | None = None,
) -> httpx.Response:
_timeout = self._handle_timeout(timeout)
return super().delete(
url,
params=params,
headers=headers,
cookies=cookies,
auth=auth,
follow_redirects=follow_redirects,
timeout=timeout,
timeout=_timeout,
extensions=extensions,
)

Expand Down
19 changes: 19 additions & 0 deletions tests/test_testclient.py
Original file line number Diff line number Diff line change
Expand Up @@ -422,3 +422,22 @@ async def app(scope: Scope, receive: Receive, send: Send) -> None:
with client.websocket_connect("/hello-world", params={"foo": "bar"}) as websocket:
data = websocket.receive_bytes()
assert data == b"/hello-world"


@pytest.mark.parametrize("method", [None, "GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS", "HEAD"])
def test_warning_timeout_deprecation(test_client_factory: TestClientFactory, method: str | None) -> None:
def homepage(request: Request) -> Response:
return Response("Hello, world!")

allowed_method = [method] if method else None
app = Starlette(routes=[Route("/", endpoint=homepage, methods=allowed_method)])
client = test_client_factory(app)
with pytest.warns(
DeprecationWarning,
match="The `timeout` argument doesn't work, is deprecated, and will be removed in future versions.",
):
if method is None:
client.request("GET", "/", timeout=0.1)
else:
client_method = getattr(client, method.lower())
client_method("/", timeout=0.1)
Loading