client = httpx.Client(dispatch=dispatch)
```
+## Build Request
+
+You can use `Client.build_request()` to build a request and
+make modifications before sending the request.
+
+```python
+>>> client = httpx.Client()
+>>> req = client.build_request("OPTIONS", "https://example.com")
+>>> req.url.full_path = "*" # Build an 'OPTIONS *' request for CORS
+>>> client.send(r)
+<Response [200 OK]>
+```
+
## .netrc Support
HTTPX supports .netrc file. In `trust_env=True` cases, if auth parameter is
* `patch(url, [data], [json], [params], [headers], [cookies], [auth], [stream], [allow_redirects], [verify], [cert], [timeout])`
* `delete(url, [data], [json], [params], [headers], [cookies], [auth], [stream], [allow_redirects], [verify], [cert], [timeout])`
* `request(method, url, [data], [params], [headers], [cookies], [auth], [stream], [allow_redirects], [verify], [cert], [timeout])`
+* `build_request(method, url, [data], [files], [json], [params], [headers], [cookies])`
## `Client`
* `def .patch(url, [data], [json], [params], [headers], [cookies], [auth], [stream], [allow_redirects], [verify], [cert], [timeout])`
* `def .delete(url, [data], [json], [params], [headers], [cookies], [auth], [stream], [allow_redirects], [verify], [cert], [timeout])`
* `def .request(method, url, [data], [params], [headers], [cookies], [auth], [stream], [allow_redirects], [verify], [cert], [timeout])`
+* `def .build_request(method, url, [data], [files], [json], [params], [headers], [cookies])`
* `def .send(request, [stream], [allow_redirects], [verify], [cert], [timeout])`
* `def .close()`
return merged_headers
return headers
- async def send(
+ async def _get_response(
self,
request: AsyncRequest,
*,
return None
+ def build_request(
+ self,
+ method: str,
+ url: URLTypes,
+ *,
+ data: AsyncRequestData = None,
+ files: RequestFiles = None,
+ json: typing.Any = None,
+ params: QueryParamTypes = None,
+ headers: HeaderTypes = None,
+ cookies: CookieTypes = None,
+ ) -> AsyncRequest:
+ url = self.merge_url(url)
+ headers = self.merge_headers(headers)
+ cookies = self.merge_cookies(cookies)
+ request = AsyncRequest(
+ method,
+ url,
+ data=data,
+ files=files,
+ json=json,
+ params=params,
+ headers=headers,
+ cookies=cookies,
+ )
+ return request
+
class AsyncClient(BaseClient):
async def get(
timeout: TimeoutTypes = None,
trust_env: bool = None,
) -> AsyncResponse:
- url = self.merge_url(url)
- headers = self.merge_headers(headers)
- cookies = self.merge_cookies(cookies)
- request = AsyncRequest(
- method,
- url,
+ request = self.build_request(
+ method=method,
+ url=url,
data=data,
files=files,
json=json,
)
return response
+ async def send(
+ self,
+ request: AsyncRequest,
+ *,
+ stream: bool = False,
+ auth: AuthTypes = None,
+ allow_redirects: bool = True,
+ verify: VerifyTypes = None,
+ cert: CertTypes = None,
+ timeout: TimeoutTypes = None,
+ trust_env: bool = None,
+ ) -> AsyncResponse:
+ return await self._get_response(
+ request=request,
+ stream=stream,
+ auth=auth,
+ allow_redirects=allow_redirects,
+ verify=verify,
+ cert=cert,
+ timeout=timeout,
+ trust_env=trust_env,
+ )
+
async def close(self) -> None:
await self.dispatch.close()
timeout: TimeoutTypes = None,
trust_env: bool = None,
) -> Response:
- url = self.merge_url(url)
- headers = self.merge_headers(headers)
- cookies = self.merge_cookies(cookies)
- request = AsyncRequest(
- method,
- url,
+ request = self.build_request(
+ method=method,
+ url=url,
data=self._async_request_data(data),
files=files,
json=json,
headers=headers,
cookies=cookies,
)
+ response = self.send(
+ request,
+ stream=stream,
+ auth=auth,
+ allow_redirects=allow_redirects,
+ verify=verify,
+ cert=cert,
+ timeout=timeout,
+ trust_env=trust_env,
+ )
+ return response
+
+ def send(
+ self,
+ request: AsyncRequest,
+ *,
+ stream: bool = False,
+ auth: AuthTypes = None,
+ allow_redirects: bool = True,
+ verify: VerifyTypes = None,
+ cert: CertTypes = None,
+ timeout: TimeoutTypes = None,
+ trust_env: bool = None,
+ ) -> Response:
concurrency_backend = self.concurrency_backend
- coroutine = self.send
+ coroutine = self._get_response
args = [request]
kwargs = {
"stream": True,
assert repr(response) == "<Response [200 OK]>"
+async def test_build_request(server, backend):
+ url = server.url.copy_with(path="/echo_headers")
+ headers = {"Custom-header": "value"}
+ async with httpx.AsyncClient(backend=backend) as client:
+ request = client.build_request("GET", url)
+ request.headers.update(headers)
+ response = await client.send(request)
+
+ assert response.status_code == 200
+ assert response.url == url
+
+ assert response.json()["Custom-header"] == "value"
+
+
@pytest.mark.asyncio
async def test_get_no_backend(server):
"""
assert repr(response) == "<Response [200 OK]>"
+def test_build_request(server):
+ url = server.url.copy_with(path="/echo_headers")
+ headers = {"Custom-header": "value"}
+
+ with httpx.Client() as http:
+ request = http.build_request("GET", url)
+ request.headers.update(headers)
+ response = http.send(request)
+
+ assert response.status_code == 200
+ assert response.url == url
+
+ assert response.json()["Custom-header"] == "value"
+
+
def test_post(server):
with httpx.Client() as http:
response = http.post(server.url, data=b"Hello, world!")
import asyncio
+import json
import os
import threading
import time
await status_code(scope, receive, send)
elif scope["path"].startswith("/echo_body"):
await echo_body(scope, receive, send)
+ elif scope["path"].startswith("/echo_headers"):
+ await echo_headers(scope, receive, send)
else:
await hello_world(scope, receive, send)
await send({"type": "http.response.body", "body": body})
+async def echo_headers(scope, receive, send):
+ body = {}
+ for name, value in scope.get("headers", []):
+ body[name.capitalize().decode()] = value.decode()
+
+ await send(
+ {
+ "type": "http.response.start",
+ "status": 200,
+ "headers": [[b"content-type", b"application/json"]],
+ }
+ )
+ await send({"type": "http.response.body", "body": json.dumps(body).encode()})
+
+
class CAWithPKEncryption(trustme.CA):
"""Implementation of trustme.CA() that can emit
private keys that are encrypted with a password.