Skip to content
Open
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ nylas-python Changelog
======================
Unreleased
----------
* Fixed `TypeError` in `drafts.create()` and `drafts.update()` when attachments trigger the multipart code path (>3MB) — `_execute()` returns a `(json_response, headers)` tuple, and both methods now unpack it correctly and forward `headers` to `Response.from_dict`

v6.15.0
----------
Expand Down
8 changes: 4 additions & 4 deletions nylas/resources/drafts.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,14 +114,14 @@ def create(
for attachment in request_body.get("attachments", [])
)
if attachment_size >= MAXIMUM_JSON_ATTACHMENT_SIZE:
json_response = self._http_client._execute(
json_response, headers = self._http_client._execute(
method="POST",
path=path,
data=_build_form_request(request_body),
overrides=overrides,
)

return Response.from_dict(json_response, Draft)
return Response.from_dict(json_response, Draft, headers)

# Encode the content of the attachments to base64
for attachment in request_body.get("attachments", []):
Expand Down Expand Up @@ -164,14 +164,14 @@ def update(
for attachment in request_body.get("attachments", [])
)
if attachment_size >= MAXIMUM_JSON_ATTACHMENT_SIZE:
json_response = self._http_client._execute(
json_response, headers = self._http_client._execute(
method="PUT",
path=path,
data=_build_form_request(request_body),
overrides=overrides,
)

return Response.from_dict(json_response, Draft)
return Response.from_dict(json_response, Draft, headers)

# Encode the content of the attachments to base64
for attachment in request_body.get("attachments", []):
Expand Down
86 changes: 86 additions & 0 deletions tests/resources/test_drafts.py
Original file line number Diff line number Diff line change
Expand Up @@ -530,3 +530,89 @@ def test_create_draft_with_special_characters_large_attachment(self, http_client
data=mock_encoder,
overrides=None,
)

def test_create_draft_large_attachment_unpacks_execute_tuple(self):
"""Regression test for #454: drafts.create() must unpack the
(json_response, headers) tuple returned by _execute() when the
multipart code path is triggered (attachments >= 3MB)."""
mock_http_client = Mock()
mock_http_client._execute.return_value = (
{
"request_id": "req-multipart-create",
"data": {
"id": "draft-large-1",
"grant_id": "abc-123",
"object": "draft",
},
},
{"X-Test-Header": "multipart"},
)
drafts = Drafts(mock_http_client)
request_body = {
"subject": "Large attachment regression",
"to": [{"name": "Jon Snow", "email": "jsnow@gmail.com"}],
"body": "Body",
"attachments": [
{
"filename": "big.bin",
"content_type": "application/octet-stream",
"content": b"x",
"size": 3 * 1024 * 1024,
},
],
}

with patch(
"nylas.resources.drafts._build_form_request", return_value=Mock()
):
response = drafts.create(identifier="abc-123", request_body=request_body)

assert isinstance(response.data, Draft)
assert response.data.id == "draft-large-1"
assert response.request_id == "req-multipart-create"
assert response.headers == {"X-Test-Header": "multipart"}

def test_update_draft_large_attachment_unpacks_execute_tuple(self):
"""Regression test for #454: drafts.update() must unpack the
(json_response, headers) tuple returned by _execute() when the
multipart code path is triggered (attachments >= 3MB)."""
mock_http_client = Mock()
mock_http_client._execute.return_value = (
{
"request_id": "req-multipart-update",
"data": {
"id": "draft-large-2",
"grant_id": "abc-123",
"object": "draft",
},
},
{"X-Test-Header": "multipart"},
)
drafts = Drafts(mock_http_client)
request_body = {
"subject": "Large attachment regression update",
"to": [{"name": "Jon Snow", "email": "jsnow@gmail.com"}],
"body": "Body",
"attachments": [
{
"filename": "big.bin",
"content_type": "application/octet-stream",
"content": b"x",
"size": 3 * 1024 * 1024,
},
],
}

with patch(
"nylas.resources.drafts._build_form_request", return_value=Mock()
):
response = drafts.update(
identifier="abc-123",
draft_id="draft-large-2",
request_body=request_body,
)

assert isinstance(response.data, Draft)
assert response.data.id == "draft-large-2"
assert response.request_id == "req-multipart-update"
assert response.headers == {"X-Test-Header": "multipart"}
Loading