Commit a2db47a
authored
fix(runtime): finish the transport-shape refactor (#140)
Follow-up to PR #137. Five small, related improvements to the
Request / Response contract introduced there:
1. Build the Request exactly once. _build_client_request now takes
'path' directly instead of returning a placeholder with path=""
that _make_request immediately rebuilt. The httpx branch used to
call _build_client_request twice (once for the unused intermediate,
again inside the now-removed _build_request). _build_request is
replaced with _build_httpx_request, which lifts an existing Request
into an httpx.Request without re-deriving the body.
2. Make middleware operate on the transport-agnostic Request /
Response instead of httpx.Request / httpx.Response. The middleware
chain now wraps an arbitrary terminal handler, so the same
middleware runs against either an httpx.Client or a custom Client
transport. RetryMiddleware gains a 'retry_on' parameter so non-httpx
transports can configure their own retryable exception types; the
default keeps httpx.RequestError for backward compat. Network-error
retry is now opt-in via retry_non_idempotent because every reflectapi
endpoint is POST.
3. Drop the runtime isinstance(Response) check on the custom-transport
response. The Protocol contract is structural — anything with
.status / .headers / .body works. The provided Response dataclass is
a convenient ready-made implementation, not a hard requirement, and
matches how the input Client / AsyncClient Protocols are
structurally typed.
4. Dispatch on isinstance(self._client, httpx.(Async)Client) instead
of hasattr('build_request') and hasattr('send'). The duck-typed check
would silently route a custom Client implementation onto the httpx
path if it happened to expose those names.
5. Move Request / Response / Client / AsyncClient to a new transport.py
module so middleware.py can depend on the types without a circular
import via client.py.
Tests:
- test_client.py: regressions for single Request build on both
branches, middleware running on both transports, dispatch using
isinstance, plus existing custom-transport coverage.
- test_middleware.py: rewritten against the Request / Response
contract — fewer mocks, smaller, clearer ordering and retry coverage.
- test_edge_cases.py: updated where mocks relied on .json side-effects
or unset .content; the runtime reconstructs httpx.Response from the
Response bytes, so parse failures need real malformed bytes rather
than mock injection.1 parent 6e4d9ac commit a2db47a
9 files changed
Lines changed: 1172 additions & 893 deletions
File tree
- reflectapi-python-runtime
- src/reflectapi_runtime
- tests
Lines changed: 2 additions & 8 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
19 | 19 | | |
20 | 20 | | |
21 | 21 | | |
22 | | - | |
23 | | - | |
24 | | - | |
25 | | - | |
26 | | - | |
27 | | - | |
28 | | - | |
29 | | - | |
| 22 | + | |
| 23 | + | |
30 | 24 | | |
31 | 25 | | |
32 | 26 | | |
| |||
0 commit comments