From 161324d9d5a5111b0a08509bc1c45908f62e15b1 Mon Sep 17 00:00:00 2001
From: Tom Christie
httpx.Auth.The most involved of these is the last, which allows you to create authentication flows involving one or more requests. A subclass of httpx.Auth should implement def auth_flow(request), and yield any requests that need to be made...
class MyCustomAuth(httpx.Auth):
- def __init__(self, token):
+class MyCustomAuth(httpx.Auth):
+ def __init__(self, token):
self.token = token
- def auth_flow(self, request):
+ def auth_flow(self, request):
# Send the request, with a custom `X-Authentication` header.
request.headers['X-Authentication'] = self.token
yield request
If the auth flow requires more than one request, you can issue multiple yields, and obtain the response in each case...
-class MyCustomAuth(httpx.Auth):
- def __init__(self, token):
+class MyCustomAuth(httpx.Auth):
+ def __init__(self, token):
self.token = token
- def auth_flow(self, request):
+ def auth_flow(self, request):
response = yield request
if response.status_code == 401:
# If the server issues a 401 response then resend the request,
@@ -1175,13 +1175,13 @@ or fallback to the default.
Custom authentication classes are designed to not perform any I/O, so that they may be used with both sync and async client instances. If you are implementing an authentication scheme that requires the request body, then you need to indicate this on the class using a requires_request_body property.
You will then be able to access request.content inside the .auth_flow() method.
-class MyCustomAuth(httpx.Auth):
+class MyCustomAuth(httpx.Auth):
requires_request_body = True
- def __init__(self, token):
+ def __init__(self, token):
self.token = token
- def auth_flow(self, request):
+ def auth_flow(self, request):
response = yield request
if response.status_code == 401:
# If the server issues a 401 response then resend the request,
@@ -1189,22 +1189,22 @@ or fallback to the default.
request.headers['X-Authentication'] = self.sign_request(...)
yield request
- def sign_request(self, request):
+ def sign_request(self, request):
# Create a request signature, based on `request.method`, `request.url`,
# `request.headers`, and `request.content`.
...
Similarly, if you are implementing a scheme that requires access to the response body, then use the requires_response_body property. You will then be able to access response body properties and methods such as response.content, response.text, response.json(), etc.
-class MyCustomAuth(httpx.Auth):
+class MyCustomAuth(httpx.Auth):
requires_response_body = True
- def __init__(self, access_token, refresh_token, refresh_url):
+ def __init__(self, access_token, refresh_token, refresh_url):
self.access_token = access_token
self.refresh_token = refresh_token
self.refresh_url = refresh_url
- def auth_flow(self, request):
+ def auth_flow(self, request):
request.headers["X-Authentication"] = self.access_token
response = yield request
@@ -1217,11 +1217,11 @@ or fallback to the default.
request.headers["X-Authentication"] = self.access_token
yield request
- def build_refresh_request(self):
+ def build_refresh_request(self):
# Return an `httpx.Request` for refreshing tokens.
...
- def update_tokens(self, response):
+ def update_tokens(self, response):
# Update the `.access_token` and `.refresh_token` tokens
# based on a refresh response.
data = response.json()
@@ -1229,47 +1229,47 @@ or fallback to the default.
If you do need to perform I/O other than HTTP requests, such as accessing a disk-based cache, or you need to use concurrency primitives, such as locks, then you should override .sync_auth_flow() and .async_auth_flow() (instead of .auth_flow()). The former will be used by httpx.Client, while the latter will be used by httpx.AsyncClient.
-import asyncio
-import threading
-import httpx
+import asyncio
+import threading
+import httpx
-class MyCustomAuth(httpx.Auth):
- def __init__(self):
+class MyCustomAuth(httpx.Auth):
+ def __init__(self):
self._sync_lock = threading.RLock()
self._async_lock = asyncio.Lock()
- def sync_get_token(self):
+ def sync_get_token(self):
with self._sync_lock:
...
- def sync_auth_flow(self, request):
+ def sync_auth_flow(self, request):
token = self.sync_get_token()
request.headers["Authorization"] = f"Token {token}"
yield request
- async def async_get_token(self):
+ async def async_get_token(self):
async with self._async_lock:
...
- async def async_auth_flow(self, request):
+ async def async_auth_flow(self, request):
token = await self.async_get_token()
request.headers["Authorization"] = f"Token {token}"
yield request
If you only want to support one of the two methods, then you should still override it, but raise an explicit RuntimeError.
-import httpx
-import sync_only_library
+import httpx
+import sync_only_library
-class MyCustomAuth(httpx.Auth):
- def sync_auth_flow(self, request):
+class MyCustomAuth(httpx.Auth):
+ def sync_auth_flow(self, request):
token = sync_only_library.get_token(...)
request.headers["Authorization"] = f"Token {token}"
yield request
- async def async_auth_flow(self, request):
+ async def async_auth_flow(self, request):
raise RuntimeError("Cannot use a sync authentication class with httpx.AsyncClient")
diff --git a/advanced/clients/index.html b/advanced/clients/index.html
index 23707b32..ff6bae4f 100644
--- a/advanced/clients/index.html
+++ b/advanced/clients/index.html
@@ -1284,7 +1284,7 @@
... r = client.get('https://example.com', auth=('alice', 'ecila123'))
...
>>> _, _, auth = r.request.headers['Authorization'].partition(' ')
->>> import base64
+>>> import base64
>>> base64.b64decode(auth)
b'alice:ecila123'
@@ -1332,10 +1332,10 @@
If you need to monitor download progress of large responses, you can use response streaming and inspect the response.num_bytes_downloaded property.
This interface is required for properly determining download progress, because the total number of bytes returned by response.content or response.iter_content() will not always correspond with the raw content length of the response if HTTP response compression is being used.
For example, showing a progress bar using the tqdm library while a response is being downloaded could be done like thisâ¦
-import tempfile
+import tempfile
-import httpx
-from tqdm import tqdm
+import httpx
+from tqdm import tqdm
with tempfile.NamedTemporaryFile() as download_file:
url = "https://speed.hetzner.de/100MB.bin"
@@ -1352,9 +1352,9 @@

Or an alternate example, this time using the rich libraryâ¦
-import tempfile
-import httpx
-import rich.progress
+import tempfile
+import httpx
+import rich.progress
with tempfile.NamedTemporaryFile() as download_file:
url = "https://speed.hetzner.de/100MB.bin"
@@ -1377,14 +1377,14 @@
Monitoring upload progress
If you need to monitor upload progress of large responses, you can use request content generator streaming.
For example, showing a progress bar using the tqdm library.
-import io
-import random
+import io
+import random
-import httpx
-from tqdm import tqdm
+import httpx
+from tqdm import tqdm
-def gen():
+def gen():
"""
this is a complete example with generated random bytes.
you can replace `io.BytesIO` with real file object.
@@ -1405,8 +1405,9 @@
As mentioned in the quickstart
multipart file encoding is available by passing a dictionary with the
name of the payloads as keys and either tuple of elements or a file-like object or a string as values.
->>> files = {'upload-file': ('report.xls', open('report.xls', 'rb'), 'application/vnd.ms-excel')}
->>> r = httpx.post("https://httpbin.org/post", files=files)
+>>> with open('report.xls', 'rb') as report_file:
+... files = {'upload-file': ('report.xls', report_file, 'application/vnd.ms-excel')}
+... r = httpx.post("https://httpbin.org/post", files=files)
>>> print(r.text)
{
...
@@ -1450,9 +1451,12 @@ MIME header field.
You can also send multiple files in one go with a multiple file field form.
To do that, pass a list of (field, <file>) items instead of a dictionary, allowing you to pass multiple items with the same field.
For instance this request sends 2 files, foo.png and bar.png in one request on the images form field:
->>> files = [('images', ('foo.png', open('foo.png', 'rb'), 'image/png')),
- ('images', ('bar.png', open('bar.png', 'rb'), 'image/png'))]
->>> r = httpx.post("https://httpbin.org/post", files=files)
+>>> with open('foo.png', 'rb') as foo_file, open('bar.png', 'rb') as bar_file:
+... files = [
+... ('images', ('foo.png', foo_file, 'image/png')),
+... ('images', ('bar.png', bar_file, 'image/png')),
+... ]
+... r = httpx.post("https://httpbin.org/post", files=files)
diff --git a/advanced/event-hooks/index.html b/advanced/event-hooks/index.html
index 9a202a00..83713220 100644
--- a/advanced/event-hooks/index.html
+++ b/advanced/event-hooks/index.html
@@ -972,10 +972,10 @@ every time a particular type of event takes place.
response - Called after the response has been fetched from the network, but before it is returned to the caller. Passed the response instance.
These allow you to install client-wide functionality such as logging, monitoring or tracing.
-def log_request(request):
+def log_request(request):
print(f"Request event hook: {request.method} {request.url} - Waiting for response")
-def log_response(response):
+def log_response(response):
request = response.request
print(f"Response event hook: {request.method} {request.url} - Status {response.status_code}")
@@ -985,7 +985,7 @@ every time a particular type of event takes place.
You can also use these hooks to install response processing code, such as this
example, which creates a client instance that always raises httpx.HTTPStatusError
on 4xx and 5xx responses.
-def raise_on_4xx_5xx(response):
+def raise_on_4xx_5xx(response):
response.raise_for_status()
client = httpx.Client(event_hooks={'response': [raise_on_4xx_5xx]})
@@ -999,7 +999,7 @@ should be read or not.
need to call response.read(), or for AsyncClients, response.aread().
The hooks are also allowed to modify request and response objects.
-def add_timestamp(request):
+def add_timestamp(request):
request.headers['x-request-timestamp'] = datetime.now(tz=datetime.utc).isoformat()
client = httpx.Client(event_hooks={'request': [add_timestamp]})
diff --git a/advanced/extensions/index.html b/advanced/extensions/index.html
index c35b3079..7a1dcee1 100644
--- a/advanced/extensions/index.html
+++ b/advanced/extensions/index.html
@@ -1242,9 +1242,9 @@
The trace extension allows a callback handler to be installed to monitor the internal
flow of events within the underlying httpcore transport.
The simplest way to explain this is with an example:
-import httpx
+import httpx
-def log(event_name, info):
+def log(event_name, info):
print(event_name, info)
client = httpx.Client()
diff --git a/advanced/ssl/index.html b/advanced/ssl/index.html
index ea4a01c3..090a8d98 100644
--- a/advanced/ssl/index.html
+++ b/advanced/ssl/index.html
@@ -1111,9 +1111,9 @@
If you're using a Client() instance you should pass any verify=<...> configuration when instantiating the client.
By default the certifi CA bundle is used for SSL verification.
For more complex configurations you can pass an SSL Context instance...
-import certifi
-import httpx
-import ssl
+import certifi
+import httpx
+import ssl
# This SSL context is equivelent to the default `verify=True`.
ctx = ssl.create_default_context(cafile=certifi.where())
@@ -1121,9 +1121,9 @@
Using the truststore package to support system certificate stores...
-import ssl
-import truststore
-import httpx
+import ssl
+import truststore
+import httpx
# Use system certificate stores.
ctx = truststore.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
@@ -1131,8 +1131,8 @@
Loding an alternative certificate verification store using the standard SSL context API...
-import httpx
-import ssl
+import httpx
+import ssl
# Use an explicitly configured certificate store.
ctx = ssl.create_default_context(cafile="path/to/certs.pem") # Either cafile or capath.
@@ -1148,17 +1148,7 @@
Working with SSL_CERT_FILE and SSL_CERT_DIR
-Unlike requests, the httpx package does not automatically pull in the environment variables SSL_CERT_FILE or SSL_CERT_DIR. If you want to use these they need to be enabled explicitly.
-For example...
-# Use `SSL_CERT_FILE` or `SSL_CERT_DIR` if configured.
-# Otherwise default to certifi.
-ctx = ssl.create_default_context(
- cafile=os.environ.get("SSL_CERT_FILE", certifi.where()),
- capath=os.environ.get("SSL_CERT_DIR"),
-)
-client = httpx.Client(verify=ctx)
-
-
+httpx does respect the SSL_CERT_FILE and SSL_CERT_DIR environment variables by default. For details, refer to the section on the environment variables page.
Making HTTPS requests to a local server
When making requests to local servers, such as a development server running on localhost, you will typically be using unencrypted HTTP connections.
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...
diff --git a/advanced/text-encodings/index.html b/advanced/text-encodings/index.html
index 42c28acc..b61957a2 100644
--- a/advanced/text-encodings/index.html
+++ b/advanced/text-encodings/index.html
@@ -1064,7 +1064,7 @@
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.
Using the default encoding
To understand this better let's start by looking at the default behaviour for text decoding...
-import httpx
+import httpx
# Instantiate a client with the default configuration.
client = httpx.Client()
# Using the client...
@@ -1078,7 +1078,7 @@
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.
Using an explicit encoding
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.
-import httpx
+import httpx
# Instantiate a client with a Japanese character set as the default encoding.
client = httpx.Client(default_encoding="shift-jis")
# Using the client...
@@ -1103,10 +1103,10 @@ $ pip install
Once chardet is installed, we can configure a client to use character-set autodetection.
-import httpx
-import chardet
+import httpx
+import chardet
-def autodetect(content):
+def autodetect(content):
return chardet.detect(content).get("encoding")
# Using a client with character-set autodetection enabled.
diff --git a/advanced/transports/index.html b/advanced/transports/index.html
index 2eb325c6..00a5b211 100644
--- a/advanced/transports/index.html
+++ b/advanced/transports/index.html
@@ -1390,20 +1390,20 @@ sending of the requests.
For some advanced configuration you might need to instantiate a transport
class directly, and pass it to the client instance. One example is the
local_address configuration which is only available via this low-level API.
->>> import httpx
+>>> import httpx
>>> transport = httpx.HTTPTransport(local_address="0.0.0.0")
>>> client = httpx.Client(transport=transport)
Connection retries are also available via this interface. Requests will be retried the given number of times in case an httpx.ConnectError or an httpx.ConnectTimeout occurs, allowing smoother operation under flaky networks. If you need other forms of retry behaviors, such as handling read/write errors or reacting to 503 Service Unavailable, consider general-purpose tools such as tenacity.
->>> import httpx
+>>> import httpx
>>> transport = httpx.HTTPTransport(retries=1)
>>> client = httpx.Client(transport=transport)
Similarly, instantiating a transport directly provides a uds option for
connecting via a Unix Domain Socket that is only available via this low-level API:
->>> import httpx
+>>> import httpx
>>> # Connect to the Docker API via a Unix Socket.
>>> transport = httpx.HTTPTransport(uds="/var/run/docker.sock")
>>> client = httpx.Client(transport=transport)
@@ -1421,14 +1421,14 @@ connecting via a Unix Domain Socket that is only available via this low-level AP
Example
Here's an example of integrating against a Flask application:
-from flask import Flask
-import httpx
+from flask import Flask
+import httpx
app = Flask(__name__)
@app.route("/")
-def hello():
+def hello():
return "Hello World!"
transport = httpx.WSGITransport(app=app)
@@ -1461,12 +1461,12 @@ connecting via a Unix Domain Socket that is only available via this low-level AP
Example
Let's take this Starlette application as an example:
-from starlette.applications import Starlette
-from starlette.responses import HTMLResponse
-from starlette.routing import Route
+from starlette.applications import Starlette
+from starlette.responses import HTMLResponse
+from starlette.routing import Route
-async def hello(request):
+async def hello(request):
return HTMLResponse("Hello World!")
@@ -1512,24 +1512,24 @@ use with AsyncClient.
See the handle_request and handle_async_request docstrings for more details
on the specifics of the Transport API.
A complete example of a custom transport implementation would be:
-import json
-import httpx
+import json
+import httpx
-class HelloWorldTransport(httpx.BaseTransport):
+class HelloWorldTransport(httpx.BaseTransport):
"""
A mock transport that always returns a JSON "Hello, world!" response.
"""
- def handle_request(self, request):
+ def handle_request(self, request):
return httpx.Response(200, json={"text": "Hello, world!"})
Or this example, which uses a custom transport and httpx.Mounts to always redirect http:// requests.
-class HTTPSRedirect(httpx.BaseTransport):
+class HTTPSRedirect(httpx.BaseTransport):
"""
A transport that always redirects to HTTPS.
"""
- def handle_request(self, request):
+ def handle_request(self, request):
url = request.url.copy_with(scheme="https")
return httpx.Response(303, headers={"Location": str(url)})
@@ -1542,17 +1542,17 @@ on the specifics of the Transport API.
A useful pattern here is custom transport classes that wrap the default HTTP implementation. For example...
-class DebuggingTransport(httpx.BaseTransport):
- def __init__(self, **kwargs):
+class DebuggingTransport(httpx.BaseTransport):
+ def __init__(self, **kwargs):
self._wrapper = httpx.HTTPTransport(**kwargs)
- def handle_request(self, request):
+ def handle_request(self, request):
print(f">>> {request}")
response = self._wrapper.handle_request(request)
print(f"<<< {response}")
return response
- def close(self):
+ def close(self):
self._wrapper.close()
transport = DebuggingTransport()
@@ -1560,20 +1560,20 @@ on the specifics of the Transport API.
Here's another case, where we're using a round-robin across a number of different proxies...
-class ProxyRoundRobin(httpx.BaseTransport):
- def __init__(self, proxies, **kwargs):
+class ProxyRoundRobin(httpx.BaseTransport):
+ def __init__(self, proxies, **kwargs):
self._transports = [
httpx.HTTPTransport(proxy=proxy, **kwargs)
for proxy in proxies
]
self._idx = 0
- def handle_request(self, request):
+ def handle_request(self, request):
transport = self._transports[self._idx]
self._idx = (self._idx + 1) % len(self._transports)
return transport.handle_request(request)
- def close(self):
+ def close(self):
for transport in self._transports:
transport.close()
@@ -1591,7 +1591,7 @@ on the specifics of the Transport API.
and return pre-determined responses, rather than making actual network requests.
The httpx.MockTransport class accepts a handler function, which can be used
to map requests onto pre-determined responses:
-def handler(request):
+def handler(request):
return httpx.Response(200, json={"text": "Hello, world!"})
@@ -1610,14 +1610,14 @@ mocking library, RESPX, or the the same style
used for specifying proxy routing.
-import httpx
+import httpx
-class HTTPSRedirectTransport(httpx.BaseTransport):
+class HTTPSRedirectTransport(httpx.BaseTransport):
"""
A transport that always redirects to HTTPS.
"""
- def handle_request(self, method, url, headers, stream, extensions):
+ def handle_request(self, method, url, headers, stream, extensions):
scheme, host, port, path = url
if port is None:
location = b"https://%s%s" % (host, path)
@@ -1646,7 +1646,7 @@ used for specifying proxy routing.
Mocking requests to a given domain:
# All requests to "example.org" should be mocked out.
# Other requests occur as usual.
-def handler(request):
+def handler(request):
return httpx.Response(200, json={"text": "Hello, World!"})
mounts = {"all://example.org": httpx.MockTransport(handler)}
diff --git a/api/index.html b/api/index.html
index 98d30b3a..a59457ba 100644
--- a/api/index.html
+++ b/api/index.html
@@ -868,6 +868,15 @@
+
+
+
+
+
+ Proxy
+
+
+
@@ -1136,6 +1145,15 @@
+
+
+
+
+
+ Proxy
+
+
+
@@ -1198,10 +1216,10 @@ variables for configuration.
Returns: Response
Usage:
->>> import httpx
->>> response = httpx.request('GET', 'https://httpbin.org/get')
->>> response
-<Response [200 OK]>
+>>> import httpx
+>>> response = httpx.request('GET', 'https://httpbin.org/get')
+>>> response
+<Response [200 OK]>
@@ -1305,7 +1323,7 @@ header. Set to a callable for automatic character set detection. Default: "utf-8
auth
Authentication class used when none is passed at the request-level.
See also Authentication.
-request(self, method, url, *, content=None, data=None, files=None, json=None, params=None, headers=None, cookies=None, auth= , follow_redirects= , timeout= , extensions=None)
+request(self, method, url, *, content=None, data=None, files=None, json=None, params=None, headers=None, cookies=None, auth= , follow_redirects= , timeout= , extensions=None)
Build and send a request.
Equivalent to:
request = client.build_request(...)
@@ -1315,33 +1333,33 @@ header. Set to a callable for automatic character set detection. Default: "utf-8
See Client.build_request(), Client.send() and
Merging of configuration for how the various parameters
are merged with client-level configuration.
-get(self, url, *, params=None, headers=None, cookies=None, auth= , follow_redirects= , timeout= , extensions=None)
+get(self, url, *, params=None, headers=None, cookies=None, auth= , follow_redirects= , timeout= , extensions=None)
Send a GET request.
Parameters: See httpx.request.
-head(self, url, *, params=None, headers=None, cookies=None, auth= , follow_redirects= , timeout= , extensions=None)
+head(self, url, *, params=None, headers=None, cookies=None, auth= , follow_redirects= , timeout= , extensions=None)
Send a HEAD request.
Parameters: See httpx.request.
-options(self, url, *, params=None, headers=None, cookies=None, auth= , follow_redirects= , timeout= , extensions=None)
+options(self, url, *, params=None, headers=None, cookies=None, auth= , follow_redirects= , timeout= , extensions=None)
Send an OPTIONS request.
Parameters: See httpx.request.
-post(self, url, *, content=None, data=None, files=None, json=None, params=None, headers=None, cookies=None, auth= , follow_redirects= , timeout= , extensions=None)
+post(self, url, *, content=None, data=None, files=None, json=None, params=None, headers=None, cookies=None, auth= , follow_redirects= , timeout= , extensions=None)
Send a POST request.
Parameters: See httpx.request.
-put(self, url, *, content=None, data=None, files=None, json=None, params=None, headers=None, cookies=None, auth= , follow_redirects= , timeout= , extensions=None)
+put(self, url, *, content=None, data=None, files=None, json=None, params=None, headers=None, cookies=None, auth= , follow_redirects= , timeout= , extensions=None)
Send a PUT request.
Parameters: See httpx.request.
-patch(self, url, *, content=None, data=None, files=None, json=None, params=None, headers=None, cookies=None, auth= , follow_redirects= , timeout= , extensions=None)
+patch(self, url, *, content=None, data=None, files=None, json=None, params=None, headers=None, cookies=None, auth= , follow_redirects= , timeout= , extensions=None)
Send a PATCH request.
Parameters: See httpx.request.
-delete(self, url, *, params=None, headers=None, cookies=None, auth= , follow_redirects= , timeout= , extensions=None)
+delete(self, url, *, params=None, headers=None, cookies=None, auth= , follow_redirects= , timeout= , extensions=None)
Send a DELETE request.
Parameters: See httpx.request.
-stream(self, method, url, *, content=None, data=None, files=None, json=None, params=None, headers=None, cookies=None, auth= , follow_redirects= , timeout= , extensions=None)
+stream(self, method, url, *, content=None, data=None, files=None, json=None, params=None, headers=None, cookies=None, auth= , follow_redirects= , timeout= , extensions=None)
Alternative to httpx.request() that streams the response body
instead of loading it into memory at once.
Parameters: See httpx.request.
See also: Streaming Responses
-build_request(self, method, url, *, content=None, data=None, files=None, json=None, params=None, headers=None, cookies=None, timeout= , extensions=None)
+build_request(self, method, url, *, content=None, data=None, files=None, json=None, params=None, headers=None, cookies=None, timeout= , extensions=None)
Build and return a request instance.
- The
params, headers and cookies arguments
@@ -1349,7 +1367,7 @@ are merged with any values set on the client.
- The
url argument is merged with any base_url set on the client.
See also: Request instances
-send(self, request, *, stream=False, auth= , follow_redirects= )
+send(self, request, *, stream=False, auth= , follow_redirects= )
Send a request.
The request is sent as-is, unmodified.
Typically you'll want to build one with Client.build_request()
@@ -1412,7 +1430,7 @@ header. Set to a callable for automatic character set detection. Default: "utf-8
auth
Authentication class used when none is passed at the request-level.
See also Authentication.
-async request(self, method, url, *, content=None, data=None, files=None, json=None, params=None, headers=None, cookies=None, auth= , follow_redirects= , timeout= , extensions=None)
+async request(self, method, url, *, content=None, data=None, files=None, json=None, params=None, headers=None, cookies=None, auth= , follow_redirects= , timeout= , extensions=None)
Build and send a request.
Equivalent to:
request = client.build_request(...)
@@ -1422,33 +1440,33 @@ header. Set to a callable for automatic character set detection. Default: "utf-8
See AsyncClient.build_request(), AsyncClient.send()
and Merging of configuration for how the various parameters
are merged with client-level configuration.
-async get(self, url, *, params=None, headers=None, cookies=None, auth= , follow_redirects= , timeout= , extensions=None)
+async get(self, url, *, params=None, headers=None, cookies=None, auth= , follow_redirects= , timeout= , extensions=None)
Send a GET request.
Parameters: See httpx.request.
-async head(self, url, *, params=None, headers=None, cookies=None, auth= , follow_redirects= , timeout= , extensions=None)
+async head(self, url, *, params=None, headers=None, cookies=None, auth= , follow_redirects= , timeout= , extensions=None)
Send a HEAD request.
Parameters: See httpx.request.
-async options(self, url, *, params=None, headers=None, cookies=None, auth= , follow_redirects= , timeout= , extensions=None)
+async options(self, url, *, params=None, headers=None, cookies=None, auth= , follow_redirects= , timeout= , extensions=None)
Send an OPTIONS request.
Parameters: See httpx.request.
-async post(self, url, *, content=None, data=None, files=None, json=None, params=None, headers=None, cookies=None, auth= , follow_redirects= , timeout= , extensions=None)
+async post(self, url, *, content=None, data=None, files=None, json=None, params=None, headers=None, cookies=None, auth= , follow_redirects= , timeout= , extensions=None)
Send a POST request.
Parameters: See httpx.request.
-async put(self, url, *, content=None, data=None, files=None, json=None, params=None, headers=None, cookies=None, auth= , follow_redirects= , timeout= , extensions=None)
+async put(self, url, *, content=None, data=None, files=None, json=None, params=None, headers=None, cookies=None, auth= , follow_redirects= , timeout= , extensions=None)
Send a PUT request.
Parameters: See httpx.request.
-async patch(self, url, *, content=None, data=None, files=None, json=None, params=None, headers=None, cookies=None, auth= , follow_redirects= , timeout= , extensions=None)
+async patch(self, url, *, content=None, data=None, files=None, json=None, params=None, headers=None, cookies=None, auth= , follow_redirects= , timeout= , extensions=None)
Send a PATCH request.
Parameters: See httpx.request.
-async delete(self, url, *, params=None, headers=None, cookies=None, auth= , follow_redirects= , timeout= , extensions=None)
+async delete(self, url, *, params=None, headers=None, cookies=None, auth= , follow_redirects= , timeout= , extensions=None)
Send a DELETE request.
Parameters: See httpx.request.
-stream(self, method, url, *, content=None, data=None, files=None, json=None, params=None, headers=None, cookies=None, auth= , follow_redirects= , timeout= , extensions=None)
+stream(self, method, url, *, content=None, data=None, files=None, json=None, params=None, headers=None, cookies=None, auth= , follow_redirects= , timeout= , extensions=None)
Alternative to httpx.request() that streams the response body
instead of loading it into memory at once.
Parameters: See httpx.request.
See also: Streaming Responses
-build_request(self, method, url, *, content=None, data=None, files=None, json=None, params=None, headers=None, cookies=None, timeout= , extensions=None)
+build_request(self, method, url, *, content=None, data=None, files=None, json=None, params=None, headers=None, cookies=None, timeout= , extensions=None)
Build and return a request instance.
- The
params, headers and cookies arguments
@@ -1456,7 +1474,7 @@ are merged with any values set on the client.
- The
url argument is merged with any base_url set on the client.
See also: Request instances
-async send(self, request, *, stream=False, auth= , follow_redirects= )
+async send(self, request, *, stream=False, auth= , follow_redirects= )
Send a request.
The request is sent as-is, unmodified.
Typically you'll want to build one with AsyncClient.build_request()
@@ -1570,6 +1588,19 @@ what gets sent over the wire.
def clear([domain], [path])
Standard mutable mapping interface
+Proxy
+A configuration of the proxy server.
+>>> proxy = Proxy("http://proxy.example.com:8030")
+>>> client = Client(proxy=proxy)
+
+
+
+def __init__(url, [ssl_context], [auth], [headers])
+.url - URL
+.auth - tuple[str, str]
+.headers - Headers
+.ssl_context - SSLContext
+
diff --git a/async/index.html b/async/index.html
index 4abca665..dcaf9309 100644
--- a/async/index.html
+++ b/async/index.html
@@ -1268,7 +1268,7 @@ async client for sending outgoing HTTP requests.
Tip
-Use IPython or Python 3.8+ with python -m asyncio to try this code interactively, as they support executing async/await expressions in the console.
+Use IPython or Python 3.9+ with python -m asyncio to try this code interactively, as they support executing async/await expressions in the console.
API Differences
If you're using an async client then there are a few bits of API that
@@ -1321,13 +1321,13 @@ use async methods.
For situations when context block usage is not practical, it is possible to enter "manual mode" by sending a Request instance using client.send(..., stream=True).
Example in the context of forwarding the response to a streaming web endpoint with Starlette:
-import httpx
-from starlette.background import BackgroundTask
-from starlette.responses import StreamingResponse
+import httpx
+from starlette.background import BackgroundTask
+from starlette.responses import StreamingResponse
client = httpx.AsyncClient()
-async def home(request):
+async def home(request):
req = client.build_request("GET", "https://www.example.com/")
r = await client.send(req, stream=True)
return StreamingResponse(r.aiter_text(), background=BackgroundTask(r.aclose))
@@ -1339,7 +1339,7 @@ use async methods.
Streaming requests
When sending a streaming request body with an AsyncClient instance, you should use an async bytes generator instead of a bytes generator:
-async def upload_bytes():
+async def upload_bytes():
... # yield byte content
await client.post(url, content=upload_bytes())
@@ -1348,7 +1348,7 @@ use async methods.
Explicit transport instances
When instantiating a transport instance directly, you need to use httpx.AsyncHTTPTransport.
For instance:
->>> import httpx
+>>> import httpx
>>> transport = httpx.AsyncHTTPTransport(retries=1)
>>> async with httpx.AsyncClient(transport=transport) as client:
>>> ...
@@ -1361,10 +1361,10 @@ for socket operations and concurrency primitives.
AsyncIO
AsyncIO is Python's built-in library
for writing concurrent code with the async/await syntax.
-import asyncio
-import httpx
+import asyncio
+import httpx
-async def main():
+async def main():
async with httpx.AsyncClient() as client:
response = await client.get('https://www.example.com/')
print(response)
@@ -1375,10 +1375,10 @@ for writing concurrent code with the async/await syntax.
Trio
Trio is an alternative async library,
designed around the the principles of structured concurrency.
-import httpx
-import trio
+import httpx
+import trio
-async def main():
+async def main():
async with httpx.AsyncClient() as client:
response = await client.get('https://www.example.com/')
print(response)
@@ -1392,10 +1392,10 @@ designed around the AnyIO
AnyIO is an asynchronous networking and concurrency library that works on top of either asyncio or trio. It blends in with native libraries of your chosen backend (defaults to asyncio).
-import httpx
-import anyio
+import httpx
+import anyio
-async def main():
+async def main():
async with httpx.AsyncClient() as client:
response = await client.get('https://www.example.com/')
print(response)
diff --git a/compatibility/index.html b/compatibility/index.html
index 19a77c22..f709cbf1 100644
--- a/compatibility/index.html
+++ b/compatibility/index.html
@@ -901,6 +901,15 @@
+
+
+
+
+
+ Exceptions and Errors
+
+
+
@@ -1370,6 +1379,15 @@
+
+
+
+
+
+ Exceptions and Errors
+
+
+
@@ -1532,6 +1550,8 @@ For more detailed documentation, see examples given in the documentation for requests.
In HTTPX, event hooks may access properties of requests and responses, but event hook callbacks cannot mutate the original request/response.
If you are looking for more control, consider checking out Custom Transports.
+Exceptions and Errors
+requests exception hierarchy is slightly different to the httpx exception hierarchy. requests exposes a top level RequestException, where as httpx exposes a top level HTTPError. see the exceptions exposes in requests here. See the httpx error hierarchy here.
diff --git a/environment_variables/index.html b/environment_variables/index.html
index 0c8ad224..dfc08f96 100644
--- a/environment_variables/index.html
+++ b/environment_variables/index.html
@@ -871,6 +871,24 @@
+
+
+
+
+
+ SSL_CERT_FILE
+
+
+
+
+
+
+
+
+ SSL_CERT_DIR
+
+
+
@@ -1058,6 +1076,24 @@
+
+
+
+
+
+ SSL_CERT_FILE
+
+
+
+
+
+
+
+
+ SSL_CERT_DIR
+
+
+
@@ -1116,6 +1152,22 @@ python -c "i
python -c "import httpx; httpx.get('https://www.python-httpx.org')"
+SSL_CERT_FILE
+Valid values: a filename
+If this environment variable is set then HTTPX will load
+CA certificate from the specified file instead of the default
+location.
+Example:
+SSL_CERT_FILE=/path/to/ca-certs/ca-bundle.crt python -c "import httpx; httpx.get('https://example.com')"
+
+
+SSL_CERT_DIR
+Valid values: a directory following an OpenSSL specific layout.
+If this environment variable is set and the directory follows an OpenSSL specific layout (ie. you ran c_rehash) then HTTPX will load CA certificates from this directory instead of the default location.
+Example:
+SSL_CERT_DIR=/path/to/ca-certs/ python -c "import httpx; httpx.get('https://example.com')"
+
+
diff --git a/img/speakeasy.png b/img/speakeasy.png
index f8a22cca4a496e46f292108a88115369a571cf9a..4acb347c9b30007e450dfc5b41e8a04ed85cda9c 100644
GIT binary patch
literal 115753
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