Seperate content=... and data=... parameters (#1266)
* Seperate content=... and data=... parameters * Update compatibility.md
This commit is contained in:
parent
54f7708e2b
commit
feb404f86b
@ -9,6 +9,28 @@ This documentation outlines places where the API differs...
|
||||
Accessing `response.url` will return a `URL` instance, rather than a string.
|
||||
Use `str(response.url)` if you need a string instance.
|
||||
|
||||
## Request Content
|
||||
|
||||
For uploading raw text or binary content we prefer to use a `content` parameter,
|
||||
in order to better separate this usage from the case of uploading form data.
|
||||
|
||||
For example, using `content=...` to upload raw content:
|
||||
|
||||
```python
|
||||
# Uploading text, bytes, or a bytes iterator.
|
||||
httpx.post(..., content=b"Hello, world")
|
||||
```
|
||||
|
||||
And using `data=...` to send form data:
|
||||
|
||||
```python
|
||||
# Uploading form data.
|
||||
httpx.post(..., data={"message": "Hello, world"})
|
||||
```
|
||||
|
||||
If you're using a type checking tool such as `mypy`, you'll see warnings issues if using test/byte content with the `data` argument.
|
||||
However, for compatibility reasons with `requests`, we do still handle the case where `data=...` is used with raw binary and text contents.
|
||||
|
||||
## Status Codes
|
||||
|
||||
In our documentation we prefer the uppercased versions, such as `codes.NOT_FOUND`, but also provide lower-cased versions for API compatibility with `requests`.
|
||||
|
||||
@ -249,13 +249,18 @@ For more complicated data structures you'll often want to use JSON encoding inst
|
||||
|
||||
## Sending Binary Request Data
|
||||
|
||||
For other encodings, you should use either a `bytes` type or a generator
|
||||
that yields `bytes`.
|
||||
For other encodings, you should use the `content=...` parameter, passing
|
||||
either a `bytes` type or a generator that yields `bytes`.
|
||||
|
||||
You'll probably also want to set a custom `Content-Type` header when uploading
|
||||
```pycon
|
||||
>>> content = b'Hello, world'
|
||||
>>> r = httpx.post("https://httpbin.org/post", content=content)
|
||||
```
|
||||
|
||||
You may also want to set a custom `Content-Type` header when uploading
|
||||
binary data.
|
||||
|
||||
## Response Status Codes
|
||||
## Response Status Codes
|
||||
|
||||
We can inspect the HTTP status code of the response:
|
||||
|
||||
|
||||
@ -10,6 +10,7 @@ from ._types import (
|
||||
HeaderTypes,
|
||||
ProxiesTypes,
|
||||
QueryParamTypes,
|
||||
RequestContent,
|
||||
RequestData,
|
||||
RequestFiles,
|
||||
TimeoutTypes,
|
||||
@ -23,6 +24,7 @@ def request(
|
||||
url: URLTypes,
|
||||
*,
|
||||
params: QueryParamTypes = None,
|
||||
content: RequestContent = None,
|
||||
data: RequestData = None,
|
||||
files: RequestFiles = None,
|
||||
json: typing.Any = None,
|
||||
@ -46,8 +48,10 @@ def request(
|
||||
* **url** - URL for the new `Request` object.
|
||||
* **params** - *(optional)* Query parameters to include in the URL, as a
|
||||
string, dictionary, or list of two-tuples.
|
||||
* **data** - *(optional)* Data to include in the body of the request, as a
|
||||
dictionary
|
||||
* **content** - *(optional)* Binary content to include in the body of the
|
||||
request, as bytes or a byte iterator.
|
||||
* **data** - *(optional)* Form data to include in the body of the request,
|
||||
as a dictionary.
|
||||
* **files** - *(optional)* A dictionary of upload files to include in the
|
||||
body of the request.
|
||||
* **json** - *(optional)* A JSON serializable object to include in the body
|
||||
@ -89,6 +93,7 @@ def request(
|
||||
return client.request(
|
||||
method=method,
|
||||
url=url,
|
||||
content=content,
|
||||
data=data,
|
||||
files=files,
|
||||
json=json,
|
||||
@ -105,6 +110,7 @@ def stream(
|
||||
url: URLTypes,
|
||||
*,
|
||||
params: QueryParamTypes = None,
|
||||
content: RequestContent = None,
|
||||
data: RequestData = None,
|
||||
files: RequestFiles = None,
|
||||
json: typing.Any = None,
|
||||
@ -133,6 +139,7 @@ def stream(
|
||||
method=method,
|
||||
url=url,
|
||||
params=params,
|
||||
content=content,
|
||||
data=data,
|
||||
files=files,
|
||||
json=json,
|
||||
@ -266,6 +273,7 @@ def head(
|
||||
def post(
|
||||
url: URLTypes,
|
||||
*,
|
||||
content: RequestContent = None,
|
||||
data: RequestData = None,
|
||||
files: RequestFiles = None,
|
||||
json: typing.Any = None,
|
||||
@ -288,6 +296,7 @@ def post(
|
||||
return request(
|
||||
"POST",
|
||||
url,
|
||||
content=content,
|
||||
data=data,
|
||||
files=files,
|
||||
json=json,
|
||||
@ -307,6 +316,7 @@ def post(
|
||||
def put(
|
||||
url: URLTypes,
|
||||
*,
|
||||
content: RequestContent = None,
|
||||
data: RequestData = None,
|
||||
files: RequestFiles = None,
|
||||
json: typing.Any = None,
|
||||
@ -329,6 +339,7 @@ def put(
|
||||
return request(
|
||||
"PUT",
|
||||
url,
|
||||
content=content,
|
||||
data=data,
|
||||
files=files,
|
||||
json=json,
|
||||
@ -348,6 +359,7 @@ def put(
|
||||
def patch(
|
||||
url: URLTypes,
|
||||
*,
|
||||
content: RequestContent = None,
|
||||
data: RequestData = None,
|
||||
files: RequestFiles = None,
|
||||
json: typing.Any = None,
|
||||
@ -370,6 +382,7 @@ def patch(
|
||||
return request(
|
||||
"PATCH",
|
||||
url,
|
||||
content=content,
|
||||
data=data,
|
||||
files=files,
|
||||
json=json,
|
||||
|
||||
@ -39,6 +39,7 @@ from ._types import (
|
||||
HeaderTypes,
|
||||
ProxiesTypes,
|
||||
QueryParamTypes,
|
||||
RequestContent,
|
||||
RequestData,
|
||||
RequestFiles,
|
||||
TimeoutTypes,
|
||||
@ -226,6 +227,7 @@ class BaseClient:
|
||||
method: str,
|
||||
url: URLTypes,
|
||||
*,
|
||||
content: RequestContent = None,
|
||||
data: RequestData = None,
|
||||
files: RequestFiles = None,
|
||||
json: typing.Any = None,
|
||||
@ -249,6 +251,7 @@ class BaseClient:
|
||||
request = self.build_request(
|
||||
method=method,
|
||||
url=url,
|
||||
content=content,
|
||||
data=data,
|
||||
files=files,
|
||||
json=json,
|
||||
@ -269,6 +272,7 @@ class BaseClient:
|
||||
method: str,
|
||||
url: URLTypes,
|
||||
*,
|
||||
content: RequestContent = None,
|
||||
data: RequestData = None,
|
||||
files: RequestFiles = None,
|
||||
json: typing.Any = None,
|
||||
@ -294,6 +298,7 @@ class BaseClient:
|
||||
return Request(
|
||||
method,
|
||||
url,
|
||||
content=content,
|
||||
data=data,
|
||||
files=files,
|
||||
json=json,
|
||||
@ -679,6 +684,7 @@ class Client(BaseClient):
|
||||
method: str,
|
||||
url: URLTypes,
|
||||
*,
|
||||
content: RequestContent = None,
|
||||
data: RequestData = None,
|
||||
files: RequestFiles = None,
|
||||
json: typing.Any = None,
|
||||
@ -708,6 +714,7 @@ class Client(BaseClient):
|
||||
request = self.build_request(
|
||||
method=method,
|
||||
url=url,
|
||||
content=content,
|
||||
data=data,
|
||||
files=files,
|
||||
json=json,
|
||||
@ -962,6 +969,7 @@ class Client(BaseClient):
|
||||
self,
|
||||
url: URLTypes,
|
||||
*,
|
||||
content: RequestContent = None,
|
||||
data: RequestData = None,
|
||||
files: RequestFiles = None,
|
||||
json: typing.Any = None,
|
||||
@ -980,6 +988,7 @@ class Client(BaseClient):
|
||||
return self.request(
|
||||
"POST",
|
||||
url,
|
||||
content=content,
|
||||
data=data,
|
||||
files=files,
|
||||
json=json,
|
||||
@ -995,6 +1004,7 @@ class Client(BaseClient):
|
||||
self,
|
||||
url: URLTypes,
|
||||
*,
|
||||
content: RequestContent = None,
|
||||
data: RequestData = None,
|
||||
files: RequestFiles = None,
|
||||
json: typing.Any = None,
|
||||
@ -1013,6 +1023,7 @@ class Client(BaseClient):
|
||||
return self.request(
|
||||
"PUT",
|
||||
url,
|
||||
content=content,
|
||||
data=data,
|
||||
files=files,
|
||||
json=json,
|
||||
@ -1028,6 +1039,7 @@ class Client(BaseClient):
|
||||
self,
|
||||
url: URLTypes,
|
||||
*,
|
||||
content: RequestContent = None,
|
||||
data: RequestData = None,
|
||||
files: RequestFiles = None,
|
||||
json: typing.Any = None,
|
||||
@ -1046,6 +1058,7 @@ class Client(BaseClient):
|
||||
return self.request(
|
||||
"PATCH",
|
||||
url,
|
||||
content=content,
|
||||
data=data,
|
||||
files=files,
|
||||
json=json,
|
||||
@ -1313,6 +1326,7 @@ class AsyncClient(BaseClient):
|
||||
method: str,
|
||||
url: URLTypes,
|
||||
*,
|
||||
content: RequestContent = None,
|
||||
data: RequestData = None,
|
||||
files: RequestFiles = None,
|
||||
json: typing.Any = None,
|
||||
@ -1342,6 +1356,7 @@ class AsyncClient(BaseClient):
|
||||
request = self.build_request(
|
||||
method=method,
|
||||
url=url,
|
||||
content=content,
|
||||
data=data,
|
||||
files=files,
|
||||
json=json,
|
||||
@ -1599,6 +1614,7 @@ class AsyncClient(BaseClient):
|
||||
self,
|
||||
url: URLTypes,
|
||||
*,
|
||||
content: RequestContent = None,
|
||||
data: RequestData = None,
|
||||
files: RequestFiles = None,
|
||||
json: typing.Any = None,
|
||||
@ -1617,6 +1633,7 @@ class AsyncClient(BaseClient):
|
||||
return await self.request(
|
||||
"POST",
|
||||
url,
|
||||
content=content,
|
||||
data=data,
|
||||
files=files,
|
||||
json=json,
|
||||
@ -1632,6 +1649,7 @@ class AsyncClient(BaseClient):
|
||||
self,
|
||||
url: URLTypes,
|
||||
*,
|
||||
content: RequestContent = None,
|
||||
data: RequestData = None,
|
||||
files: RequestFiles = None,
|
||||
json: typing.Any = None,
|
||||
@ -1650,6 +1668,7 @@ class AsyncClient(BaseClient):
|
||||
return await self.request(
|
||||
"PUT",
|
||||
url,
|
||||
content=content,
|
||||
data=data,
|
||||
files=files,
|
||||
json=json,
|
||||
@ -1665,6 +1684,7 @@ class AsyncClient(BaseClient):
|
||||
self,
|
||||
url: URLTypes,
|
||||
*,
|
||||
content: RequestContent = None,
|
||||
data: RequestData = None,
|
||||
files: RequestFiles = None,
|
||||
json: typing.Any = None,
|
||||
@ -1683,6 +1703,7 @@ class AsyncClient(BaseClient):
|
||||
return await self.request(
|
||||
"PATCH",
|
||||
url,
|
||||
content=content,
|
||||
data=data,
|
||||
files=files,
|
||||
json=json,
|
||||
|
||||
@ -8,7 +8,14 @@ from urllib.parse import urlencode
|
||||
import httpcore
|
||||
|
||||
from ._exceptions import StreamConsumed
|
||||
from ._types import FileContent, FileTypes, RequestData, RequestFiles, ResponseContent
|
||||
from ._types import (
|
||||
FileContent,
|
||||
FileTypes,
|
||||
RequestContent,
|
||||
RequestData,
|
||||
RequestFiles,
|
||||
ResponseContent,
|
||||
)
|
||||
from ._utils import (
|
||||
format_form_param,
|
||||
guess_content_type,
|
||||
@ -357,35 +364,52 @@ class MultipartStream(ContentStream):
|
||||
|
||||
|
||||
def encode(
|
||||
content: RequestContent = None,
|
||||
data: RequestData = None,
|
||||
files: RequestFiles = None,
|
||||
json: typing.Any = None,
|
||||
boundary: bytes = None,
|
||||
) -> ContentStream:
|
||||
"""
|
||||
Handles encoding the given `data`, `files`, and `json`, returning
|
||||
a `ContentStream` implementation.
|
||||
Handles encoding the given `content`, `data`, `files`, and `json`,
|
||||
returning a `ContentStream` implementation.
|
||||
"""
|
||||
if not data:
|
||||
if json is not None:
|
||||
return JSONStream(json=json)
|
||||
elif files:
|
||||
return MultipartStream(data={}, files=files, boundary=boundary)
|
||||
if data is not None and not isinstance(data, dict):
|
||||
# We prefer to seperate `content=<bytes|byte iterator|bytes aiterator>`
|
||||
# for raw request content, and `data=<form data>` for url encoded or
|
||||
# multipart form content.
|
||||
#
|
||||
# However for compat with requests, we *do* still support
|
||||
# `data=<bytes...>` usages. We deal with that case here, treating it
|
||||
# as if `content=<...>` had been supplied instead.
|
||||
content = data
|
||||
data = None
|
||||
|
||||
if content is not None:
|
||||
if isinstance(content, (str, bytes)):
|
||||
return ByteStream(body=content)
|
||||
elif hasattr(content, "__aiter__"):
|
||||
content = typing.cast(typing.AsyncIterator[bytes], content)
|
||||
return AsyncIteratorStream(aiterator=content)
|
||||
elif hasattr(content, "__iter__"):
|
||||
content = typing.cast(typing.Iterator[bytes], content)
|
||||
return IteratorStream(iterator=content)
|
||||
else:
|
||||
return ByteStream(body=b"")
|
||||
elif isinstance(data, dict):
|
||||
raise TypeError(f"Unexpected type for 'content', {type(content)!r}")
|
||||
|
||||
elif data:
|
||||
if files:
|
||||
return MultipartStream(data=data, files=files, boundary=boundary)
|
||||
else:
|
||||
return URLEncodedStream(data=data)
|
||||
elif isinstance(data, (str, bytes)):
|
||||
return ByteStream(body=data)
|
||||
elif isinstance(data, typing.AsyncIterator):
|
||||
return AsyncIteratorStream(aiterator=data)
|
||||
elif isinstance(data, typing.Iterator):
|
||||
return IteratorStream(iterator=data)
|
||||
|
||||
raise TypeError(f"Unexpected type for 'data', {type(data)!r}")
|
||||
elif files:
|
||||
return MultipartStream(data={}, files=files, boundary=boundary)
|
||||
|
||||
elif json is not None:
|
||||
return JSONStream(json=json)
|
||||
|
||||
return ByteStream(body=b"")
|
||||
|
||||
|
||||
def encode_response(content: ResponseContent = None) -> ContentStream:
|
||||
|
||||
@ -41,6 +41,7 @@ from ._types import (
|
||||
HeaderTypes,
|
||||
PrimitiveData,
|
||||
QueryParamTypes,
|
||||
RequestContent,
|
||||
RequestData,
|
||||
RequestFiles,
|
||||
ResponseContent,
|
||||
@ -590,6 +591,7 @@ class Request:
|
||||
params: QueryParamTypes = None,
|
||||
headers: HeaderTypes = None,
|
||||
cookies: CookieTypes = None,
|
||||
content: RequestContent = None,
|
||||
data: RequestData = None,
|
||||
files: RequestFiles = None,
|
||||
json: typing.Any = None,
|
||||
@ -604,7 +606,7 @@ class Request:
|
||||
if stream is not None:
|
||||
self.stream = stream
|
||||
else:
|
||||
self.stream = encode(data, files, json)
|
||||
self.stream = encode(content, data, files, json)
|
||||
|
||||
self._prepare()
|
||||
|
||||
|
||||
@ -64,9 +64,10 @@ AuthTypes = Union[
|
||||
None,
|
||||
]
|
||||
|
||||
RequestContent = Union[str, bytes, Iterator[bytes], AsyncIterator[bytes]]
|
||||
ResponseContent = Union[bytes, Iterator[bytes], AsyncIterator[bytes]]
|
||||
|
||||
RequestData = Union[dict, str, bytes, Iterator[bytes], AsyncIterator[bytes]]
|
||||
RequestData = dict
|
||||
|
||||
FileContent = Union[IO[str], IO[bytes], str, bytes]
|
||||
FileTypes = Union[
|
||||
|
||||
@ -56,7 +56,7 @@ async def test_build_request(server):
|
||||
async def test_post(server):
|
||||
url = server.url
|
||||
async with httpx.AsyncClient() as client:
|
||||
response = await client.post(url, data=b"Hello, world!")
|
||||
response = await client.post(url, content=b"Hello, world!")
|
||||
assert response.status_code == 200
|
||||
|
||||
|
||||
@ -97,7 +97,7 @@ async def test_stream_request(server):
|
||||
yield b"world!"
|
||||
|
||||
async with httpx.AsyncClient() as client:
|
||||
response = await client.request("POST", server.url, data=hello_world())
|
||||
response = await client.request("POST", server.url, content=hello_world())
|
||||
assert response.status_code == 200
|
||||
|
||||
|
||||
@ -136,14 +136,14 @@ async def test_head(server):
|
||||
@pytest.mark.usefixtures("async_environment")
|
||||
async def test_put(server):
|
||||
async with httpx.AsyncClient() as client:
|
||||
response = await client.put(server.url, data=b"Hello, world!")
|
||||
response = await client.put(server.url, content=b"Hello, world!")
|
||||
assert response.status_code == 200
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("async_environment")
|
||||
async def test_patch(server):
|
||||
async with httpx.AsyncClient() as client:
|
||||
response = await client.patch(server.url, data=b"Hello, world!")
|
||||
response = await client.patch(server.url, content=b"Hello, world!")
|
||||
assert response.status_code == 200
|
||||
|
||||
|
||||
@ -158,15 +158,15 @@ async def test_delete(server):
|
||||
@pytest.mark.usefixtures("async_environment")
|
||||
async def test_100_continue(server):
|
||||
headers = {"Expect": "100-continue"}
|
||||
data = b"Echo request body"
|
||||
content = b"Echo request body"
|
||||
|
||||
async with httpx.AsyncClient() as client:
|
||||
response = await client.post(
|
||||
server.url.copy_with(path="/echo_body"), headers=headers, data=data
|
||||
server.url.copy_with(path="/echo_body"), headers=headers, content=content
|
||||
)
|
||||
|
||||
assert response.status_code == 200
|
||||
assert response.content == data
|
||||
assert response.content == content
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("async_environment")
|
||||
|
||||
@ -73,7 +73,7 @@ def test_build_post_request(server):
|
||||
|
||||
def test_post(server):
|
||||
with httpx.Client() as client:
|
||||
response = client.post(server.url, data=b"Hello, world!")
|
||||
response = client.post(server.url, content=b"Hello, world!")
|
||||
assert response.status_code == 200
|
||||
assert response.reason_phrase == "OK"
|
||||
|
||||
@ -148,14 +148,14 @@ def test_head(server):
|
||||
|
||||
def test_put(server):
|
||||
with httpx.Client() as client:
|
||||
response = client.put(server.url, data=b"Hello, world!")
|
||||
response = client.put(server.url, content=b"Hello, world!")
|
||||
assert response.status_code == 200
|
||||
assert response.reason_phrase == "OK"
|
||||
|
||||
|
||||
def test_patch(server):
|
||||
with httpx.Client() as client:
|
||||
response = client.patch(server.url, data=b"Hello, world!")
|
||||
response = client.patch(server.url, content=b"Hello, world!")
|
||||
assert response.status_code == 200
|
||||
assert response.reason_phrase == "OK"
|
||||
|
||||
|
||||
@ -298,8 +298,8 @@ def test_body_redirect():
|
||||
"""
|
||||
client = httpx.Client(transport=MockTransport(redirects))
|
||||
url = "https://example.org/redirect_body"
|
||||
data = b"Example request body"
|
||||
response = client.post(url, data=data)
|
||||
content = b"Example request body"
|
||||
response = client.post(url, content=content)
|
||||
assert response.url == "https://example.org/redirect_body_target"
|
||||
assert response.json()["body"] == "Example request body"
|
||||
assert "content-length" in response.json()["headers"]
|
||||
@ -311,8 +311,8 @@ def test_no_body_redirect():
|
||||
"""
|
||||
client = httpx.Client(transport=MockTransport(redirects))
|
||||
url = "https://example.org/redirect_no_body"
|
||||
data = b"Example request body"
|
||||
response = client.post(url, data=data)
|
||||
content = b"Example request body"
|
||||
response = client.post(url, content=content)
|
||||
assert response.url == "https://example.org/redirect_body_target"
|
||||
assert response.json()["body"] == ""
|
||||
assert "content-length" not in response.json()["headers"]
|
||||
@ -335,7 +335,7 @@ def test_cannot_redirect_streaming_body():
|
||||
yield b"Example request body" # pragma: nocover
|
||||
|
||||
with pytest.raises(httpx.RequestBodyUnavailable):
|
||||
client.post(url, data=streaming_body())
|
||||
client.post(url, content=streaming_body())
|
||||
|
||||
|
||||
def test_cross_subdomain_redirect():
|
||||
|
||||
@ -14,7 +14,7 @@ def test_no_content():
|
||||
|
||||
|
||||
def test_content_length_header():
|
||||
request = httpx.Request("POST", "http://example.org", data=b"test 123")
|
||||
request = httpx.Request("POST", "http://example.org", content=b"test 123")
|
||||
assert request.headers["Content-Length"] == "8"
|
||||
|
||||
|
||||
|
||||
@ -12,7 +12,7 @@ def test_get(server):
|
||||
|
||||
|
||||
def test_post(server):
|
||||
response = httpx.post(server.url, data=b"Hello, world!")
|
||||
response = httpx.post(server.url, content=b"Hello, world!")
|
||||
assert response.status_code == 200
|
||||
assert response.reason_phrase == "OK"
|
||||
|
||||
@ -23,7 +23,7 @@ def test_post_byte_iterator(server):
|
||||
yield b", "
|
||||
yield b"world!"
|
||||
|
||||
response = httpx.post(server.url, data=data())
|
||||
response = httpx.post(server.url, content=data())
|
||||
assert response.status_code == 200
|
||||
assert response.reason_phrase == "OK"
|
||||
|
||||
@ -41,13 +41,13 @@ def test_head(server):
|
||||
|
||||
|
||||
def test_put(server):
|
||||
response = httpx.put(server.url, data=b"Hello, world!")
|
||||
response = httpx.put(server.url, content=b"Hello, world!")
|
||||
assert response.status_code == 200
|
||||
assert response.reason_phrase == "OK"
|
||||
|
||||
|
||||
def test_patch(server):
|
||||
response = httpx.patch(server.url, data=b"Hello, world!")
|
||||
response = httpx.patch(server.url, content=b"Hello, world!")
|
||||
assert response.status_code == 200
|
||||
assert response.reason_phrase == "OK"
|
||||
|
||||
|
||||
@ -51,7 +51,7 @@ async def test_asgi():
|
||||
@pytest.mark.usefixtures("async_environment")
|
||||
async def test_asgi_upload():
|
||||
async with httpx.AsyncClient(app=echo_body) as client:
|
||||
response = await client.post("http://www.example.org/", data=b"example")
|
||||
response = await client.post("http://www.example.org/", content=b"example")
|
||||
|
||||
assert response.status_code == 200
|
||||
assert response.text == "example"
|
||||
@ -99,7 +99,7 @@ async def test_asgi_disconnect_after_response_complete():
|
||||
disconnect = message.get("type") == "http.disconnect"
|
||||
|
||||
async with httpx.AsyncClient(app=read_body) as client:
|
||||
response = await client.post("http://www.example.org/", data=b"example")
|
||||
response = await client.post("http://www.example.org/", content=b"example")
|
||||
|
||||
assert response.status_code == 200
|
||||
assert disconnect
|
||||
|
||||
@ -32,7 +32,17 @@ async def test_empty_content():
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_bytes_content():
|
||||
stream = encode(data=b"Hello, world!")
|
||||
stream = encode(content=b"Hello, world!")
|
||||
sync_content = b"".join([part for part in stream])
|
||||
async_content = b"".join([part async for part in stream])
|
||||
|
||||
assert stream.can_replay()
|
||||
assert stream.get_headers() == {"Content-Length": "13"}
|
||||
assert sync_content == b"Hello, world!"
|
||||
assert async_content == b"Hello, world!"
|
||||
|
||||
# Support 'data' for compat with requests.
|
||||
stream = encode(data=b"Hello, world!") # type: ignore
|
||||
sync_content = b"".join([part for part in stream])
|
||||
async_content = b"".join([part async for part in stream])
|
||||
|
||||
@ -48,7 +58,7 @@ async def test_iterator_content():
|
||||
yield b"Hello, "
|
||||
yield b"world!"
|
||||
|
||||
stream = encode(data=hello_world())
|
||||
stream = encode(content=hello_world())
|
||||
content = b"".join([part for part in stream])
|
||||
|
||||
assert not stream.can_replay()
|
||||
@ -61,6 +71,14 @@ async def test_iterator_content():
|
||||
with pytest.raises(StreamConsumed):
|
||||
[part for part in stream]
|
||||
|
||||
# Support 'data' for compat with requests.
|
||||
stream = encode(data=hello_world()) # type: ignore
|
||||
content = b"".join([part for part in stream])
|
||||
|
||||
assert not stream.can_replay()
|
||||
assert stream.get_headers() == {"Transfer-Encoding": "chunked"}
|
||||
assert content == b"Hello, world!"
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_aiterator_content():
|
||||
@ -68,7 +86,7 @@ async def test_aiterator_content():
|
||||
yield b"Hello, "
|
||||
yield b"world!"
|
||||
|
||||
stream = encode(data=hello_world())
|
||||
stream = encode(content=hello_world())
|
||||
content = b"".join([part async for part in stream])
|
||||
|
||||
assert not stream.can_replay()
|
||||
@ -81,6 +99,14 @@ async def test_aiterator_content():
|
||||
with pytest.raises(StreamConsumed):
|
||||
[part async for part in stream]
|
||||
|
||||
# Support 'data' for compat with requests.
|
||||
stream = encode(data=hello_world()) # type: ignore
|
||||
content = b"".join([part async for part in stream])
|
||||
|
||||
assert not stream.can_replay()
|
||||
assert stream.get_headers() == {"Transfer-Encoding": "chunked"}
|
||||
assert content == b"Hello, world!"
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_json_content():
|
||||
|
||||
@ -19,7 +19,7 @@ async def test_write_timeout(server):
|
||||
async with httpx.AsyncClient(timeout=timeout) as client:
|
||||
with pytest.raises(httpx.WriteTimeout):
|
||||
data = b"*" * 1024 * 1024 * 100
|
||||
await client.put(server.url.copy_with(path="/slow_response"), data=data)
|
||||
await client.put(server.url.copy_with(path="/slow_response"), content=data)
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("async_environment")
|
||||
|
||||
@ -78,14 +78,14 @@ def test_wsgi():
|
||||
|
||||
def test_wsgi_upload():
|
||||
client = httpx.Client(app=echo_body)
|
||||
response = client.post("http://www.example.org/", data=b"example")
|
||||
response = client.post("http://www.example.org/", content=b"example")
|
||||
assert response.status_code == 200
|
||||
assert response.text == "example"
|
||||
|
||||
|
||||
def test_wsgi_upload_with_response_stream():
|
||||
client = httpx.Client(app=echo_body_with_response_stream)
|
||||
response = client.post("http://www.example.org/", data=b"example")
|
||||
response = client.post("http://www.example.org/", content=b"example")
|
||||
assert response.status_code == 200
|
||||
assert response.text == "example"
|
||||
|
||||
|
||||
@ -43,7 +43,7 @@ class MockTransport(httpcore.SyncHTTPTransport):
|
||||
path = raw_path.decode("ascii")
|
||||
|
||||
request_headers = httpx.Headers(headers)
|
||||
data = (
|
||||
content = (
|
||||
(item for item in stream)
|
||||
if stream
|
||||
and (
|
||||
@ -57,7 +57,7 @@ class MockTransport(httpcore.SyncHTTPTransport):
|
||||
method=method.decode("ascii"),
|
||||
url=f"{scheme}://{host}{port_str}{path}",
|
||||
headers=request_headers,
|
||||
data=data,
|
||||
content=content,
|
||||
)
|
||||
request.read()
|
||||
response = self.handler(request)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user