15 |
16 | HTTPX is a fully featured HTTP client library for Python 3. It includes **an integrated command line client**, has support for both **HTTP/1.1 and HTTP/2**, and provides both **sync and async APIs**.
17 |
18 | ---
19 |
20 | Install HTTPX using pip:
21 |
22 | ```shell
23 | $ pip install httpx
24 | ```
25 |
26 | Now, let's get started:
27 |
28 | ```pycon
29 | >>> import httpx
30 | >>> r = httpx.get('https://www.example.org/')
31 | >>> r
32 |
33 | >>> r.status_code
34 | 200
35 | >>> r.headers['content-type']
36 | 'text/html; charset=UTF-8'
37 | >>> r.text
38 | '\n\n\nExample Domain...'
39 | ```
40 |
41 | Or, using the command-line client.
42 |
43 | ```shell
44 | $ pip install 'httpx[cli]' # The command line client is an optional dependency.
45 | ```
46 |
47 | Which now allows us to use HTTPX directly from the command-line...
48 |
49 |
50 |
51 |
52 |
53 | Sending a request...
54 |
55 |
56 |
57 |
58 |
59 | ## Features
60 |
61 | HTTPX builds on the well-established usability of `requests`, and gives you:
62 |
63 | * A broadly [requests-compatible API](https://www.python-httpx.org/compatibility/).
64 | * An integrated command-line client.
65 | * HTTP/1.1 [and HTTP/2 support](https://www.python-httpx.org/http2/).
66 | * Standard synchronous interface, but with [async support if you need it](https://www.python-httpx.org/async/).
67 | * Ability to make requests directly to [WSGI applications](https://www.python-httpx.org/advanced/transports/#wsgi-transport) or [ASGI applications](https://www.python-httpx.org/advanced/transports/#asgi-transport).
68 | * Strict timeouts everywhere.
69 | * Fully type annotated.
70 | * 100% test coverage.
71 |
72 | Plus all the standard features of `requests`...
73 |
74 | * International Domains and URLs
75 | * Keep-Alive & Connection Pooling
76 | * Sessions with Cookie Persistence
77 | * Browser-style SSL Verification
78 | * Basic/Digest Authentication
79 | * Elegant Key/Value Cookies
80 | * Automatic Decompression
81 | * Automatic Content Decoding
82 | * Unicode Response Bodies
83 | * Multipart File Uploads
84 | * HTTP(S) Proxy Support
85 | * Connection Timeouts
86 | * Streaming Downloads
87 | * .netrc Support
88 | * Chunked Requests
89 |
90 | ## Installation
91 |
92 | Install with pip:
93 |
94 | ```shell
95 | $ pip install httpx
96 | ```
97 |
98 | Or, to include the optional HTTP/2 support, use:
99 |
100 | ```shell
101 | $ pip install httpx[http2]
102 | ```
103 |
104 | HTTPX requires Python 3.8+.
105 |
106 | ## Documentation
107 |
108 | Project documentation is available at [https://www.python-httpx.org/](https://www.python-httpx.org/).
109 |
110 | For a run-through of all the basics, head over to the [QuickStart](https://www.python-httpx.org/quickstart/).
111 |
112 | For more advanced topics, see the [Advanced Usage](https://www.python-httpx.org/advanced/) section, the [async support](https://www.python-httpx.org/async/) section, or the [HTTP/2](https://www.python-httpx.org/http2/) section.
113 |
114 | The [Developer Interface](https://www.python-httpx.org/api/) provides a comprehensive API reference.
115 |
116 | To find out about tools that integrate with HTTPX, see [Third Party Packages](https://www.python-httpx.org/third_party_packages/).
117 |
118 | ## Contribute
119 |
120 | If you want to contribute with HTTPX check out the [Contributing Guide](https://www.python-httpx.org/contributing/) to learn how to start.
121 |
122 | ## Dependencies
123 |
124 | The HTTPX project relies on these excellent libraries:
125 |
126 | * `httpcore` - The underlying transport implementation for `httpx`.
127 | * `h11` - HTTP/1.1 support.
128 | * `certifi` - SSL certificates.
129 | * `idna` - Internationalized domain name support.
130 | * `sniffio` - Async library autodetection.
131 |
132 | As well as these optional installs:
133 |
134 | * `h2` - HTTP/2 support. *(Optional, with `httpx[http2]`)*
135 | * `socksio` - SOCKS proxy support. *(Optional, with `httpx[socks]`)*
136 | * `rich` - Rich terminal support. *(Optional, with `httpx[cli]`)*
137 | * `click` - Command line client support. *(Optional, with `httpx[cli]`)*
138 | * `brotli` or `brotlicffi` - Decoding for "brotli" compressed responses. *(Optional, with `httpx[brotli]`)*
139 | * `zstandard` - Decoding for "zstd" compressed responses. *(Optional, with `httpx[zstd]`)*
140 |
141 | A huge amount of credit is due to `requests` for the API layout that
142 | much of this work follows, as well as to `urllib3` for plenty of design
143 | inspiration around the lower-level networking details.
144 |
145 | ---
146 |
147 |
HTTPX is BSD licensed code. Designed & crafted with care. — 🦋 —
148 |
--------------------------------------------------------------------------------
/docs/CNAME:
--------------------------------------------------------------------------------
1 | www.python-httpx.org
2 |
--------------------------------------------------------------------------------
/docs/advanced/event-hooks.md:
--------------------------------------------------------------------------------
1 | HTTPX allows you to register "event hooks" with the client, that are called
2 | every time a particular type of event takes place.
3 |
4 | There are currently two event hooks:
5 |
6 | * `request` - Called after a request is fully prepared, but before it is sent to the network. Passed the `request` instance.
7 | * `response` - Called after the response has been fetched from the network, but before it is returned to the caller. Passed the `response` instance.
8 |
9 | These allow you to install client-wide functionality such as logging, monitoring or tracing.
10 |
11 | ```python
12 | def log_request(request):
13 | print(f"Request event hook: {request.method} {request.url} - Waiting for response")
14 |
15 | def log_response(response):
16 | request = response.request
17 | print(f"Response event hook: {request.method} {request.url} - Status {response.status_code}")
18 |
19 | client = httpx.Client(event_hooks={'request': [log_request], 'response': [log_response]})
20 | ```
21 |
22 | You can also use these hooks to install response processing code, such as this
23 | example, which creates a client instance that always raises `httpx.HTTPStatusError`
24 | on 4xx and 5xx responses.
25 |
26 | ```python
27 | def raise_on_4xx_5xx(response):
28 | response.raise_for_status()
29 |
30 | client = httpx.Client(event_hooks={'response': [raise_on_4xx_5xx]})
31 | ```
32 |
33 | !!! note
34 | Response event hooks are called before determining if the response body
35 | should be read or not.
36 |
37 | If you need access to the response body inside an event hook, you'll
38 | need to call `response.read()`, or for AsyncClients, `response.aread()`.
39 |
40 | The hooks are also allowed to modify `request` and `response` objects.
41 |
42 | ```python
43 | def add_timestamp(request):
44 | request.headers['x-request-timestamp'] = datetime.now(tz=datetime.utc).isoformat()
45 |
46 | client = httpx.Client(event_hooks={'request': [add_timestamp]})
47 | ```
48 |
49 | Event hooks must always be set as a **list of callables**, and you may register
50 | multiple event hooks for each type of event.
51 |
52 | As well as being able to set event hooks on instantiating the client, there
53 | is also an `.event_hooks` property, that allows you to inspect and modify
54 | the installed hooks.
55 |
56 | ```python
57 | client = httpx.Client()
58 | client.event_hooks['request'] = [log_request]
59 | client.event_hooks['response'] = [log_response, raise_on_4xx_5xx]
60 | ```
61 |
62 | !!! note
63 | If you are using HTTPX's async support, then you need to be aware that
64 | hooks registered with `httpx.AsyncClient` MUST be async functions,
65 | rather than plain functions.
66 |
--------------------------------------------------------------------------------
/docs/advanced/proxies.md:
--------------------------------------------------------------------------------
1 | HTTPX supports setting up [HTTP proxies](https://en.wikipedia.org/wiki/Proxy_server#Web_proxy_servers) via the `proxy` parameter to be passed on client initialization or top-level API functions like `httpx.get(..., proxy=...)`.
2 |
3 |
4 |
5 | Diagram of how a proxy works (source: Wikipedia). The left hand side "Internet" blob may be your HTTPX client requesting example.com through a proxy.
6 |
7 |
8 | ## HTTP Proxies
9 |
10 | To route all traffic (HTTP and HTTPS) to a proxy located at `http://localhost:8030`, pass the proxy URL to the client...
11 |
12 | ```python
13 | with httpx.Client(proxy="http://localhost:8030") as client:
14 | ...
15 | ```
16 |
17 | For more advanced use cases, pass a mounts `dict`. For example, to route HTTP and HTTPS requests to 2 different proxies, respectively located at `http://localhost:8030`, and `http://localhost:8031`, pass a `dict` of proxy URLs:
18 |
19 | ```python
20 | proxy_mounts = {
21 | "http://": httpx.HTTPTransport(proxy="http://localhost:8030"),
22 | "https://": httpx.HTTPTransport(proxy="http://localhost:8031"),
23 | }
24 |
25 | with httpx.Client(mounts=proxy_mounts) as client:
26 | ...
27 | ```
28 |
29 | For detailed information about proxy routing, see the [Routing](#routing) section.
30 |
31 | !!! tip "Gotcha"
32 | In most cases, the proxy URL for the `https://` key _should_ use the `http://` scheme (that's not a typo!).
33 |
34 | This is because HTTP proxying requires initiating a connection with the proxy server. While it's possible that your proxy supports doing it via HTTPS, most proxies only support doing it via HTTP.
35 |
36 | For more information, see [FORWARD vs TUNNEL](#forward-vs-tunnel).
37 |
38 | ## Authentication
39 |
40 | Proxy credentials can be passed as the `userinfo` section of the proxy URL. For example:
41 |
42 | ```python
43 | with httpx.Client(proxy="http://username:password@localhost:8030") as client:
44 | ...
45 | ```
46 |
47 | ## Proxy mechanisms
48 |
49 | !!! note
50 | This section describes **advanced** proxy concepts and functionality.
51 |
52 | ### FORWARD vs TUNNEL
53 |
54 | In general, the flow for making an HTTP request through a proxy is as follows:
55 |
56 | 1. The client connects to the proxy (initial connection request).
57 | 2. The proxy transfers data to the server on your behalf.
58 |
59 | How exactly step 2/ is performed depends on which of two proxying mechanisms is used:
60 |
61 | * **Forwarding**: the proxy makes the request for you, and sends back the response it obtained from the server.
62 | * **Tunnelling**: the proxy establishes a TCP connection to the server on your behalf, and the client reuses this connection to send the request and receive the response. This is known as an [HTTP Tunnel](https://en.wikipedia.org/wiki/HTTP_tunnel). This mechanism is how you can access websites that use HTTPS from an HTTP proxy (the client "upgrades" the connection to HTTPS by performing the TLS handshake with the server over the TCP connection provided by the proxy).
63 |
64 | ### Troubleshooting proxies
65 |
66 | If you encounter issues when setting up proxies, please refer to our [Troubleshooting guide](../troubleshooting.md#proxies).
67 |
68 | ## SOCKS
69 |
70 | In addition to HTTP proxies, `httpcore` also supports proxies using the SOCKS protocol.
71 | This is an optional feature that requires an additional third-party library be installed before use.
72 |
73 | You can install SOCKS support using `pip`:
74 |
75 | ```shell
76 | $ pip install httpx[socks]
77 | ```
78 |
79 | You can now configure a client to make requests via a proxy using the SOCKS protocol:
80 |
81 | ```python
82 | httpx.Client(proxy='socks5://user:pass@host:port')
83 | ```
84 |
--------------------------------------------------------------------------------
/docs/advanced/resource-limits.md:
--------------------------------------------------------------------------------
1 | You can control the connection pool size using the `limits` keyword
2 | argument on the client. It takes instances of `httpx.Limits` which define:
3 |
4 | - `max_keepalive_connections`, number of allowable keep-alive connections, or `None` to always
5 | allow. (Defaults 20)
6 | - `max_connections`, maximum number of allowable connections, or `None` for no limits.
7 | (Default 100)
8 | - `keepalive_expiry`, time limit on idle keep-alive connections in seconds, or `None` for no limits. (Default 5)
9 |
10 | ```python
11 | limits = httpx.Limits(max_keepalive_connections=5, max_connections=10)
12 | client = httpx.Client(limits=limits)
13 | ```
--------------------------------------------------------------------------------
/docs/advanced/ssl.md:
--------------------------------------------------------------------------------
1 | When making a request over HTTPS, HTTPX needs to verify the identity of the requested host. To do this, it uses a bundle of SSL certificates (a.k.a. CA bundle) delivered by a trusted certificate authority (CA).
2 |
3 | ### Enabling and disabling verification
4 |
5 | By default httpx will verify HTTPS connections, and raise an error for invalid SSL cases...
6 |
7 | ```pycon
8 | >>> httpx.get("https://expired.badssl.com/")
9 | httpx.ConnectError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: certificate has expired (_ssl.c:997)
10 | ```
11 |
12 | You can disable SSL verification completely and allow insecure requests...
13 |
14 | ```pycon
15 | >>> httpx.get("https://expired.badssl.com/", verify=False)
16 |
17 | ```
18 |
19 | ### Configuring client instances
20 |
21 | If you're using a `Client()` instance you should pass any `verify=<...>` configuration when instantiating the client.
22 |
23 | By default the [certifi CA bundle](https://certifiio.readthedocs.io/en/latest/) is used for SSL verification.
24 |
25 | For more complex configurations you can pass an [SSL Context](https://docs.python.org/3/library/ssl.html) instance...
26 |
27 | ```python
28 | import certifi
29 | import httpx
30 | import ssl
31 |
32 | # This SSL context is equivelent to the default `verify=True`.
33 | ctx = ssl.create_default_context(cafile=certifi.where())
34 | client = httpx.Client(verify=ctx)
35 | ```
36 |
37 | Using [the `truststore` package](https://truststore.readthedocs.io/) to support system certificate stores...
38 |
39 | ```python
40 | import ssl
41 | import truststore
42 | import httpx
43 |
44 | # Use system certificate stores.
45 | ctx = truststore.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
46 | client = httpx.Client(verify=ctx)
47 | ```
48 |
49 | Loding an alternative certificate verification store using [the standard SSL context API](https://docs.python.org/3/library/ssl.html)...
50 |
51 | ```python
52 | import httpx
53 | import ssl
54 |
55 | # Use an explicitly configured certificate store.
56 | ctx = ssl.create_default_context(cafile="path/to/certs.pem") # Either cafile or capath.
57 | client = httpx.Client(verify=ctx)
58 | ```
59 |
60 | ### Client side certificates
61 |
62 | Client side certificates allow a remote server to verify the client. They tend to be used within private organizations to authenticate requests to remote servers.
63 |
64 | You can specify client-side certificates, using the [`.load_cert_chain()`](https://docs.python.org/3/library/ssl.html#ssl.SSLContext.load_cert_chain) API...
65 |
66 | ```python
67 | ctx = ssl.create_default_context()
68 | ctx.load_cert_chain(certfile="path/to/client.pem") # Optionally also keyfile or password.
69 | client = httpx.Client(verify=ctx)
70 | ```
71 |
72 | ### Working with `SSL_CERT_FILE` and `SSL_CERT_DIR`
73 |
74 | Unlike `requests`, the `httpx` package does not automatically pull in [the environment variables `SSL_CERT_FILE` or `SSL_CERT_DIR`](https://www.openssl.org/docs/manmaster/man3/SSL_CTX_set_default_verify_paths.html). If you want to use these they need to be enabled explicitly.
75 |
76 | For example...
77 |
78 | ```python
79 | # Use `SSL_CERT_FILE` or `SSL_CERT_DIR` if configured.
80 | # Otherwise default to certifi.
81 | ctx = ssl.create_default_context(
82 | cafile=os.environ.get("SSL_CERT_FILE", certifi.where()),
83 | capath=os.environ.get("SSL_CERT_DIR"),
84 | )
85 | client = httpx.Client(verify=ctx)
86 | ```
87 |
88 | ### Making HTTPS requests to a local server
89 |
90 | When making requests to local servers, such as a development server running on `localhost`, you will typically be using unencrypted HTTP connections.
91 |
92 | If you do need to make HTTPS connections to a local server, for example to test an HTTPS-only service, you will need to create and use your own certificates. Here's one way to do it...
93 |
94 | 1. Use [trustme](https://github.com/python-trio/trustme) to generate a pair of server key/cert files, and a client cert file.
95 | 2. Pass the server key/cert files when starting your local server. (This depends on the particular web server you're using. For example, [Uvicorn](https://www.uvicorn.org) provides the `--ssl-keyfile` and `--ssl-certfile` options.)
96 | 3. Configure `httpx` to use the certificates stored in `client.pem`.
97 |
98 | ```python
99 | ctx = ssl.create_default_context(cafile="client.pem")
100 | client = httpx.Client(verify=ctx)
101 | ```
102 |
--------------------------------------------------------------------------------
/docs/advanced/text-encodings.md:
--------------------------------------------------------------------------------
1 | When accessing `response.text`, we need to decode the response bytes into a unicode text representation.
2 |
3 | By default `httpx` will use `"charset"` information included in the response `Content-Type` header to determine how the response bytes should be decoded into text.
4 |
5 | In cases where no charset information is included on the response, the default behaviour is to assume "utf-8" encoding, which is by far the most widely used text encoding on the internet.
6 |
7 | ## Using the default encoding
8 |
9 | To understand this better let's start by looking at the default behaviour for text decoding...
10 |
11 | ```python
12 | import httpx
13 | # Instantiate a client with the default configuration.
14 | client = httpx.Client()
15 | # Using the client...
16 | response = client.get(...)
17 | print(response.encoding) # This will either print the charset given in
18 | # the Content-Type charset, or else "utf-8".
19 | print(response.text) # The text will either be decoded with the Content-Type
20 | # charset, or using "utf-8".
21 | ```
22 |
23 | This is normally absolutely fine. Most servers will respond with a properly formatted Content-Type header, including a charset encoding. And in most cases where no charset encoding is included, UTF-8 is very likely to be used, since it is so widely adopted.
24 |
25 | ## Using an explicit encoding
26 |
27 | In some cases we might be making requests to a site where no character set information is being set explicitly by the server, but we know what the encoding is. In this case it's best to set the default encoding explicitly on the client.
28 |
29 | ```python
30 | import httpx
31 | # Instantiate a client with a Japanese character set as the default encoding.
32 | client = httpx.Client(default_encoding="shift-jis")
33 | # Using the client...
34 | response = client.get(...)
35 | print(response.encoding) # This will either print the charset given in
36 | # the Content-Type charset, or else "shift-jis".
37 | print(response.text) # The text will either be decoded with the Content-Type
38 | # charset, or using "shift-jis".
39 | ```
40 |
41 | ## Using auto-detection
42 |
43 | In cases where the server is not reliably including character set information, and where we don't know what encoding is being used, we can enable auto-detection to make a best-guess attempt when decoding from bytes to text.
44 |
45 | To use auto-detection you need to set the `default_encoding` argument to a callable instead of a string. This callable should be a function which takes the input bytes as an argument and returns the character set to use for decoding those bytes to text.
46 |
47 | There are two widely used Python packages which both handle this functionality:
48 |
49 | * [`chardet`](https://chardet.readthedocs.io/) - This is a well established package, and is a port of [the auto-detection code in Mozilla](https://www-archive.mozilla.org/projects/intl/chardet.html).
50 | * [`charset-normalizer`](https://charset-normalizer.readthedocs.io/) - A newer package, motivated by `chardet`, with a different approach.
51 |
52 | Let's take a look at installing autodetection using one of these packages...
53 |
54 | ```shell
55 | $ pip install httpx
56 | $ pip install chardet
57 | ```
58 |
59 | Once `chardet` is installed, we can configure a client to use character-set autodetection.
60 |
61 | ```python
62 | import httpx
63 | import chardet
64 |
65 | def autodetect(content):
66 | return chardet.detect(content).get("encoding")
67 |
68 | # Using a client with character-set autodetection enabled.
69 | client = httpx.Client(default_encoding=autodetect)
70 | response = client.get(...)
71 | print(response.encoding) # This will either print the charset given in
72 | # the Content-Type charset, or else the auto-detected
73 | # character set.
74 | print(response.text)
75 | ```
76 |
--------------------------------------------------------------------------------
/docs/advanced/timeouts.md:
--------------------------------------------------------------------------------
1 | HTTPX is careful to enforce timeouts everywhere by default.
2 |
3 | The default behavior is to raise a `TimeoutException` after 5 seconds of
4 | network inactivity.
5 |
6 | ## Setting and disabling timeouts
7 |
8 | You can set timeouts for an individual request:
9 |
10 | ```python
11 | # Using the top-level API:
12 | httpx.get('http://example.com/api/v1/example', timeout=10.0)
13 |
14 | # Using a client instance:
15 | with httpx.Client() as client:
16 | client.get("http://example.com/api/v1/example", timeout=10.0)
17 | ```
18 |
19 | Or disable timeouts for an individual request:
20 |
21 | ```python
22 | # Using the top-level API:
23 | httpx.get('http://example.com/api/v1/example', timeout=None)
24 |
25 | # Using a client instance:
26 | with httpx.Client() as client:
27 | client.get("http://example.com/api/v1/example", timeout=None)
28 | ```
29 |
30 | ## Setting a default timeout on a client
31 |
32 | You can set a timeout on a client instance, which results in the given
33 | `timeout` being used as the default for requests made with this client:
34 |
35 | ```python
36 | client = httpx.Client() # Use a default 5s timeout everywhere.
37 | client = httpx.Client(timeout=10.0) # Use a default 10s timeout everywhere.
38 | client = httpx.Client(timeout=None) # Disable all timeouts by default.
39 | ```
40 |
41 | ## Fine tuning the configuration
42 |
43 | HTTPX also allows you to specify the timeout behavior in more fine grained detail.
44 |
45 | There are four different types of timeouts that may occur. These are **connect**,
46 | **read**, **write**, and **pool** timeouts.
47 |
48 | * The **connect** timeout specifies the maximum amount of time to wait until
49 | a socket connection to the requested host is established. If HTTPX is unable to connect
50 | within this time frame, a `ConnectTimeout` exception is raised.
51 | * The **read** timeout specifies the maximum duration to wait for a chunk of
52 | data to be received (for example, a chunk of the response body). If HTTPX is
53 | unable to receive data within this time frame, a `ReadTimeout` exception is raised.
54 | * The **write** timeout specifies the maximum duration to wait for a chunk of
55 | data to be sent (for example, a chunk of the request body). If HTTPX is unable
56 | to send data within this time frame, a `WriteTimeout` exception is raised.
57 | * The **pool** timeout specifies the maximum duration to wait for acquiring
58 | a connection from the connection pool. If HTTPX is unable to acquire a connection
59 | within this time frame, a `PoolTimeout` exception is raised. A related
60 | configuration here is the maximum number of allowable connections in the
61 | connection pool, which is configured by the `limits` argument.
62 |
63 | You can configure the timeout behavior for any of these values...
64 |
65 | ```python
66 | # A client with a 60s timeout for connecting, and a 10s timeout elsewhere.
67 | timeout = httpx.Timeout(10.0, connect=60.0)
68 | client = httpx.Client(timeout=timeout)
69 |
70 | response = client.get('http://example.com/')
71 | ```
--------------------------------------------------------------------------------
/docs/api.md:
--------------------------------------------------------------------------------
1 | # Developer Interface
2 |
3 | ## Helper Functions
4 |
5 | !!! note
6 | Only use these functions if you're testing HTTPX in a console
7 | or making a small number of requests. Using a `Client` will
8 | enable HTTP/2 and connection pooling for more efficient and
9 | long-lived connections.
10 |
11 | ::: httpx.request
12 | :docstring:
13 |
14 | ::: httpx.get
15 | :docstring:
16 |
17 | ::: httpx.options
18 | :docstring:
19 |
20 | ::: httpx.head
21 | :docstring:
22 |
23 | ::: httpx.post
24 | :docstring:
25 |
26 | ::: httpx.put
27 | :docstring:
28 |
29 | ::: httpx.patch
30 | :docstring:
31 |
32 | ::: httpx.delete
33 | :docstring:
34 |
35 | ::: httpx.stream
36 | :docstring:
37 |
38 | ## `Client`
39 |
40 | ::: httpx.Client
41 | :docstring:
42 | :members: headers cookies params auth request get head options post put patch delete stream build_request send close
43 |
44 | ## `AsyncClient`
45 |
46 | ::: httpx.AsyncClient
47 | :docstring:
48 | :members: headers cookies params auth request get head options post put patch delete stream build_request send aclose
49 |
50 |
51 | ## `Response`
52 |
53 | *An HTTP response.*
54 |
55 | * `def __init__(...)`
56 | * `.status_code` - **int**
57 | * `.reason_phrase` - **str**
58 | * `.http_version` - `"HTTP/2"` or `"HTTP/1.1"`
59 | * `.url` - **URL**
60 | * `.headers` - **Headers**
61 | * `.content` - **bytes**
62 | * `.text` - **str**
63 | * `.encoding` - **str**
64 | * `.is_redirect` - **bool**
65 | * `.request` - **Request**
66 | * `.next_request` - **Optional[Request]**
67 | * `.cookies` - **Cookies**
68 | * `.history` - **List[Response]**
69 | * `.elapsed` - **[timedelta](https://docs.python.org/3/library/datetime.html)**
70 | * The amount of time elapsed between sending the request and calling `close()` on the corresponding response received for that request.
71 | [total_seconds()](https://docs.python.org/3/library/datetime.html#datetime.timedelta.total_seconds) to correctly get
72 | the total elapsed seconds.
73 | * `def .raise_for_status()` - **Response**
74 | * `def .json()` - **Any**
75 | * `def .read()` - **bytes**
76 | * `def .iter_raw([chunk_size])` - **bytes iterator**
77 | * `def .iter_bytes([chunk_size])` - **bytes iterator**
78 | * `def .iter_text([chunk_size])` - **text iterator**
79 | * `def .iter_lines()` - **text iterator**
80 | * `def .close()` - **None**
81 | * `def .next()` - **Response**
82 | * `def .aread()` - **bytes**
83 | * `def .aiter_raw([chunk_size])` - **async bytes iterator**
84 | * `def .aiter_bytes([chunk_size])` - **async bytes iterator**
85 | * `def .aiter_text([chunk_size])` - **async text iterator**
86 | * `def .aiter_lines()` - **async text iterator**
87 | * `def .aclose()` - **None**
88 | * `def .anext()` - **Response**
89 |
90 | ## `Request`
91 |
92 | *An HTTP request. Can be constructed explicitly for more control over exactly
93 | what gets sent over the wire.*
94 |
95 | ```pycon
96 | >>> request = httpx.Request("GET", "https://example.org", headers={'host': 'example.org'})
97 | >>> response = client.send(request)
98 | ```
99 |
100 | * `def __init__(method, url, [params], [headers], [cookies], [content], [data], [files], [json], [stream])`
101 | * `.method` - **str**
102 | * `.url` - **URL**
103 | * `.content` - **byte**, **byte iterator**, or **byte async iterator**
104 | * `.headers` - **Headers**
105 | * `.cookies` - **Cookies**
106 |
107 | ## `URL`
108 |
109 | *A normalized, IDNA supporting URL.*
110 |
111 | ```pycon
112 | >>> url = URL("https://example.org/")
113 | >>> url.host
114 | 'example.org'
115 | ```
116 |
117 | * `def __init__(url, **kwargs)`
118 | * `.scheme` - **str**
119 | * `.authority` - **str**
120 | * `.host` - **str**
121 | * `.port` - **int**
122 | * `.path` - **str**
123 | * `.query` - **str**
124 | * `.raw_path` - **str**
125 | * `.fragment` - **str**
126 | * `.is_ssl` - **bool**
127 | * `.is_absolute_url` - **bool**
128 | * `.is_relative_url` - **bool**
129 | * `def .copy_with([scheme], [authority], [path], [query], [fragment])` - **URL**
130 |
131 | ## `Headers`
132 |
133 | *A case-insensitive multi-dict.*
134 |
135 | ```pycon
136 | >>> headers = Headers({'Content-Type': 'application/json'})
137 | >>> headers['content-type']
138 | 'application/json'
139 | ```
140 |
141 | * `def __init__(self, headers, encoding=None)`
142 | * `def copy()` - **Headers**
143 |
144 | ## `Cookies`
145 |
146 | *A dict-like cookie store.*
147 |
148 | ```pycon
149 | >>> cookies = Cookies()
150 | >>> cookies.set("name", "value", domain="example.org")
151 | ```
152 |
153 | * `def __init__(cookies: [dict, Cookies, CookieJar])`
154 | * `.jar` - **CookieJar**
155 | * `def extract_cookies(response)`
156 | * `def set_cookie_header(request)`
157 | * `def set(name, value, [domain], [path])`
158 | * `def get(name, [domain], [path])`
159 | * `def delete(name, [domain], [path])`
160 | * `def clear([domain], [path])`
161 | * *Standard mutable mapping interface*
162 |
163 | ## `Proxy`
164 |
165 | *A configuration of the proxy server.*
166 |
167 | ```pycon
168 | >>> proxy = Proxy("http://proxy.example.com:8030")
169 | >>> client = Client(proxy=proxy)
170 | ```
171 |
172 | * `def __init__(url, [ssl_context], [auth], [headers])`
173 | * `.url` - **URL**
174 | * `.auth` - **tuple[str, str]**
175 | * `.headers` - **Headers**
176 | * `.ssl_context` - **SSLContext**
177 |
--------------------------------------------------------------------------------
/docs/async.md:
--------------------------------------------------------------------------------
1 | # Async Support
2 |
3 | HTTPX offers a standard synchronous API by default, but also gives you
4 | the option of an async client if you need it.
5 |
6 | Async is a concurrency model that is far more efficient than multi-threading,
7 | and can provide significant performance benefits and enable the use of
8 | long-lived network connections such as WebSockets.
9 |
10 | If you're working with an async web framework then you'll also want to use an
11 | async client for sending outgoing HTTP requests.
12 |
13 | ## Making Async requests
14 |
15 | To make asynchronous requests, you'll need an `AsyncClient`.
16 |
17 | ```pycon
18 | >>> async with httpx.AsyncClient() as client:
19 | ... r = await client.get('https://www.example.com/')
20 | ...
21 | >>> r
22 |
23 | ```
24 |
25 | !!! tip
26 | Use [IPython](https://ipython.readthedocs.io/en/stable/) or Python 3.8+ with `python -m asyncio` to try this code interactively, as they support executing `async`/`await` expressions in the console.
27 |
28 | ## API Differences
29 |
30 | If you're using an async client then there are a few bits of API that
31 | use async methods.
32 |
33 | ### Making requests
34 |
35 | The request methods are all async, so you should use `response = await client.get(...)` style for all of the following:
36 |
37 | * `AsyncClient.get(url, ...)`
38 | * `AsyncClient.options(url, ...)`
39 | * `AsyncClient.head(url, ...)`
40 | * `AsyncClient.post(url, ...)`
41 | * `AsyncClient.put(url, ...)`
42 | * `AsyncClient.patch(url, ...)`
43 | * `AsyncClient.delete(url, ...)`
44 | * `AsyncClient.request(method, url, ...)`
45 | * `AsyncClient.send(request, ...)`
46 |
47 | ### Opening and closing clients
48 |
49 | Use `async with httpx.AsyncClient()` if you want a context-managed client...
50 |
51 | ```python
52 | async with httpx.AsyncClient() as client:
53 | ...
54 | ```
55 |
56 | !!! warning
57 | In order to get the most benefit from connection pooling, make sure you're not instantiating multiple client instances - for example by using `async with` inside a "hot loop". This can be achieved either by having a single scoped client that's passed throughout wherever it's needed, or by having a single global client instance.
58 |
59 | Alternatively, use `await client.aclose()` if you want to close a client explicitly:
60 |
61 | ```python
62 | client = httpx.AsyncClient()
63 | ...
64 | await client.aclose()
65 | ```
66 |
67 | ### Streaming responses
68 |
69 | The `AsyncClient.stream(method, url, ...)` method is an async context block.
70 |
71 | ```pycon
72 | >>> client = httpx.AsyncClient()
73 | >>> async with client.stream('GET', 'https://www.example.com/') as response:
74 | ... async for chunk in response.aiter_bytes():
75 | ... ...
76 | ```
77 |
78 | The async response streaming methods are:
79 |
80 | * `Response.aread()` - For conditionally reading a response inside a stream block.
81 | * `Response.aiter_bytes()` - For streaming the response content as bytes.
82 | * `Response.aiter_text()` - For streaming the response content as text.
83 | * `Response.aiter_lines()` - For streaming the response content as lines of text.
84 | * `Response.aiter_raw()` - For streaming the raw response bytes, without applying content decoding.
85 | * `Response.aclose()` - For closing the response. You don't usually need this, since `.stream` block closes the response automatically on exit.
86 |
87 | For situations when context block usage is not practical, it is possible to enter "manual mode" by sending a [`Request` instance](advanced/clients.md#request-instances) using `client.send(..., stream=True)`.
88 |
89 | Example in the context of forwarding the response to a streaming web endpoint with [Starlette](https://www.starlette.io):
90 |
91 | ```python
92 | import httpx
93 | from starlette.background import BackgroundTask
94 | from starlette.responses import StreamingResponse
95 |
96 | client = httpx.AsyncClient()
97 |
98 | async def home(request):
99 | req = client.build_request("GET", "https://www.example.com/")
100 | r = await client.send(req, stream=True)
101 | return StreamingResponse(r.aiter_text(), background=BackgroundTask(r.aclose))
102 | ```
103 |
104 | !!! warning
105 | When using this "manual streaming mode", it is your duty as a developer to make sure that `Response.aclose()` is called eventually. Failing to do so would leave connections open, most likely resulting in resource leaks down the line.
106 |
107 | ### Streaming requests
108 |
109 | When sending a streaming request body with an `AsyncClient` instance, you should use an async bytes generator instead of a bytes generator:
110 |
111 | ```python
112 | async def upload_bytes():
113 | ... # yield byte content
114 |
115 | await client.post(url, content=upload_bytes())
116 | ```
117 |
118 | ### Explicit transport instances
119 |
120 | When instantiating a transport instance directly, you need to use `httpx.AsyncHTTPTransport`.
121 |
122 | For instance:
123 |
124 | ```pycon
125 | >>> import httpx
126 | >>> transport = httpx.AsyncHTTPTransport(retries=1)
127 | >>> async with httpx.AsyncClient(transport=transport) as client:
128 | >>> ...
129 | ```
130 |
131 | ## Supported async environments
132 |
133 | HTTPX supports either `asyncio` or `trio` as an async environment.
134 |
135 | It will auto-detect which of those two to use as the backend
136 | for socket operations and concurrency primitives.
137 |
138 | ### [AsyncIO](https://docs.python.org/3/library/asyncio.html)
139 |
140 | AsyncIO is Python's [built-in library](https://docs.python.org/3/library/asyncio.html)
141 | for writing concurrent code with the async/await syntax.
142 |
143 | ```python
144 | import asyncio
145 | import httpx
146 |
147 | async def main():
148 | async with httpx.AsyncClient() as client:
149 | response = await client.get('https://www.example.com/')
150 | print(response)
151 |
152 | asyncio.run(main())
153 | ```
154 |
155 | ### [Trio](https://github.com/python-trio/trio)
156 |
157 | Trio is [an alternative async library](https://trio.readthedocs.io/en/stable/),
158 | designed around the [the principles of structured concurrency](https://en.wikipedia.org/wiki/Structured_concurrency).
159 |
160 | ```python
161 | import httpx
162 | import trio
163 |
164 | async def main():
165 | async with httpx.AsyncClient() as client:
166 | response = await client.get('https://www.example.com/')
167 | print(response)
168 |
169 | trio.run(main)
170 | ```
171 |
172 | !!! important
173 | The `trio` package must be installed to use the Trio backend.
174 |
175 |
176 | ### [AnyIO](https://github.com/agronholm/anyio)
177 |
178 | AnyIO is an [asynchronous networking and concurrency library](https://anyio.readthedocs.io/) that works on top of either `asyncio` or `trio`. It blends in with native libraries of your chosen backend (defaults to `asyncio`).
179 |
180 | ```python
181 | import httpx
182 | import anyio
183 |
184 | async def main():
185 | async with httpx.AsyncClient() as client:
186 | response = await client.get('https://www.example.com/')
187 | print(response)
188 |
189 | anyio.run(main, backend='trio')
190 | ```
191 |
192 | ## Calling into Python Web Apps
193 |
194 | For details on calling directly into ASGI applications, see [the `ASGITransport` docs](../advanced/transports#asgitransport).
--------------------------------------------------------------------------------
/docs/code_of_conduct.md:
--------------------------------------------------------------------------------
1 | # Code of Conduct
2 |
3 | We expect contributors to our projects and online spaces to follow [the Python Software Foundation’s Code of Conduct](https://www.python.org/psf/conduct/).
4 |
5 | The Python community is made up of members from around the globe with a diverse set of skills, personalities, and experiences. It is through these differences that our community experiences great successes and continued growth. When you're working with members of the community, this Code of Conduct will help steer your interactions and keep Python a positive, successful, and growing community.
6 |
7 | ## Our Community
8 |
9 | Members of the Python community are **open, considerate, and respectful**. Behaviours that reinforce these values contribute to a positive environment, and include:
10 |
11 | * **Being open.** Members of the community are open to collaboration, whether it's on PEPs, patches, problems, or otherwise.
12 | * **Focusing on what is best for the community.** We're respectful of the processes set forth in the community, and we work within them.
13 | * **Acknowledging time and effort.** We're respectful of the volunteer efforts that permeate the Python community. We're thoughtful when addressing the efforts of others, keeping in mind that often times the labor was completed simply for the good of the community.
14 | * **Being respectful of differing viewpoints and experiences.** We're receptive to constructive comments and criticism, as the experiences and skill sets of other members contribute to the whole of our efforts.
15 | * **Showing empathy towards other community members.** We're attentive in our communications, whether in person or online, and we're tactful when approaching differing views.
16 | * **Being considerate.** Members of the community are considerate of their peers -- other Python users.
17 | * **Being respectful.** We're respectful of others, their positions, their skills, their commitments, and their efforts.
18 | * **Gracefully accepting constructive criticism.** When we disagree, we are courteous in raising our issues.
19 | * **Using welcoming and inclusive language.** We're accepting of all who wish to take part in our activities, fostering an environment where anyone can participate and everyone can make a difference.
20 |
21 | ## Our Standards
22 |
23 | Every member of our community has the right to have their identity respected. The Python community is dedicated to providing a positive experience for everyone, regardless of age, gender identity and expression, sexual orientation, disability, physical appearance, body size, ethnicity, nationality, race, or religion (or lack thereof), education, or socio-economic status.
24 |
25 | ## Inappropriate Behavior
26 |
27 | Examples of unacceptable behavior by participants include:
28 |
29 | * Harassment of any participants in any form
30 | * Deliberate intimidation, stalking, or following
31 | * Logging or taking screenshots of online activity for harassment purposes
32 | * Publishing others' private information, such as a physical or electronic address, without explicit permission
33 | * Violent threats or language directed against another person
34 | * Incitement of violence or harassment towards any individual, including encouraging a person to commit suicide or to engage in self-harm
35 | * Creating additional online accounts in order to harass another person or circumvent a ban
36 | * Sexual language and imagery in online communities or in any conference venue, including talks
37 | * Insults, put downs, or jokes that are based upon stereotypes, that are exclusionary, or that hold others up for ridicule
38 | * Excessive swearing
39 | * Unwelcome sexual attention or advances
40 | * Unwelcome physical contact, including simulated physical contact (eg, textual descriptions like "hug" or "backrub") without consent or after a request to stop
41 | * Pattern of inappropriate social contact, such as requesting/assuming inappropriate levels of intimacy with others
42 | * Sustained disruption of online community discussions, in-person presentations, or other in-person events
43 | * Continued one-on-one communication after requests to cease
44 | * Other conduct that is inappropriate for a professional audience including people of many different backgrounds
45 |
46 | Community members asked to stop any inappropriate behavior are expected to comply immediately.
47 |
48 | ## Enforcement
49 |
50 | We take Code of Conduct violations seriously, and will act to ensure our spaces are welcoming, inclusive, and professional environments to communicate in.
51 |
52 | If you need to raise a Code of Conduct report, you may do so privately by email to tom@tomchristie.com.
53 |
54 | Reports will be treated confidentially.
55 |
56 | Alternately you may [make a report to the Python Software Foundation](https://www.python.org/psf/conduct/reporting/).
57 |
--------------------------------------------------------------------------------
/docs/css/custom.css:
--------------------------------------------------------------------------------
1 | div.autodoc-docstring {
2 | padding-left: 20px;
3 | margin-bottom: 30px;
4 | border-left: 5px solid rgba(230, 230, 230);
5 | }
6 |
7 | div.autodoc-members {
8 | padding-left: 20px;
9 | margin-bottom: 15px;
10 | }
11 |
--------------------------------------------------------------------------------
/docs/environment_variables.md:
--------------------------------------------------------------------------------
1 | # Environment Variables
2 |
3 | The HTTPX library can be configured via environment variables.
4 | Environment variables are used by default. To ignore environment variables, `trust_env` has to be set `False`. There are two ways to set `trust_env` to disable environment variables:
5 |
6 | * On the client via `httpx.Client(trust_env=False)`.
7 | * Using the top-level API, such as `httpx.get("", trust_env=False)`.
8 |
9 | Here is a list of environment variables that HTTPX recognizes and what function they serve:
10 |
11 | ## Proxies
12 |
13 | The environment variables documented below are used as a convention by various HTTP tooling, including:
14 |
15 | * [cURL](https://github.com/curl/curl/blob/master/docs/MANUAL.md#environment-variables)
16 | * [requests](https://github.com/psf/requests/blob/master/docs/user/advanced.rst#proxies)
17 |
18 | For more information on using proxies in HTTPX, see [HTTP Proxying](advanced/proxies.md#http-proxying).
19 |
20 | ### `HTTP_PROXY`, `HTTPS_PROXY`, `ALL_PROXY`
21 |
22 | Valid values: A URL to a proxy
23 |
24 | `HTTP_PROXY`, `HTTPS_PROXY`, `ALL_PROXY` set the proxy to be used for `http`, `https`, or all requests respectively.
25 |
26 | ```bash
27 | export HTTP_PROXY=http://my-external-proxy.com:1234
28 |
29 | # This request will be sent through the proxy
30 | python -c "import httpx; httpx.get('http://example.com')"
31 |
32 | # This request will be sent directly, as we set `trust_env=False`
33 | python -c "import httpx; httpx.get('http://example.com', trust_env=False)"
34 |
35 | ```
36 |
37 | ### `NO_PROXY`
38 |
39 | Valid values: a comma-separated list of hostnames/urls
40 |
41 | `NO_PROXY` disables the proxy for specific urls
42 |
43 | ```bash
44 | export HTTP_PROXY=http://my-external-proxy.com:1234
45 | export NO_PROXY=http://127.0.0.1,python-httpx.org
46 |
47 | # As in the previous example, this request will be sent through the proxy
48 | python -c "import httpx; httpx.get('http://example.com')"
49 |
50 | # These requests will be sent directly, bypassing the proxy
51 | python -c "import httpx; httpx.get('http://127.0.0.1:5000/my-api')"
52 | python -c "import httpx; httpx.get('https://www.python-httpx.org')"
53 | ```
54 |
--------------------------------------------------------------------------------
/docs/exceptions.md:
--------------------------------------------------------------------------------
1 | # Exceptions
2 |
3 | This page lists exceptions that may be raised when using HTTPX.
4 |
5 | For an overview of how to work with HTTPX exceptions, see [Exceptions (Quickstart)](quickstart.md#exceptions).
6 |
7 | ## The exception hierarchy
8 |
9 | * HTTPError
10 | * RequestError
11 | * TransportError
12 | * TimeoutException
13 | * ConnectTimeout
14 | * ReadTimeout
15 | * WriteTimeout
16 | * PoolTimeout
17 | * NetworkError
18 | * ConnectError
19 | * ReadError
20 | * WriteError
21 | * CloseError
22 | * ProtocolError
23 | * LocalProtocolError
24 | * RemoteProtocolError
25 | * ProxyError
26 | * UnsupportedProtocol
27 | * DecodingError
28 | * TooManyRedirects
29 | * HTTPStatusError
30 | * InvalidURL
31 | * CookieConflict
32 | * StreamError
33 | * StreamConsumed
34 | * ResponseNotRead
35 | * RequestNotRead
36 | * StreamClosed
37 |
38 | ---
39 |
40 | ## Exception classes
41 |
42 | ::: httpx.HTTPError
43 | :docstring:
44 |
45 | ::: httpx.RequestError
46 | :docstring:
47 |
48 | ::: httpx.TransportError
49 | :docstring:
50 |
51 | ::: httpx.TimeoutException
52 | :docstring:
53 |
54 | ::: httpx.ConnectTimeout
55 | :docstring:
56 |
57 | ::: httpx.ReadTimeout
58 | :docstring:
59 |
60 | ::: httpx.WriteTimeout
61 | :docstring:
62 |
63 | ::: httpx.PoolTimeout
64 | :docstring:
65 |
66 | ::: httpx.NetworkError
67 | :docstring:
68 |
69 | ::: httpx.ConnectError
70 | :docstring:
71 |
72 | ::: httpx.ReadError
73 | :docstring:
74 |
75 | ::: httpx.WriteError
76 | :docstring:
77 |
78 | ::: httpx.CloseError
79 | :docstring:
80 |
81 | ::: httpx.ProtocolError
82 | :docstring:
83 |
84 | ::: httpx.LocalProtocolError
85 | :docstring:
86 |
87 | ::: httpx.RemoteProtocolError
88 | :docstring:
89 |
90 | ::: httpx.ProxyError
91 | :docstring:
92 |
93 | ::: httpx.UnsupportedProtocol
94 | :docstring:
95 |
96 | ::: httpx.DecodingError
97 | :docstring:
98 |
99 | ::: httpx.TooManyRedirects
100 | :docstring:
101 |
102 | ::: httpx.HTTPStatusError
103 | :docstring:
104 |
105 | ::: httpx.InvalidURL
106 | :docstring:
107 |
108 | ::: httpx.CookieConflict
109 | :docstring:
110 |
111 | ::: httpx.StreamError
112 | :docstring:
113 |
114 | ::: httpx.StreamConsumed
115 | :docstring:
116 |
117 | ::: httpx.StreamClosed
118 | :docstring:
119 |
120 | ::: httpx.ResponseNotRead
121 | :docstring:
122 |
123 | ::: httpx.RequestNotRead
124 | :docstring:
125 |
--------------------------------------------------------------------------------
/docs/http2.md:
--------------------------------------------------------------------------------
1 | # HTTP/2
2 |
3 | HTTP/2 is a major new iteration of the HTTP protocol, that provides a far more
4 | efficient transport, with potential performance benefits. HTTP/2 does not change
5 | the core semantics of the request or response, but alters the way that data is
6 | sent to and from the server.
7 |
8 | Rather than the text format that HTTP/1.1 uses, HTTP/2 is a binary format.
9 | The binary format provides full request and response multiplexing, and efficient
10 | compression of HTTP headers. The stream multiplexing means that where HTTP/1.1
11 | requires one TCP stream for each concurrent request, HTTP/2 allows a single TCP
12 | stream to handle multiple concurrent requests.
13 |
14 | HTTP/2 also provides support for functionality such as response prioritization,
15 | and server push.
16 |
17 | For a comprehensive guide to HTTP/2 you may want to check out "[http2 explained](https://http2-explained.haxx.se/)".
18 |
19 | ## Enabling HTTP/2
20 |
21 | When using the `httpx` client, HTTP/2 support is not enabled by default, because
22 | HTTP/1.1 is a mature, battle-hardened transport layer, and our HTTP/1.1
23 | implementation may be considered the more robust option at this point in time.
24 | It is possible that a future version of `httpx` may enable HTTP/2 support by default.
25 |
26 | If you're issuing highly concurrent requests you might want to consider
27 | trying out our HTTP/2 support. You can do so by first making sure to install
28 | the optional HTTP/2 dependencies...
29 |
30 | ```shell
31 | $ pip install httpx[http2]
32 | ```
33 |
34 | And then instantiating a client with HTTP/2 support enabled:
35 |
36 | ```python
37 | client = httpx.AsyncClient(http2=True)
38 | ...
39 | ```
40 |
41 | You can also instantiate a client as a context manager, to ensure that all
42 | HTTP connections are nicely scoped, and will be closed once the context block
43 | is exited.
44 |
45 | ```python
46 | async with httpx.AsyncClient(http2=True) as client:
47 | ...
48 | ```
49 |
50 | HTTP/2 support is available on both `Client` and `AsyncClient`, although it's
51 | typically more useful in async contexts if you're issuing lots of concurrent
52 | requests.
53 |
54 | ## Inspecting the HTTP version
55 |
56 | Enabling HTTP/2 support on the client does not *necessarily* mean that your
57 | requests and responses will be transported over HTTP/2, since both the client
58 | *and* the server need to support HTTP/2. If you connect to a server that only
59 | supports HTTP/1.1 the client will use a standard HTTP/1.1 connection instead.
60 |
61 | You can determine which version of the HTTP protocol was used by examining
62 | the `.http_version` property on the response.
63 |
64 | ```python
65 | client = httpx.AsyncClient(http2=True)
66 | response = await client.get(...)
67 | print(response.http_version) # "HTTP/1.0", "HTTP/1.1", or "HTTP/2".
68 | ```
69 |
--------------------------------------------------------------------------------
/docs/img/butterfly.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/encode/httpx/6c7af967734bafd011164f2a1653abc87905a62b/docs/img/butterfly.png
--------------------------------------------------------------------------------
/docs/img/gh-actions-fail-check.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/encode/httpx/6c7af967734bafd011164f2a1653abc87905a62b/docs/img/gh-actions-fail-check.png
--------------------------------------------------------------------------------
/docs/img/gh-actions-fail-test.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/encode/httpx/6c7af967734bafd011164f2a1653abc87905a62b/docs/img/gh-actions-fail-test.png
--------------------------------------------------------------------------------
/docs/img/gh-actions-fail.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/encode/httpx/6c7af967734bafd011164f2a1653abc87905a62b/docs/img/gh-actions-fail.png
--------------------------------------------------------------------------------
/docs/img/httpx-help.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/encode/httpx/6c7af967734bafd011164f2a1653abc87905a62b/docs/img/httpx-help.png
--------------------------------------------------------------------------------
/docs/img/httpx-request.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/encode/httpx/6c7af967734bafd011164f2a1653abc87905a62b/docs/img/httpx-request.png
--------------------------------------------------------------------------------
/docs/img/logo.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/encode/httpx/6c7af967734bafd011164f2a1653abc87905a62b/docs/img/logo.jpg
--------------------------------------------------------------------------------
/docs/img/rich-progress.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/encode/httpx/6c7af967734bafd011164f2a1653abc87905a62b/docs/img/rich-progress.gif
--------------------------------------------------------------------------------
/docs/img/speakeasy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/encode/httpx/6c7af967734bafd011164f2a1653abc87905a62b/docs/img/speakeasy.png
--------------------------------------------------------------------------------
/docs/img/tqdm-progress.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/encode/httpx/6c7af967734bafd011164f2a1653abc87905a62b/docs/img/tqdm-progress.gif
--------------------------------------------------------------------------------
/docs/index.md:
--------------------------------------------------------------------------------
1 |