Skip to content

Commit

Permalink
Fix warning raised in aiohttp 3.9.4 regarding deprecated `content_tra…
Browse files Browse the repository at this point in the history
…nsfer_encoding` argument (#1881)
  • Loading branch information
beagold authored Apr 13, 2024
1 parent e8d2392 commit 3a27bfd
Show file tree
Hide file tree
Showing 4 changed files with 36 additions and 12 deletions.
1 change: 1 addition & 0 deletions changes/1881.bugfix.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fix warning raised in aiohttp 3.9.4 when using `FormData` (most commonly, when uploading attachments)
10 changes: 6 additions & 4 deletions hikari/internal/data_binding.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,6 @@

_APPLICATION_OCTET_STREAM: typing.Final[str] = "application/octet-stream"
_JSON_CONTENT_TYPE: typing.Final[str] = "application/json"
_BINARY: typing.Final[str] = "binary"
_UTF_8: typing.Final[str] = "utf-8"

default_json_dumps: JSONEncoder
Expand Down Expand Up @@ -136,13 +135,16 @@ class URLEncodedFormBuilder:
__slots__: typing.Sequence[str] = ("_fields", "_resources")

def __init__(self) -> None:
self._fields: typing.List[typing.Tuple[str, typing.Union[str, bytes], typing.Optional[str]]] = []
self._fields: typing.List[typing.Tuple[str, aiohttp.BytesPayload, typing.Optional[str]]] = []
self._resources: typing.List[typing.Tuple[str, files.Resource[files.AsyncReader]]] = []

def add_field(
self, name: str, data: typing.Union[str, bytes], *, content_type: typing.Optional[str] = None
) -> None:
self._fields.append((name, data, content_type))
if isinstance(data, str):
data = data.encode()

self._fields.append((name, aiohttp.BytesPayload(data), content_type))

def add_resource(self, name: str, resource: files.Resource[files.AsyncReader]) -> None:
self._resources.append((name, resource))
Expand All @@ -153,7 +155,7 @@ async def build(
form = aiohttp.FormData()

for field in self._fields:
form.add_field(field[0], field[1], content_type=field[2], content_transfer_encoding=_BINARY)
form.add_field(field[0], field[1], content_type=field[2])

for name, resource in self._resources:
stream = await stack.enter_async_context(resource.stream(executor=executor))
Expand Down
6 changes: 3 additions & 3 deletions tests/hikari/impl/test_interaction_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -481,10 +481,10 @@ async def test_aiohttp_hook_when_files(self, mock_interaction_server: interactio
await result.body.write(mock_writer)

boundary = result.body.boundary.encode()
assert mock_writer.payload == (
assert mock_writer.payload == bytearray(
b"--" + boundary + b"""\r\nContent-Type: ooga/booga\r\nContent-Disposition: form-data; name="payload_json"""
b""""\r\nContent-Length: 5\r\n\r\nabody\r\n--""" + boundary + b"""\r\nContent-Type: text/plain\r\nConten"""
b"""t-Disposition: form-data; name="files[0]"; filename="meow.txt"\r\n\r\nxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"""
b""""\r\n\r\nabody\r\n--""" + boundary + b"""\r\nContent-Type: text/plain\r\nContent-Disposition: """
b"""form-data; name="files[0]"; filename="meow.txt"\r\n\r\nxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"""
b"""xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"""
b"""xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"""
b"""xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"""
Expand Down
31 changes: 26 additions & 5 deletions tests/hikari/internal/test_data_binding.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,28 @@ def form_builder(self):
return data_binding.URLEncodedFormBuilder()

def test_add_field(self, form_builder):
form_builder.add_field("test_name", "test_data", content_type="mimetype")
class TestBytesPayload:
def __init__(self, value: bytes) -> None:
self.inner = value

assert form_builder._fields == [("test_name", "test_data", "mimetype")]
def __eq__(self, other: typing.Any) -> bool:
if not isinstance(other, TestBytesPayload):
return False

return self.inner == other.inner

def __repr__(self) -> str:
# Make it easier to debug future errors
return f"TestBytesPayload({self.inner!r})"

with mock.patch.object(aiohttp, "BytesPayload", new=TestBytesPayload):
form_builder.add_field("test_name", "test_data", content_type="mimetype")
form_builder.add_field("test_name2", b"test_data2", content_type="mimetype2")

assert form_builder._fields == [
("test_name", TestBytesPayload(b"test_data"), "mimetype"),
("test_name2", TestBytesPayload(b"test_data2"), "mimetype2"),
]

def test_add_resource(self, form_builder):
mock_resource = object()
Expand All @@ -60,9 +79,11 @@ async def test_build(self, form_builder):
resource2 = mock.Mock()
stream1 = mock.Mock(filename="testing1", mimetype="text")
stream2 = mock.Mock(filename="testing2", mimetype=None)
data1 = aiohttp.BytesPayload(b"data1")
data2 = aiohttp.BytesPayload(b"data2")
mock_stack = mock.AsyncMock(enter_async_context=mock.AsyncMock(side_effect=[stream1, stream2]))
executor = object()
form_builder._fields = [("test_name", "test_data", "mimetype"), ("test_name2", "test_data2", "mimetype2")]
form_builder._fields = [("test_name", data1, "mimetype"), ("test_name2", data2, "mimetype2")]
form_builder._resources = [("aye", resource1), ("lmao", resource2)]

with mock.patch.object(aiohttp, "FormData") as mock_form_class:
Expand All @@ -75,8 +96,8 @@ async def test_build(self, form_builder):
)
mock_form_class.return_value.add_field.assert_has_calls(
[
mock.call("test_name", "test_data", content_type="mimetype", content_transfer_encoding="binary"),
mock.call("test_name2", "test_data2", content_type="mimetype2", content_transfer_encoding="binary"),
mock.call("test_name", data1, content_type="mimetype"),
mock.call("test_name2", data2, content_type="mimetype2"),
mock.call("aye", stream1, filename="testing1", content_type="text"),
mock.call("lmao", stream2, filename="testing2", content_type="application/octet-stream"),
]
Expand Down

0 comments on commit 3a27bfd

Please sign in to comment.