Add build_request to Client (#319)
* Update documentation * Update documentation * Update tests Rename `_send` -> `_get_response` Update documentation * Code format with black * Change documentation example to OPTIONS * * Update documentation Small code reformat * `echo_headers` return json * Simplify test * Fix typo
This commit is contained in:
parent
71648ece09
commit
08edfac37d
@ -57,6 +57,19 @@ dispatch = httpx.WSGIDispatch(app=app, remote_addr="1.2.3.4")
|
||||
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
|
||||
|
||||
@ -16,6 +16,7 @@
|
||||
* `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`
|
||||
|
||||
@ -37,6 +38,7 @@
|
||||
* `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()`
|
||||
|
||||
|
||||
@ -151,7 +151,7 @@ class BaseClient:
|
||||
return merged_headers
|
||||
return headers
|
||||
|
||||
async def send(
|
||||
async def _get_response(
|
||||
self,
|
||||
request: AsyncRequest,
|
||||
*,
|
||||
@ -235,6 +235,33 @@ class BaseClient:
|
||||
|
||||
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(
|
||||
@ -490,12 +517,9 @@ class AsyncClient(BaseClient):
|
||||
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,
|
||||
@ -515,6 +539,29 @@ class AsyncClient(BaseClient):
|
||||
)
|
||||
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()
|
||||
|
||||
@ -592,12 +639,9 @@ class Client(BaseClient):
|
||||
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,
|
||||
@ -605,9 +649,33 @@ class Client(BaseClient):
|
||||
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,
|
||||
|
||||
@ -14,6 +14,20 @@ async def test_get(server, backend):
|
||||
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):
|
||||
"""
|
||||
|
||||
@ -19,6 +19,21 @@ def test_get(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!")
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import asyncio
|
||||
import json
|
||||
import os
|
||||
import threading
|
||||
import time
|
||||
@ -53,6 +54,8 @@ async def app(scope, receive, send):
|
||||
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)
|
||||
|
||||
@ -111,6 +114,21 @@ async def echo_body(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.
|
||||
|
||||
Loading…
Reference in New Issue
Block a user