Skip to content

[Bug]: Malformed attachment object if adding under the same key when using the Async client #33

@yassiezar

Description

@yassiezar

Version

1.6.0

Operating System

Linux

Python Version

3.12

What happened?

I'm running into an error when adding multiple file attachments under the same key when using the Async client, e.g.

client = AsyncClient(
        auth=..., api_url="https://api.eu.mailgun.net"
    )
data = {
        "from": "source@mydomain.com",
        "to": "dest@mydomain.com",
        "subject": "Error",
        "text": "buggy test",
    }

attachments = [
    (
        "inline",
        ("test.txt", b"Hello, this is a test file.")
    ),
    (
        "inline",
        ("test2.txt", b"Hello, this is also a test file.")
    )
]

req = await client.messages.create(data=data, files=attachments, domain="mydomain.com")

This behaviour is supported in the requests library (see here) and the above seems to be valid. However, it looks like the mailgun SDK is transforming the input into an unsupported dict format that breaks when passed into the requests API.

E.g. the above is transformed into the dict below

{
    'inline': [
        ('test.txt', <_io.BytesIO object at 0x7fba431c7510>, 'application/octet-stream'), 
        ('test2.txt', <_io.BytesIO object at 0x7fba431c75b0>, 'application/octet-stream')
    ]
}

and requests isn't able to process the dict.

Weirdly, running the above with the sync client yields no errors. It might be because the async client is calling the _prepare_files() function first, which looks to be doing the malforming

Steps to reproduce

  1. Setup test env (mailgun v1.6.0)
  2. Initialise client
  3. Setup data and attachments as above
  4. Execute request with the async client

Relevant log output

File ".../venv/lib/python3.12/site-packages/httpx/_transports/default.py", line 394, in handle_async_request
    resp = await self._pool.handle_async_request(req)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File ".../venv/lib/python3.12/site-packages/httpcore/_async/connection_pool.py", line 256, in handle_async_request
    raise exc from None
  File ".../venv/lib/python3.12/site-packages/httpcore/_async/connection_pool.py", line 236, in handle_async_request
    response = await connection.handle_async_request(
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File ".../venv/lib/python3.12/site-packages/httpcore/_async/connection.py", line 103, in handle_async_request
    return await self._connection.handle_async_request(request)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File ".../venv/lib/python3.12/site-packages/httpcore/_async/http11.py", line 136, in handle_async_request
    raise exc
  File ".../venv/lib/python3.12/site-packages/httpcore/_async/http11.py", line 88, in handle_async_request
    await self._send_request_body(**kwargs)
  File ".../fc-api/venv/lib/python3.12/site-packages/httpcore/_async/http11.py", line 157, in _send_request_body
    async for chunk in request.stream:
  File ".../venv/lib/python3.12/site-packages/httpx/_multipart.py", line 299, in __aiter__
    for chunk in self.iter_chunks():
  File ".../venv/lib/python3.12/site-packages/httpx/_multipart.py", line 261, in iter_chunks
    yield from field.render()
  File ".../venv/lib/python3.12/site-packages/httpx/_multipart.py", line 221, in render
    yield from self.render_data()
  File ".../venv/lib/python3.12/site-packages/httpx/_multipart.py", line 214, in render_data
    chunk = self.file.read(self.CHUNK_SIZE)
            ^^^^^^^^^^^^^^
AttributeError: 'list' object has no attribute 'read'

Additional information

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingtriageTriage is required

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions