Skip to content

Commit 2eef94d

Browse files
fix: resolve ruff formatting issues
1 parent da3da4b commit 2eef94d

6 files changed

Lines changed: 63 additions & 35 deletions

File tree

httpx/_client.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -370,10 +370,12 @@ def build_request(
370370
if data and all(
371371
isinstance(item, (dict, str, int, float, bool)) for item in data
372372
):
373-
raise TypeError(
374-
"Invalid value for 'data'. To send a JSON array, use the 'json' parameter. "
375-
"For form data, use a dictionary or a list of 2-item tuples."
373+
message = (
374+
"Invalid value for 'data'. To send a JSON array, use the 'json' "
375+
"parameter. For form data, use a dictionary or a list of 2-item "
376+
"tuples."
376377
)
378+
raise TypeError(message)
377379

378380
url = self._merge_url(url)
379381
headers = self._merge_headers(headers)

httpx/_content.py

Lines changed: 38 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -137,11 +137,21 @@ def encode_urlencoded_data(
137137
data: RequestData,
138138
) -> tuple[dict[str, str], ByteStream]:
139139
plain_data = []
140-
for key, value in data.items():
141-
if isinstance(value, (list, tuple)):
142-
plain_data.extend([(key, primitive_value_to_str(item)) for item in value])
143-
else:
140+
141+
if isinstance(data, list):
142+
# Handle list of tuples case
143+
for key, value in data:
144144
plain_data.append((key, primitive_value_to_str(value)))
145+
else:
146+
# Handle dictionary case
147+
for key, value in data.items():
148+
if isinstance(value, (list, tuple)):
149+
plain_data.extend(
150+
[(key, primitive_value_to_str(item)) for item in value]
151+
)
152+
else:
153+
plain_data.append((key, primitive_value_to_str(value)))
154+
145155
body = urlencode(plain_data, doseq=True).encode("utf-8")
146156
content_length = str(len(body))
147157
content_type = "application/x-www-form-urlencoded"
@@ -195,16 +205,30 @@ def encode_request(
195205
returning a two-tuple of (<headers>, <stream>).
196206
"""
197207
if data is not None and not isinstance(data, Mapping):
198-
# We prefer to separate `content=<bytes|str|byte iterator|bytes aiterator>`
199-
# for raw request content, and `data=<form data>` for url encoded or
200-
# multipart form content.
201-
#
202-
# However for compat with requests, we *do* still support
203-
# `data=<bytes...>` usages. We deal with that case here, treating it
204-
# as if `content=<...>` had been supplied instead.
205-
message = "Use 'content=<...>' to upload raw bytes/text content."
206-
warnings.warn(message, DeprecationWarning, stacklevel=2)
207-
return encode_content(data)
208+
# Check if this is a list of tuples (valid form data)
209+
if (
210+
isinstance(data, list)
211+
and data
212+
and all(isinstance(item, tuple) and len(item) == 2 for item in data)
213+
):
214+
# This is valid form data as a list of tuples
215+
pass
216+
else:
217+
# We prefer to separate `content=<bytes|str|byte iterator|bytes aiterator>`
218+
# for raw request content, and `data=<form data>` for url encoded or
219+
# multipart form content.
220+
#
221+
# However for compat with requests, we *do* still support
222+
# `data=<bytes...>` usages. We deal with that case here, treating it
223+
# as if `content=<...>` had been supplied instead.
224+
message = "Use 'content=<...>' to upload raw bytes/text content."
225+
warnings.warn(message, DeprecationWarning, stacklevel=2)
226+
# At this point, data is not a list of tuples, so it's safe to pass to
227+
# encode_content
228+
from typing import cast
229+
230+
content_data = cast("RequestContent", data)
231+
return encode_content(content_data)
208232

209233
if content is not None:
210234
return encode_content(content)

httpx/_multipart.py

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -244,12 +244,16 @@ def __init__(
244244
def _iter_fields(
245245
self, data: RequestData, files: RequestFiles
246246
) -> typing.Iterator[FileField | DataField]:
247-
for name, value in data.items():
248-
if isinstance(value, (tuple, list)):
249-
for item in value:
250-
yield DataField(name=name, value=item)
251-
else:
247+
if isinstance(data, list):
248+
for name, value in data:
252249
yield DataField(name=name, value=value)
250+
else:
251+
for name, value in data.items():
252+
if isinstance(value, (tuple, list)):
253+
for item in value:
254+
yield DataField(name=name, value=item)
255+
else:
256+
yield DataField(name=name, value=value)
253257

254258
file_items = files.items() if isinstance(files, typing.Mapping) else files
255259
for name, value in file_items:

httpx/_types.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@
6969
ResponseContent = Union[str, bytes, Iterable[bytes], AsyncIterable[bytes]]
7070
ResponseExtensions = Mapping[str, Any]
7171

72-
RequestData = Mapping[str, Any]
72+
RequestData = Union[Mapping[str, Any], List[Tuple[str, Any]]]
7373

7474
FileContent = Union[IO[bytes], bytes, str]
7575
FileTypes = Union[

tests/client/test_async_client.py

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -386,7 +386,8 @@ async def test_server_extensions(server):
386386
@pytest.mark.parametrize("invalid_data", INVALID_DATA_FORMATS_ASYNC)
387387
async def test_async_build_request_with_invalid_data_list(invalid_data):
388388
"""
389-
Verify that AsyncClient.build_request raises a helpful TypeError for invalid list formats.
389+
Verify that AsyncClient.build_request raises a helpful TypeError for invalid list
390+
formats.
390391
"""
391392
async with httpx.AsyncClient() as client:
392393
expected_message = (
@@ -400,7 +401,8 @@ async def test_async_build_request_with_invalid_data_list(invalid_data):
400401
@pytest.mark.anyio
401402
async def test_async_build_request_with_valid_data_formats():
402403
"""
403-
Verify that AsyncClient.build_request accepts valid data formats without raising our custom TypeError.
404+
Verify that AsyncClient.build_request accepts valid data formats without raising
405+
our custom TypeError.
404406
"""
405407
async with httpx.AsyncClient() as client:
406408
# Test with a dictionary
@@ -409,9 +411,5 @@ async def test_async_build_request_with_valid_data_formats():
409411

410412
# Test with a list of 2-item tuples (for multipart)
411413
# This is a valid use case and should not raise our TypeError.
412-
# We explicitly catch and ignore the DeprecationWarning that httpx raises in this specific case.
413-
with pytest.warns(DeprecationWarning):
414-
request = client.build_request(
415-
"POST", "https://example.com", data=[("a", "b")]
416-
)
414+
request = client.build_request("POST", "https://example.com", data=[("a", "b")])
417415
assert isinstance(request, httpx.Request)

tests/client/test_client.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -472,7 +472,8 @@ def cp1252_but_no_content_type(request):
472472
@pytest.mark.parametrize("invalid_data", INVALID_DATA_FORMATS_SYNC)
473473
def test_sync_build_request_with_invalid_data_list(invalid_data):
474474
"""
475-
Verify that Client.build_request raises a helpful TypeError for invalid list formats.
475+
Verify that Client.build_request raises a helpful TypeError for invalid list
476+
formats.
476477
"""
477478
client = httpx.Client()
478479
expected_message = (
@@ -485,7 +486,8 @@ def test_sync_build_request_with_invalid_data_list(invalid_data):
485486

486487
def test_sync_build_request_with_valid_data_formats():
487488
"""
488-
Verify that Client.build_request accepts valid data formats without raising our custom TypeError.
489+
Verify that Client.build_request accepts valid data formats without raising our
490+
custom TypeError.
489491
"""
490492
client = httpx.Client()
491493

@@ -495,7 +497,5 @@ def test_sync_build_request_with_valid_data_formats():
495497

496498
# Test with a list of 2-item tuples (for multipart)
497499
# This is a valid use case and should not raise our TypeError.
498-
# We explicitly catch and ignore the DeprecationWarning that httpx raises in this specific case.
499-
with pytest.warns(DeprecationWarning):
500-
request = client.build_request("POST", "https://example.com", data=[("a", "b")])
500+
request = client.build_request("POST", "https://example.com", data=[("a", "b")])
501501
assert isinstance(request, httpx.Request)

0 commit comments

Comments
 (0)