Repository navigation
fix: map InvalidURL in build_request; clear TypeError for sync-stream middleware responses - #189
Merged
Merged
Conversation
… middleware responses build_request on both clients now raises TransportError for an invalid URL, with the httpx2.InvalidURL as __cause__, like every other entry point. When AsyncClient middleware returns an unread response with a sync stream, send() and send_with_response() raise a TypeError that names the problem instead of the RuntimeError from inside httpx2. Client gets the mirror check for an async-stream response, which used to surface as a DecodeError. Closes #175 Closes #176
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.
What changed
#175.
Client.build_requestandAsyncClient.build_requestnow raiseTransportErrorfor an invalid URL, with thehttpx2.InvalidURLas__cause__. The verb methods,request()and the*_with_responsemethods already did this. Thetry/except InvalidURLthat lived in both_prepare_requestmethods has moved into the shared_build_requesthelper, so all four call sites go through one mapping viamap_httpx2_exception.stream()also calls_build_requestand raisedTransportErrorbefore this change too, because its outerexcept MAPPED_HTTPX2_ERRORScaught the raw error. Thebuild_requestdocstrings now say what an invalid URL raises.docs/errors.mdalready says an invalid URL raisesTransportErrorfrom every method, and that is now true.#176. When
AsyncClientmiddleware returns an unread response whose stream is not anhttpx2.AsyncByteStream,send()andsend_with_response()(and so every verb withresponse_model) raise:The check runs before
await response.aread(). Before this change the caller gotRuntimeError: Attempted to call an async iterator on a sync stream.from inside httpx2.httpx2.AsyncByteStreamandhttpx2.SyncByteStreamare both public exports.ByteStream(whatcontent=b"..."produces) subclasses both, so in-memory bodies pass either check.Sync mirror.
Clienthas the same problem in a different form. A sync middleware returning a response built from an async iterator reached_BoundDecoder.decode, whoseresponse.read()raisedRuntimeError: Attempted to call a sync iterator on an async stream., which got wrapped asDecodeError. That pointed at the decoder, though the decoder had nothing to do with it.Client._sendand_send_with_responsenow raise the mirroredTypeError("Client middleware returned a response with an async stream; Client middleware must return sync-streamed responses"). A test also pins the existing behaviour that an unread sync-stream response from sync middleware still decodes.docs/middleware.mdgets one paragraph about this next to the existing sync/async middleware rule.Performance
Both checks sit behind
if not response.is_closed. A response from httpx2's ownsend()(not streamed) and one built withcontent=bytesare already closed, so theisinstanceonly runs for unread middleware-built responses. On the async side the guard was already there. On the sync side it adds one attribute read per decoded request (about 7 ns on its own intimeit).Mocked
get("/", response_model=dict)overhttpx2.MockTransport, 20k calls x 7 rounds, min per call:AsyncClientClient(two runs each.) The differences are within noise.
Closes #175
Closes #176