Skip to content

Commit

Permalink
Add deprecation warning to timeout in TestClient
Browse files Browse the repository at this point in the history
  • Loading branch information
lealre committed Jan 4, 2025
1 parent 0109dce commit 16fade5
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 16 deletions.
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)

0 comments on commit 16fade5

Please sign in to comment.