Skip to content
Merged
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
3 changes: 3 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ classifiers = [
version = "0"
dependencies = [
"httpx2>=2.0.0,<3.0",
# 4.14.0 is the first whose closed TypedDicts keep their keys on Python 3.14, and the
# cp314 pydantic floor (2.12) needs 4.14.1.
"typing-extensions>=4.14.1",
]

[project.optional-dependencies]
Expand Down
7 changes: 4 additions & 3 deletions src/httpware/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from http import HTTPStatus

import httpx2
import typing_extensions

from httpware._internal import import_checker
from httpware._internal.body_cap import _read_capped, _read_capped_async, _validate_max_response_body_bytes
Expand Down Expand Up @@ -75,7 +76,7 @@ def _reject_base_url_query(base_url: httpx2.URL | str) -> None:
raise ValueError(_BASE_URL_QUERY_MESSAGE)


class _ClientOptionsBase(typing.TypedDict, total=False):
class _ClientOptionsBase(typing_extensions.TypedDict, total=False):
base_url: str
headers: dict[str, str] | None
params: dict[str, str] | None
Expand All @@ -93,14 +94,14 @@ class _ClientOptionsBase(typing.TypedDict, total=False):
default_encoding: str | Callable[[bytes], str | None]


class _AsyncClientOptions(_ClientOptionsBase, total=False):
class _AsyncClientOptions(_ClientOptionsBase, total=False, closed=True):
"""Keyword arguments `AsyncClient` forwards to the `httpx2.AsyncClient` it owns."""

transport: httpx2.AsyncBaseTransport | None
mounts: Mapping[str, httpx2.AsyncBaseTransport | None] | None


class _ClientOptions(_ClientOptionsBase, total=False):
class _ClientOptions(_ClientOptionsBase, total=False, closed=True):
"""Keyword arguments `Client` forwards to the `httpx2.Client` it owns."""

transport: httpx2.BaseTransport | None
Expand Down
14 changes: 14 additions & 0 deletions tests/test_client_options.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,20 @@ def test_unsupported_option_is_typeerror(client_cls: type, key: str) -> None:
client_cls(**{key: object()})


def test_type_checkers_reject_unsupported_async_options() -> None:
with pytest.raises(TypeError, match="verfy"):
AsyncClient(verfy=True) # ty: ignore[unknown-argument]
with pytest.raises(TypeError, match="cert"):
AsyncClient(cert="client.pem") # ty: ignore[unknown-argument]


def test_type_checkers_reject_unsupported_sync_options() -> None:
with pytest.raises(TypeError, match="verfy"):
Client(verfy=True) # ty: ignore[unknown-argument]
with pytest.raises(TypeError, match="cert"):
Client(cert="client.pem") # ty: ignore[unknown-argument]


@pytest.mark.parametrize("client_cls", [AsyncClient, Client])
def test_follow_redirects_with_body_cap_is_valueerror(client_cls: type) -> None:
with pytest.raises(ValueError, match="follow_redirects"):
Expand Down
Loading