requests¶
The sync workhorse. The engine mounts as a requests.adapters.HTTPAdapter on a
genuine requests.Session — the seam requests itself designed for exactly this
kind of extension:
import requests
from clientwright import ClientConfig, build_sync
session = build_sync("requests", ClientConfig(service_name="reports"))
assert type(session) is requests.Session
response = session.get("https://api.example.com/reports/42")
No base_url — on purpose¶
requests has no base-URL concept, and inventing one above the session would be a
wrapper — the thing clientwright refuses to be. Configs for this adapter leave
base_url unset and call sites use absolute URLs, exactly as idiomatic requests
code always has. (Setting base_url anyway fails the build with a clear error.)
The famous timeout hole, closed¶
Stock requests has no default timeout — a bare session.get(url) can hang
forever, and "always pass timeout=" is a convention that survives until the
first forgotten call site. Under clientwright the engine plans a per-attempt
(connect, read) timeout from your config and the remaining total on every
request, so the hole is simply gone:
config = ClientConfig(service_name="reports", timeout=TimeoutConfig(total=15.0))
session = build_sync("requests", config)
session.get("https://api.example.com/slow-report") # no timeout= needed: capped at 15 s
A caller-passed timeout= still participates per your
caller_override
mode — clamped by the total either way.
Per-call options¶
from clientwright.adapters.requests import call_options
with call_options(route="/reports/{id}", idempotent=True):
session.post(url, json=payload)
Capability notes¶
- Deadline: soft. Sync runtime — phase clamping plus boundary checks, honest
read_timeoutoutcome when a stall eats the budget. Declared asDEADLINE_HARD: absent. - requests sits on urllib3. The adapter suppresses the inner layer's
instrumentation, so a requests call counts once even though urllib3 physically
carries it — and urllib3's own hidden retry machinery is pinned off
(
max_retries=Retry(0)); the engine is the only retry loop. - HTTP/2: absent. requests is HTTP/1.1; asking for
http2=Truelands inreport.dropped(and fails astrictbuild). - Pool-acquire timeout: absent — declared dropped, with the engine's per-origin limiter available as the emulated alternative for per-host capping.
- mTLS with an encrypted key: requests cannot take a key password; the
three-element
certtuple is rejected at build rather than passed to a library that would ignore the password. - Errors:
RequestsCircuitOpenErrorand friends inheritrequests.RequestException— existing handlers keep catching.