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
32 changes: 32 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,38 @@ The organization users endpoint also supports server-side email filtering:
The equivalent asynchronous operation is
``await client.organization.users.list(email="person@example.com")``.

HTTPX2 transports
-----------------

HTTPX remains the default client family. To opt in to HTTPX2, construct the
HTTPX2 transport explicitly and pass it to the client. The standard
``coderpad-py`` installation includes both client families.

.. code-block:: python

"""Configure CoderPad to use HTTPX2."""

import sys

import httpx2

from coderpad.client import CoderPad
from coderpad.transports import HTTPX2Transport

transport = HTTPX2Transport(timeout=httpx2.Timeout(timeout=10))
with CoderPad(api_key="your-api-key", transport=transport) as client:
sys.stdout.write(client.base_url)

Use ``AsyncHTTPX2Transport`` with ``AsyncCoderPad`` for asynchronous calls.
The ``limits``, ``proxy`` and ``timeout`` arguments passed to these transports
accept HTTPX2 configuration objects. Do not pass equivalent ``httpx`` objects
across the package boundary. If the Screen API should also use HTTPX2, pass a
separate HTTPX2 transport as ``screen_transport``.

Existing HTTPX users do not need to change anything. Migrating to HTTPX2 only
requires selecting the new transport; the CoderPad client methods and returned
models are unchanged.

CoderPad Screen
---------------

Expand Down
6 changes: 5 additions & 1 deletion docs/source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,10 +79,14 @@
nitpicky = True
nitpick_ignore: list[tuple[str, str]] = [
("py:class", "coderpad.types._T"),
# httpx is not in intersphinx_mapping; keep typed annotations.
# The HTTP client inventories do not expose these configuration classes;
# keep the typed annotations without making the docs build fail.
("py:class", "httpx.Limits"),
("py:class", "httpx.Proxy"),
("py:class", "httpx.Timeout"),
("py:class", "httpx2.Limits"),
("py:class", "httpx2.Proxy"),
("py:class", "httpx2.Timeout"),
]
nitpick_ignore_regex = [
(r"py:class", r"coderpad\._dict_types\..*"),
Expand Down
32 changes: 32 additions & 0 deletions docs/source/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,38 @@ Usage
org = client.organization.get()
sys.stdout.write(org.organization_name)

HTTPX2 transports
-----------------

HTTPX remains the default client family. To opt in to HTTPX2, construct the
HTTPX2 transport explicitly and pass it to the client. The standard
``coderpad-py`` installation includes both client families.

.. code-block:: python

"""Configure CoderPad to use HTTPX2."""

import sys

import httpx2

from coderpad.client import CoderPad
from coderpad.transports import HTTPX2Transport

transport = HTTPX2Transport(timeout=httpx2.Timeout(timeout=10))
with CoderPad(api_key="your-api-key", transport=transport) as client:
sys.stdout.write(client.base_url)

Use ``AsyncHTTPX2Transport`` with ``AsyncCoderPad`` for asynchronous calls.
The ``limits``, ``proxy`` and ``timeout`` arguments passed to these transports
accept HTTPX2 configuration objects. Do not pass equivalent ``httpx`` objects
across the package boundary. If the Screen API should also use HTTPX2, pass a
separate HTTPX2 transport as ``screen_transport``.

Existing HTTPX users do not need to change anything. Migrating to HTTPX2 only
requires selecting the new transport; the CoderPad client methods and returned
models are unchanged.

See the :doc:`api-reference` for full usage details, including the exception hierarchy.

Reference
Expand Down
2 changes: 2 additions & 0 deletions newsfragments/385.change.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Add synchronous and asynchronous HTTPX2 transports while retaining HTTPX as
the default client family.
2 changes: 2 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ dynamic = [
dependencies = [
"beartype>=0.22.9",
"httpx>=0.28.0",
"httpx2>=2.12.0",
"pydantic>=2.12.0",
]
optional-dependencies.dev = [
Expand Down Expand Up @@ -64,6 +65,7 @@ optional-dependencies.dev = [
"pytest-asyncio==1.4.0",
"pytest-beartype-tests==2026.8.16",
"pytest-cov==7.1.0",
"pytest-httpx2==1.0.0",
"pyyaml==6.0.3",
"respx==0.23.1",
"ruff==0.16.6",
Expand Down
1 change: 1 addition & 0 deletions spelling_private_dict.txt
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ html
http
https
httpx
httpx2
io
iterable
json
Expand Down
9 changes: 6 additions & 3 deletions src/coderpad/async_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
from coderpad.exceptions import CoderPadError
from coderpad.screen import SCREEN_US_BASE_URL
from coderpad.transports import (
AsyncHTTPX2Transport,
AsyncHTTPXTransport,
AsyncJSONTransport,
AsyncTransport,
Expand Down Expand Up @@ -924,12 +925,14 @@ async def _noop() -> None:

if isinstance(
resolved_transport,
AsyncHTTPXTransport,
(AsyncHTTPXTransport, AsyncHTTPX2Transport),
):
self._aclose = resolved_transport.aclose
else:
self._aclose = _noop
if isinstance(screen_transport, AsyncHTTPXTransport):
if isinstance(
screen_transport, (AsyncHTTPXTransport, AsyncHTTPX2Transport)
):
self._screen_aclose = screen_transport.aclose
else:
self._screen_aclose = _noop
Expand Down Expand Up @@ -962,7 +965,7 @@ def screen(self) -> AsyncScreenNamespace:
)
if self._screen_transport is None and isinstance(
resolved_screen_transport,
AsyncHTTPXTransport,
(AsyncHTTPXTransport, AsyncHTTPX2Transport),
):
self._screen_aclose = resolved_screen_transport.aclose
self._screen_transport = resolved_screen_transport
Expand Down
7 changes: 4 additions & 3 deletions src/coderpad/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
from coderpad.exceptions import CoderPadError
from coderpad.screen import SCREEN_US_BASE_URL, ScreenNamespace
from coderpad.transports import (
HTTPX2Transport,
HTTPXTransport,
JSONTransport,
Transport,
Expand Down Expand Up @@ -903,11 +904,11 @@ def __init__(
self._screen_transport = screen_transport
self._default_headers = default_headers
self._screen: ScreenNamespace | None = None
if isinstance(resolved_transport, HTTPXTransport):
if isinstance(resolved_transport, (HTTPXTransport, HTTPX2Transport)):
self._close = resolved_transport.close
else:
self._close = lambda: None
if isinstance(screen_transport, HTTPXTransport):
if isinstance(screen_transport, (HTTPXTransport, HTTPX2Transport)):
self._screen_close = screen_transport.close
else:
self._screen_close = lambda: None
Expand Down Expand Up @@ -938,7 +939,7 @@ def screen(self) -> ScreenNamespace:
)
if self._screen_transport is None and isinstance(
resolved_screen_transport,
HTTPXTransport,
(HTTPXTransport, HTTPX2Transport),
):
self._screen_close = resolved_screen_transport.close
self._screen_transport = resolved_screen_transport
Expand Down
Loading
Loading