feat: add send_with_response method for atomic (response, decoded) pair#33
Merged
Conversation
Tests cover: returns (response, decoded); preserves response headers; preserves response.request.url; decode failure raises DecodeError with the right original; malformed JSON raises DecodeError; DecodeError is caught by ClientError; 4xx raises StatusError (not DecodeError); user middleware mutation is observable on the wire and on response.request. All tests currently fail with AttributeError — implementation lands next. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…rtions Code quality review caught: - `_client_with_payload`'s `record` keyword-only param had no caller (the middleware test builds its own inline handler) — dropped. - `test_send_with_response_malformed_json_raises_decode_error` now asserts the full DecodeError shape (status_code/model/original), matching test_client_response_model.py's analog. Tests still all fail with AttributeError — red phase preserved. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Returns (response, decoded) atomically — routes the decode through the configured ResponseDecoder so decoder failures surface as DecodeError, identical to send(request, response_model=...). Use case: callers who need response headers (Link, X-Total-Count, ...) alongside a typed body, most commonly Link-header pagination. Spec: planning/specs/2026-06-08-send-with-response-design.md Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sync siblings of the async test file: same eight cases, using Client / httpx2.Client / before_request. All currently fail with AttributeError; implementation lands next. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sync sibling of AsyncClient.send_with_response. Same shape: returns (response, decoded) atomically and routes the decode through the configured ResponseDecoder. Identical docstring; sync dispatch path. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
docs/index.md: new "Response metadata + typed body" subsection with a Link-header pagination example; points body-only callers back at client.get(..., response_model=). planning/engineering.md: Seam B contract now names send_with_response alongside send as the two call sites that wrap decoder exceptions. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Code-quality review on the Response metadata + typed body subsection flagged that the example used undefined names without acknowledgment and the closing "when to use what" list skipped the build_request + body-only case. This fixes both: - One-line note above the example: process/next_link are caller-defined - Adds a sentence pointing readers at client.send(request, response_model=) as the body-only alternative when they need a custom Request - "Link-header" -> "Link header" to match RFC 5988 terminology Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The 0.8.2 spec deliberately scoped send_with_response to a single method; the per-verb sibling form (get_with_response etc.) was considered and deferred. Recording here so it isn't forgotten if a concrete consumer demand surfaces later. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The double-check-with-lock pattern in AsyncBulkhead._check_loop has an inner `elif self._loop is not current` arm that fires only when two threads simultaneously pass the cached-loop check and queue on the lock. It's a real race in concurrent use but extremely hard to trigger deterministically in a test. Mark it `# pragma: no cover` with a short justification rather than carry a contrived two-thread test. Carry-along on PR #33 to unblock CI; bulkhead.py was modified by df729fa on main and the coverage gap propagated to every PR. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
send_with_response(request, *, response_model) -> tuple[httpx2.Response, T]to bothAsyncClientandClient. Returns the raw response and a decoded typed body atomically — for callers who need response metadata (headers, status, request URL) alongside a typed body. Canonical use case: RFC 5988 Link header pagination.httpware.DecodeError, identical to the existingsend(..., response_model=)contract.except httpware.ClientErrorcatches every failure mode.Test plan
Target release: 0.8.2 (patch — additive).
🤖 Generated with Claude Code