Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion httpcore/adapters/redirects.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ def build_redirect_request(self, request: Request, response: Response) -> Reques
url = self.redirect_url(request, response)
headers = self.redirect_headers(request, url)
content = self.redirect_content(request, method)
return Request(method=method, url=url, headers=headers, content=content)
return Request(method=method, url=url, headers=headers, data=content)

def redirect_method(self, request: Request, response: Response) -> str:
"""
Expand Down
33 changes: 22 additions & 11 deletions httpcore/backends/sync.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,11 @@
)
from ..models import (
URL,
ByteOrByteStream,
Headers,
HeaderTypes,
QueryParamTypes,
Request,
RequestData,
Response,
URLTypes,
)
Expand Down Expand Up @@ -100,14 +101,17 @@ def request(
method: str,
url: URLTypes,
*,
content: ByteOrByteStream = b"",
data: RequestData = b"",
query_params: QueryParamTypes = None,
headers: HeaderTypes = None,
stream: bool = False,
allow_redirects: bool = True,
ssl: SSLConfig = None,
timeout: TimeoutConfig = None,
) -> SyncResponse:
request = Request(method, url, headers=headers, content=content)
request = Request(
method, url, data=data, query_params=query_params, headers=headers
)
self.prepare_request(request)
response = self.send(
request,
Expand All @@ -122,6 +126,7 @@ def get(
self,
url: URLTypes,
*,
query_params: QueryParamTypes = None,
headers: HeaderTypes = None,
stream: bool = False,
allow_redirects: bool = True,
Expand All @@ -142,6 +147,7 @@ def options(
self,
url: URLTypes,
*,
query_params: QueryParamTypes = None,
headers: HeaderTypes = None,
stream: bool = False,
allow_redirects: bool = True,
Expand All @@ -162,6 +168,7 @@ def head(
self,
url: URLTypes,
*,
query_params: QueryParamTypes = None,
headers: HeaderTypes = None,
stream: bool = False,
allow_redirects: bool = False, #  Note: Differs to usual default.
Expand All @@ -182,7 +189,8 @@ def post(
self,
url: URLTypes,
*,
content: ByteOrByteStream = b"",
data: RequestData = b"",
query_params: QueryParamTypes = None,
headers: HeaderTypes = None,
stream: bool = False,
allow_redirects: bool = True,
Expand All @@ -192,7 +200,7 @@ def post(
return self.request(
"POST",
url,
content=content,
data=data,
headers=headers,
stream=stream,
allow_redirects=allow_redirects,
Expand All @@ -204,7 +212,8 @@ def put(
self,
url: URLTypes,
*,
content: ByteOrByteStream = b"",
data: RequestData = b"",
query_params: QueryParamTypes = None,
headers: HeaderTypes = None,
stream: bool = False,
allow_redirects: bool = True,
Expand All @@ -214,7 +223,7 @@ def put(
return self.request(
"PUT",
url,
content=content,
data=data,
headers=headers,
stream=stream,
allow_redirects=allow_redirects,
Expand All @@ -226,7 +235,8 @@ def patch(
self,
url: URLTypes,
*,
content: ByteOrByteStream = b"",
data: RequestData = b"",
query_params: QueryParamTypes = None,
headers: HeaderTypes = None,
stream: bool = False,
allow_redirects: bool = True,
Expand All @@ -236,7 +246,7 @@ def patch(
return self.request(
"PATCH",
url,
content=content,
data=data,
headers=headers,
stream=stream,
allow_redirects=allow_redirects,
Expand All @@ -248,7 +258,8 @@ def delete(
self,
url: URLTypes,
*,
content: ByteOrByteStream = b"",
data: RequestData = b"",
query_params: QueryParamTypes = None,
headers: HeaderTypes = None,
stream: bool = False,
allow_redirects: bool = True,
Expand All @@ -258,7 +269,7 @@ def delete(
return self.request(
"DELETE",
url,
content=content,
data=data,
headers=headers,
stream=stream,
allow_redirects=allow_redirects,
Expand Down
22 changes: 11 additions & 11 deletions httpcore/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@
from .dispatch.connection_pool import ConnectionPool
from .models import (
URL,
ByteOrByteStream,
HeaderTypes,
QueryParamTypes,
Request,
RequestData,
Response,
URLTypes,
)
Expand Down Expand Up @@ -49,7 +49,7 @@ async def request(
method: str,
url: URLTypes,
*,
content: ByteOrByteStream = b"",
data: RequestData = b"",
query_params: QueryParamTypes = None,
headers: HeaderTypes = None,
stream: bool = False,
Expand All @@ -58,7 +58,7 @@ async def request(
timeout: TimeoutConfig = None,
) -> Response:
request = Request(
method, url, query_params=query_params, headers=headers, content=content
method, url, data=data, query_params=query_params, headers=headers
)
self.prepare_request(request)
response = await self.send(
Expand Down Expand Up @@ -140,7 +140,7 @@ async def post(
self,
url: URLTypes,
*,
content: ByteOrByteStream = b"",
data: RequestData = b"",
query_params: QueryParamTypes = None,
headers: HeaderTypes = None,
stream: bool = False,
Expand All @@ -151,7 +151,7 @@ async def post(
return await self.request(
"POST",
url,
content=content,
data=data,
query_params=query_params,
headers=headers,
stream=stream,
Expand All @@ -164,7 +164,7 @@ async def put(
self,
url: URLTypes,
*,
content: ByteOrByteStream = b"",
data: RequestData = b"",
query_params: QueryParamTypes = None,
headers: HeaderTypes = None,
stream: bool = False,
Expand All @@ -175,7 +175,7 @@ async def put(
return await self.request(
"PUT",
url,
content=content,
data=data,
query_params=query_params,
headers=headers,
stream=stream,
Expand All @@ -188,7 +188,7 @@ async def patch(
self,
url: URLTypes,
*,
content: ByteOrByteStream = b"",
data: RequestData = b"",
query_params: QueryParamTypes = None,
headers: HeaderTypes = None,
stream: bool = False,
Expand All @@ -199,7 +199,7 @@ async def patch(
return await self.request(
"PATCH",
url,
content=content,
data=data,
query_params=query_params,
headers=headers,
stream=stream,
Expand All @@ -212,7 +212,7 @@ async def delete(
self,
url: URLTypes,
*,
content: ByteOrByteStream = b"",
data: RequestData = b"",
query_params: QueryParamTypes = None,
headers: HeaderTypes = None,
stream: bool = False,
Expand All @@ -223,7 +223,7 @@ async def delete(
return await self.request(
"DELETE",
url,
content=content,
data=data,
query_params=query_params,
headers=headers,
stream=stream,
Expand Down
17 changes: 14 additions & 3 deletions httpcore/interfaces.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,15 @@
from types import TracebackType

from .config import TimeoutConfig
from .models import URL, ByteOrByteStream, HeaderTypes, Request, Response, URLTypes
from .models import (
URL,
HeaderTypes,
QueryParamTypes,
Request,
RequestData,
Response,
URLTypes,
)

OptionalTimeout = typing.Optional[TimeoutConfig]

Expand All @@ -21,11 +29,14 @@ async def request(
method: str,
url: URLTypes,
*,
data: RequestData = b"",
query_params: QueryParamTypes = None,
headers: HeaderTypes = None,
content: ByteOrByteStream = b"",
**options: typing.Any,
) -> Response:
request = Request(method, url, headers=headers, content=content)
request = Request(
method, url, data=data, query_params=query_params, headers=headers
)
self.prepare_request(request)
response = await self.send(request, **options)
return response
Expand Down
23 changes: 15 additions & 8 deletions httpcore/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,9 @@
typing.List[typing.Tuple[typing.AnyStr, typing.AnyStr]],
]

ByteOrByteStream = typing.Union[bytes, typing.AsyncIterator[bytes]]
RequestData = typing.Union[dict, bytes, typing.AsyncIterator[bytes]]

ResponseContent = typing.Union[bytes, typing.AsyncIterator[bytes]]


class URL:
Expand Down Expand Up @@ -197,7 +199,7 @@ def __hash__(self) -> int:
return hash((self.is_ssl, self.host, self.port))


class QueryParams(typing.Mapping):
class QueryParams(typing.Mapping[str, str]):
"""
URL query parameters, as a multi-dict.
"""
Expand Down Expand Up @@ -456,19 +458,24 @@ def __init__(
method: str,
url: typing.Union[str, URL],
*,
data: RequestData = b"",
query_params: QueryParamTypes = None,
headers: HeaderTypes = None,
content: ByteOrByteStream = b"",
):
self.method = method.upper()
self.url = URL(url, query_params=query_params)
if isinstance(content, bytes):
self.headers = Headers(headers)

if isinstance(data, bytes):
self.is_streaming = False
self.content = content
self.content = data
elif isinstance(data, dict):
self.is_streaming = False
self.content = urlencode(data, doseq=True).encode("utf-8")
self.headers["Content-Type"] = "application/x-www-form-urlencoded"
else:
self.is_streaming = True
self.content_aiter = content
self.headers = Headers(headers)
self.content_aiter = data

async def read(self) -> bytes:
"""
Expand Down Expand Up @@ -532,7 +539,7 @@ def __init__(
reason_phrase: str = None,
protocol: str = None,
headers: HeaderTypes = None,
content: ByteOrByteStream = b"",
content: ResponseContent = b"",
on_close: typing.Callable = None,
request: Request = None,
history: typing.List["Response"] = None,
Expand Down
6 changes: 3 additions & 3 deletions tests/adapters/test_redirects.py
Original file line number Diff line number Diff line change
Expand Up @@ -222,8 +222,8 @@ async def test_same_domain_redirect():
async def test_body_redirect():
client = RedirectAdapter(MockDispatch())
url = "https://example.org/redirect_body"
content = b"Example request body"
response = await client.request("POST", url, content=content)
data = b"Example request body"
response = await client.request("POST", url, data=data)
data = json.loads(response.content.decode())
assert response.url == URL("https://example.org/redirect_body_target")
assert data == {"body": "Example request body"}
Expand All @@ -238,4 +238,4 @@ async def streaming_body():
yield b"Example request body"

with pytest.raises(RedirectBodyUnavailable):
await client.request("POST", url, content=streaming_body())
await client.request("POST", url, data=streaming_body())
2 changes: 1 addition & 1 deletion tests/dispatch/test_http2.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ async def test_http2_get_request():
async def test_http2_post_request():
server = MockServer()
async with httpcore.HTTP2Connection(reader=server, writer=server) as conn:
response = await conn.request("POST", "http://example.org", content=b"<data>")
response = await conn.request("POST", "http://example.org", data=b"<data>")
assert response.status_code == 200
assert json.loads(response.content) == {
"method": "POST",
Expand Down
Loading