Added httpx.BaseTransport
and httpx.AsyncBaseTransport
.
#1515
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.
We have a little niggle in our API. Almost all the way through
httpcore
is treated as an implementation detail, that just happens to be used by the default transport implementation,httpx.HTTPTransport
.The one place where this isn't the case is in our "Transport API". In that case we're explicitly documenting "subclass httpcore.SyncHTTPTransport and implement it's API".
To make this clearer, here's how the "custom transports" docs look after this change...
Writing custom transports
A transport instance must implement the low-level Transport API, which deals
with sending a single request, and returning a response. You should either
subclass
httpx.BaseTransport
to implement a transport to use withClient
,or subclass
httpx.AsyncBaseTransport
to implement a transport touse with
AsyncClient
.A complete example of a custom transport implementation would be:
Which we can use in the same way:
I do have some further thoughts on progressing on from this point, but from a review perspective we probably want to treat this in isolation.
Nonetheless, I think the potential follow through points are worth talking through...
.close()
method at thehttpcore
level, but which makes for an awkward base.request()
signature. A neater alternative would be to switch to havingclose
be an optional key on the returnedext
dict. Then request and response streams are just plain old byte iterables. Yay. (There's a couple of type: ignores in this PR that sweep this under the table.)handle_request(...)
instead ofrequest(...)
. Why? Because then we could implement a couple of convenience methods on the base classes, allowing for easy usage of sending a single request with a transport. Eg...This kinda gives us the best of both worlds, of having a strict low-level point in the API where all the request/response models drop away to plain primitives, while also being able to use transports directly. (Which for the purposes of debugging, narrowing down issues etc. is actually super useful. Especially if we start doing a really good job in
__repr__
of showing exactly which transports are mounted on a client, and exactly what configuration each transport has setup.)HTTPCORE_EXC_MAP
out of the client, and strictly inside thehttpx.HTTPTransport
implementation, which is nice from the perspective of getting any reference to httpcore entirely out ofhttpx
, except in the sole case of the concretehttpx.HTTPTransport
implementation. Not worth discussing the details of that tweak here.httpx.BaseTransport
API in either case, because I think this way around feels more user-centred regardless of if we had a close-callback or a context-managed API. (Tho would need to take another look at the streaming case forASGITransport
?)Either ways. This particular PR rubs out one of our last sets of API niggles, and necessarily put us on path for a 0.18.x series, which I think would be the last prior to a 1.0 release.