From 4f8068a7ade1f4d10403e325ed2354109df1724f Mon Sep 17 00:00:00 2001 From: toppk Date: Tue, 8 Feb 2022 09:58:08 -0500 Subject: [PATCH] update docstring/docs for transport using request/response models (#2070) * update docstring/docs for transport based on pull #1840 * Update httpx/_transports/base.py * lint'd Co-authored-by: Tom Christie --- docs/advanced.md | 11 +++---- httpx/_transports/base.py | 65 ++++++++++----------------------------- 2 files changed, 21 insertions(+), 55 deletions(-) diff --git a/docs/advanced.md b/docs/advanced.md index 58eb29dab9..631cc4634d 100644 --- a/docs/advanced.md +++ b/docs/advanced.md @@ -1051,10 +1051,8 @@ subclass `httpx.BaseTransport` to implement a transport to use with `Client`, or subclass `httpx.AsyncBaseTransport` to implement a transport to use with `AsyncClient`. -At the layer of the transport API we're using plain primitives. -No `Request` or `Response` models, no fancy `URL` or `Header` handling. -This strict point of cut-off provides a clear design separation between the -HTTPX API, and the low-level network handling. +At the layer of the transport API we're using the familiar `Request` and +`Response` models. See the `handle_request` and `handle_async_request` docstrings for more details on the specifics of the Transport API. @@ -1071,13 +1069,12 @@ class HelloWorldTransport(httpx.BaseTransport): A mock transport that always returns a JSON "Hello, world!" response. """ - def handle_request(self, method, url, headers, stream, extensions): + def handle_request(self, request): message = {"text": "Hello, world!"} content = json.dumps(message).encode("utf-8") stream = httpx.ByteStream(content) headers = [(b"content-type", b"application/json")] - extensions = {} - return 200, headers, stream, extensions + return httpx.Response(200, headers=headers, stream=stream) ``` Which we can use in the same way: diff --git a/httpx/_transports/base.py b/httpx/_transports/base.py index ed3502e948..e5e3283c16 100644 --- a/httpx/_transports/base.py +++ b/httpx/_transports/base.py @@ -23,63 +23,32 @@ def handle_request(self, request: Request) -> Response: """ Send a single HTTP request and return a response. - At this layer of API we're simply using plain primitives. No `Request` or - `Response` models, no fancy `URL` or `Header` handling. This strict point - of cut-off provides a clear design separation between the HTTPX API, - and the low-level network handling. - Developers shouldn't typically ever need to call into this API directly, since the Client class provides all the higher level user-facing API niceties. - In order to properly release any network resources, the response stream - should *either* be consumed immediately, with a call to `stream.read()`, - or else the `handle_request` call should be followed with a try/finally - block to ensuring the stream is always closed. + In order to properly release any network resources, the response + stream should *either* be consumed immediately, with a call to + `response.stream.read()`, or else the `handle_request` call should + be followed with a try/finally block to ensuring the stream is + always closed. Example usage: with httpx.HTTPTransport() as transport: - status_code, headers, stream, extensions = transport.handle_request( - method=b'GET', - url=(b'https', b'www.example.com', 443, b'/'), - headers=[(b'Host', b'www.example.com')], - stream=[], - extensions={} + req = httpx.Request( + method=b"GET", + url=(b"https", b"www.example.com", 443, b"/"), + headers=[(b"Host", b"www.example.com")], ) - body = stream.read() - print(status_code, headers, body) - - Arguments: - - method: The request method as bytes. Eg. b'GET'. - url: The components of the request URL, as a tuple of `(scheme, host, port, target)`. - The target will usually be the URL path, but also allows for alternative - formulations, such as proxy requests which include the complete URL in - the target portion of the HTTP request, or for "OPTIONS *" requests, which - cannot be expressed in a URL string. - headers: The request headers as a list of byte pairs. - stream: The request body as a bytes iterator. - extensions: An open ended dictionary, including optional extensions to the - core request/response API. Keys may include: - timeout: A dictionary of str:Optional[float] timeout values. - May include values for 'connect', 'read', 'write', or 'pool'. - - Returns a tuple of: - - status_code: The response status code as an integer. Should be in the range 1xx-5xx. - headers: The response headers as a list of byte pairs. - stream: The response body as a bytes iterator. - extensions: An open ended dictionary, including optional extensions to the - core request/response API. Keys are plain strings, and may include: - reason_phrase: The reason-phrase of the HTTP response, as bytes. Eg b'OK'. - HTTP/2 onwards does not include a reason phrase on the wire. - When no key is included, a default based on the status code may - be used. An empty-string reason phrase should not be substituted - for a default, as it indicates the server left the portion blank - eg. the leading response bytes were b"HTTP/1.1 200 ". - http_version: The HTTP version, as bytes. Eg. b"HTTP/1.1". - When no http_version key is included, HTTP/1.1 may be assumed. + resp = transport.handle_request(req) + body = resp.stream.read() + print(resp.status_code, resp.headers, body) + + + Takes a `Request` instance as the only argument. + + Returns a `Response` instance. """ raise NotImplementedError( "The 'handle_request' method must be implemented."