Skip to content

Commit 29ac6f6

Browse files
authored
python(fix): fall back to application/octet-stream for unknown MIME t… (#509)
1 parent c47512b commit 29ac6f6

2 files changed

Lines changed: 59 additions & 9 deletions

File tree

python/lib/sift_client/_internal/low_level_wrappers/upload.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,11 @@ async def upload_attachment(
9393
file_name, mimetype, content_encoding = self._mime_and_content_type_from_path(posix_path)
9494

9595
if not mimetype:
96-
raise ValueError(f"The MIME-type of '{posix_path}' could not be computed.")
96+
extension = posix_path.suffix
97+
if extension:
98+
mimetype = f"application/x-{extension.lstrip('.')}"
99+
else:
100+
mimetype = "application/octet-stream" # fallback to generic 'binary data' MIME type
97101

98102
# Run the synchronous file upload in a thread pool to avoid blocking the event loop
99103
loop = asyncio.get_event_loop()
Lines changed: 54 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,62 @@
11
"""Tests for UploadLowLevelClient functionality."""
22

33
from pathlib import Path
4+
from unittest.mock import patch
5+
6+
import pytest
47

58
from sift_client._internal.low_level_wrappers.upload import UploadLowLevelClient
69

710

8-
class TestUploadLowLevelClient:
9-
class TestMimeAndContentTypeFromPath:
10-
def test_parquet_file_extension(self):
11-
_, mime, _ = UploadLowLevelClient._mime_and_content_type_from_path(Path("data.parquet"))
12-
assert mime == "application/vnd.apache.parquet"
11+
class TestUploadAttachment:
12+
@pytest.mark.asyncio
13+
async def test_known_mime_type(self, tmp_path):
14+
test_file = tmp_path / "video.mp4"
15+
test_file.write_bytes(b"fake data")
16+
17+
client = UploadLowLevelClient.__new__(UploadLowLevelClient)
18+
19+
with patch.object(client, "_upload_file_sync", return_value="remote-file-123") as mock:
20+
await client.upload_attachment(path=test_file, entity_id="e1", entity_type="runs")
21+
22+
_, _, mimetype, *_ = mock.call_args[0]
23+
assert mimetype == "video/mp4"
24+
25+
@pytest.mark.asyncio
26+
async def test_unknown_extension_falls_back_to_application_x_ext(self, tmp_path):
27+
test_file = tmp_path / "data.pcapng"
28+
test_file.write_bytes(b"fake data")
29+
30+
client = UploadLowLevelClient.__new__(UploadLowLevelClient)
31+
32+
with patch.object(client, "_upload_file_sync", return_value="remote-file-123") as mock:
33+
await client.upload_attachment(path=test_file, entity_id="e1", entity_type="runs")
34+
35+
_, _, mimetype, *_ = mock.call_args[0]
36+
assert mimetype == "application/x-pcapng"
37+
38+
@pytest.mark.asyncio
39+
async def test_no_extension_falls_back_to_octet_stream(self, tmp_path):
40+
test_file = tmp_path / "README"
41+
test_file.write_bytes(b"fake data")
42+
43+
client = UploadLowLevelClient.__new__(UploadLowLevelClient)
44+
45+
with patch.object(client, "_upload_file_sync", return_value="remote-file-123") as mock:
46+
await client.upload_attachment(path=test_file, entity_id="e1", entity_type="runs")
47+
48+
_, _, mimetype, *_ = mock.call_args[0]
49+
assert mimetype == "application/octet-stream"
50+
51+
@pytest.mark.asyncio
52+
async def test_file_name_preserved(self, tmp_path):
53+
test_file = tmp_path / "my_file.pcapng"
54+
test_file.write_bytes(b"fake data")
55+
56+
client = UploadLowLevelClient.__new__(UploadLowLevelClient)
57+
58+
with patch.object(client, "_upload_file_sync", return_value="remote-file-123") as mock:
59+
await client.upload_attachment(path=test_file, entity_id="e1", entity_type="runs")
1360

14-
def test_pqt_file_extension(self):
15-
_, mime, _ = UploadLowLevelClient._mime_and_content_type_from_path(Path("data.pqt"))
16-
assert mime == "application/vnd.apache.parquet"
61+
file_name, *_ = mock.call_args[0]
62+
assert file_name == Path(test_file)

0 commit comments

Comments
 (0)