Skip to content

Commit cdf120c

Browse files
committed
Switched to auto parsing of mime_type
1 parent 97373a4 commit cdf120c

File tree

2 files changed

+21
-202
lines changed

2 files changed

+21
-202
lines changed

lf_toolkit/evaluation/image_upload.py

Lines changed: 13 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -13,22 +13,16 @@
1313
'image/png': ['PNG'],
1414
'image/gif': ['GIF'],
1515
'image/bmp': ['BMP'],
16-
'image/webp': ['WEBP'],
17-
'image/tiff': ['TIFF', 'TIF'],
18-
'image/x-icon': ['ICO'],
1916
}
2017

21-
FORMAT_TO_EXTENSION: Dict[str, List[str]] = {
22-
'JPEG': ['.jpg', '.jpeg', '.jpe'],
23-
'PNG': ['.png'],
24-
'GIF': ['.gif'],
25-
'BMP': ['.bmp'],
26-
'WEBP': ['.webp'],
27-
'TIFF': ['.tiff', '.tif'],
28-
'ICO': ['.ico'],
18+
FORMAT_TO_MIME: Dict[str, str] = {
19+
'JPEG': 'image/jpeg',
20+
'JPG': 'image/jpeg',
21+
'PNG': 'image/png',
22+
'GIF': 'image/gif',
23+
"bmp": 'image/bmp'
2924
}
3025

31-
3226
class ImageUploadError(Exception):
3327
"""Custom exception for image upload failures"""
3428
pass
@@ -57,50 +51,6 @@ def generate_file_name(img: Image.Image) -> str:
5751
format_ext: str = img.format.lower() if img.format else 'png'
5852
return f"{unique_id}.{format_ext}"
5953

60-
61-
def validate_mime_type(mime_type: str, img: Image.Image, filename: str) -> bool:
62-
"""Validate MIME type against image format and filename
63-
64-
Args:
65-
mime_type: MIME type string to validate
66-
img: PIL Image object
67-
filename: Name of the file
68-
69-
Returns:
70-
True if validation passes
71-
72-
Raises:
73-
InvalidMimeTypeError: If MIME type is invalid or doesn't match image
74-
"""
75-
if mime_type not in MIME_TO_FORMAT:
76-
raise InvalidMimeTypeError(
77-
f"Invalid MIME type '{mime_type}'. "
78-
f"Supported types: {', '.join(MIME_TO_FORMAT.keys())}"
79-
)
80-
81-
img_format: Optional[str] = img.format.upper() if img.format else None
82-
83-
if img_format:
84-
allowed_formats: List[str] = MIME_TO_FORMAT[mime_type]
85-
if img_format not in allowed_formats:
86-
raise InvalidMimeTypeError(
87-
f"MIME type '{mime_type}' does not match image format '{img_format}'. "
88-
f"Expected formats for {mime_type}: {', '.join(allowed_formats)}"
89-
)
90-
91-
file_ext: str = filename[filename.rfind('.'):].lower()
92-
93-
if img_format and img_format in FORMAT_TO_EXTENSION:
94-
valid_extensions: List[str] = FORMAT_TO_EXTENSION[img_format]
95-
if file_ext not in valid_extensions:
96-
raise InvalidMimeTypeError(
97-
f"File extension '{file_ext}' does not match format '{img_format}'. "
98-
f"Expected extensions: {', '.join(valid_extensions)}"
99-
)
100-
101-
return True
102-
103-
10454
def get_s3_bucket_uri() -> str:
10555
"""Get S3 bucket URI from environment variable"""
10656
s3_uri: Optional[str] = os.getenv('S3_BUCKET_URI')
@@ -113,12 +63,11 @@ def get_s3_bucket_uri() -> str:
11363
return s3_uri
11464

11565

116-
def upload_image(img: Image.Image, mime_type: str) -> str:
66+
def upload_image(img: Image.Image) -> str:
11767
"""Upload PIL image with comprehensive MIME type validation
11868
11969
Args:
12070
img: PIL Image object to upload
121-
mime_type: MIME type for the upload
12271
12372
Returns:
12473
JSON response from the server as a dictionary
@@ -134,10 +83,13 @@ def upload_image(img: Image.Image, mime_type: str) -> str:
13483

13584
filename: str = generate_file_name(img)
13685

137-
validate_mime_type(mime_type, img, filename)
138-
13986
full_url = base_url + filename
14087

88+
if img.format is None:
89+
img.format = 'PNG'
90+
91+
mime_type = FORMAT_TO_MIME[img.format.upper()]
92+
14193
buffer: BytesIO = BytesIO()
14294
img_format: str = img.format if img.format else 'PNG'
14395
img.save(buffer, format=img_format)
@@ -169,5 +121,5 @@ def upload_image(img: Image.Image, mime_type: str) -> str:
169121
img.format = 'JPEG'
170122

171123
# Execute
172-
result = upload_image(img, 'image/jpeg')
124+
result = upload_image(img)
173125
print(result)

tests/evaluation/image_upload_test.py

Lines changed: 8 additions & 141 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,12 @@
77
# Import the module to test
88
from lf_toolkit.evaluation.image_upload import (
99
generate_file_name,
10-
validate_mime_type,
1110
get_s3_bucket_uri,
1211
upload_image,
1312
ImageUploadError,
1413
InvalidMimeTypeError,
1514
MissingEnvironmentVariableError,
1615
MIME_TO_FORMAT,
17-
FORMAT_TO_EXTENSION
1816
)
1917

2018

@@ -65,89 +63,6 @@ def test_generate_file_name_unique(self):
6563
assert filename1 != filename2
6664

6765

68-
class TestValidateMimeType:
69-
"""Test suite for validate_mime_type function"""
70-
71-
def test_valid_jpeg_mime_type(self):
72-
"""Test validation with valid JPEG MIME type"""
73-
img = Mock(spec=Image.Image)
74-
img.format = 'JPEG'
75-
76-
result = validate_mime_type('image/jpeg', img, 'test.jpg')
77-
assert result is True
78-
79-
def test_valid_png_mime_type(self):
80-
"""Test validation with valid PNG MIME type"""
81-
img = Mock(spec=Image.Image)
82-
img.format = 'PNG'
83-
84-
result = validate_mime_type('image/png', img, 'test.png')
85-
assert result is True
86-
87-
def test_invalid_mime_type(self):
88-
"""Test validation with unsupported MIME type"""
89-
img = Mock(spec=Image.Image)
90-
img.format = 'PNG'
91-
92-
with pytest.raises(InvalidMimeTypeError) as exc_info:
93-
validate_mime_type('image/invalid', img, 'test.png')
94-
95-
assert "Invalid MIME type 'image/invalid'" in str(exc_info.value)
96-
97-
def test_mime_type_format_mismatch(self):
98-
"""Test validation when MIME type doesn't match image format"""
99-
img = Mock(spec=Image.Image)
100-
img.format = 'PNG'
101-
102-
with pytest.raises(InvalidMimeTypeError) as exc_info:
103-
validate_mime_type('image/jpeg', img, 'test.png')
104-
105-
assert "does not match image format 'PNG'" in str(exc_info.value)
106-
107-
def test_extension_format_mismatch(self):
108-
"""Test validation when file extension doesn't match format"""
109-
img = Mock(spec=Image.Image)
110-
img.format = 'JPEG'
111-
112-
with pytest.raises(InvalidMimeTypeError) as exc_info:
113-
validate_mime_type('image/jpeg', img, 'test.png')
114-
115-
assert "File extension '.png' does not match format 'JPEG'" in str(exc_info.value)
116-
117-
def test_valid_with_no_image_format(self):
118-
"""Test validation when image has no format attribute"""
119-
img = Mock(spec=Image.Image)
120-
img.format = None
121-
122-
# Should not raise when format is None
123-
result = validate_mime_type('image/png', img, 'test.png')
124-
assert result is True
125-
126-
def test_valid_webp_mime_type(self):
127-
"""Test validation with valid WEBP MIME type"""
128-
img = Mock(spec=Image.Image)
129-
img.format = 'WEBP'
130-
131-
result = validate_mime_type('image/webp', img, 'test.webp')
132-
assert result is True
133-
134-
def test_jpeg_with_jpg_extension(self):
135-
"""Test JPEG image with .jpg extension"""
136-
img = Mock(spec=Image.Image)
137-
img.format = 'JPEG'
138-
139-
result = validate_mime_type('image/jpeg', img, 'photo.jpg')
140-
assert result is True
141-
142-
def test_jpeg_with_jpeg_extension(self):
143-
"""Test JPEG image with .jpeg extension"""
144-
img = Mock(spec=Image.Image)
145-
img.format = 'JPEG'
146-
147-
result = validate_mime_type('image/jpeg', img, 'photo.jpeg')
148-
assert result is True
149-
150-
15166
class TestGetS3BucketUri:
15267
"""Test suite for get_s3_bucket_uri function"""
15368

@@ -201,7 +116,7 @@ def test_successful_upload(self, mock_uuid, mock_getenv, mock_put):
201116
img.format = 'JPEG'
202117

203118
# Execute
204-
result = upload_image(img, 'image/jpeg')
119+
result = upload_image(img)
205120

206121
# Verify response
207122
assert result == 'https://s3.amazonaws.com/my-bucket/12345678-1234-5678-1234-567812345678.jpeg'
@@ -223,7 +138,7 @@ def test_upload_with_png_image(self, mock_uuid, mock_getenv, mock_put):
223138
img = Image.new('RGBA', (50, 50), color=(0, 255, 0, 128))
224139
img.format = 'PNG'
225140

226-
result = upload_image(img, 'image/png')
141+
result = upload_image(img)
227142

228143
assert result == 'https://storage.example.com/aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee.png'
229144

@@ -236,18 +151,7 @@ def test_upload_missing_s3_uri(self, mock_getenv):
236151
img.format = 'JPEG'
237152

238153
with pytest.raises(MissingEnvironmentVariableError):
239-
upload_image(img, 'image/jpeg')
240-
241-
@patch('lf_toolkit.evaluation.image_upload.os.getenv')
242-
def test_upload_invalid_mime_type(self, mock_getenv):
243-
"""Test upload fails with invalid MIME type"""
244-
mock_getenv.return_value = 'https://s3.amazonaws.com/bucket'
245-
246-
img = Image.new('RGB', (100, 100))
247-
img.format = 'JPEG'
248-
249-
with pytest.raises(InvalidMimeTypeError):
250-
upload_image(img, 'image/invalid')
154+
upload_image(img)
251155

252156
@patch('lf_toolkit.evaluation.image_upload.requests.put')
253157
@patch('lf_toolkit.evaluation.image_upload.os.getenv')
@@ -266,7 +170,7 @@ def test_upload_server_error(self, mock_uuid, mock_getenv, mock_put):
266170
img.format = 'JPEG'
267171

268172
with pytest.raises(ImageUploadError) as exc_info:
269-
upload_image(img, 'image/jpeg')
173+
upload_image(img)
270174

271175
assert "Upload failed with status code 500" in str(exc_info.value)
272176

@@ -284,7 +188,7 @@ def test_upload_network_error(self, mock_uuid, mock_getenv, mock_put):
284188
img.format = 'JPEG'
285189

286190
with pytest.raises(ImageUploadError) as exc_info:
287-
upload_image(img, 'image/jpeg')
191+
upload_image(img)
288192

289193
assert "Network error" in str(exc_info.value)
290194

@@ -302,24 +206,10 @@ def test_upload_timeout_error(self, mock_uuid, mock_getenv, mock_put):
302206
img.format = 'JPEG'
303207

304208
with pytest.raises(ImageUploadError) as exc_info:
305-
upload_image(img, 'image/jpeg')
209+
upload_image(img)
306210

307211
assert "Network error" in str(exc_info.value)
308212

309-
@patch('lf_toolkit.evaluation.image_upload.requests.put')
310-
@patch('lf_toolkit.evaluation.image_upload.os.getenv')
311-
@patch('lf_toolkit.evaluation.image_upload.uuid.uuid4')
312-
def test_upload_mime_type_mismatch(self, mock_uuid, mock_getenv, mock_put):
313-
"""Test upload fails when MIME type doesn't match image format"""
314-
mock_uuid.return_value = uuid.UUID('12345678-1234-5678-1234-567812345678')
315-
mock_getenv.return_value = 'https://s3.amazonaws.com/bucket'
316-
317-
img = Image.new('RGB', (100, 100))
318-
img.format = 'PNG'
319-
320-
with pytest.raises(InvalidMimeTypeError):
321-
upload_image(img, 'image/jpeg')
322-
323213
@patch('lf_toolkit.evaluation.image_upload.requests.put')
324214
@patch('lf_toolkit.evaluation.image_upload.os.getenv')
325215
@patch('lf_toolkit.evaluation.image_upload.uuid.uuid4')
@@ -335,7 +225,7 @@ def test_upload_image_no_format(self, mock_uuid, mock_getenv, mock_put):
335225
img = Image.new('RGB', (100, 100))
336226
img.format = None
337227

338-
result = upload_image(img, 'image/png')
228+
result = upload_image(img)
339229

340230
assert result == 'https://s3.amazonaws.com/bucket/12345678-1234-5678-1234-567812345678.png'
341231

@@ -354,7 +244,7 @@ def test_upload_verifies_correct_file_uploaded(self, mock_uuid, mock_getenv, moc
354244
img = Image.new('RGB', (100, 100), color='blue')
355245
img.format = 'JPEG'
356246

357-
upload_image(img, 'image/jpeg')
247+
upload_image(img)
358248

359249

360250
class TestExceptionHierarchy:
@@ -385,28 +275,5 @@ def test_invalid_mime_type_error_caught_as_image_upload_error(self):
385275
raise InvalidMimeTypeError("Invalid MIME")
386276

387277

388-
class TestConstants:
389-
"""Test suite for module constants"""
390-
391-
def test_mime_to_format_has_expected_types(self):
392-
"""Test that MIME_TO_FORMAT contains expected image types"""
393-
assert 'image/jpeg' in MIME_TO_FORMAT
394-
assert 'image/png' in MIME_TO_FORMAT
395-
assert 'image/gif' in MIME_TO_FORMAT
396-
assert 'image/webp' in MIME_TO_FORMAT
397-
398-
def test_format_to_extension_has_expected_formats(self):
399-
"""Test that FORMAT_TO_EXTENSION contains expected formats"""
400-
assert 'JPEG' in FORMAT_TO_EXTENSION
401-
assert 'PNG' in FORMAT_TO_EXTENSION
402-
assert 'GIF' in FORMAT_TO_EXTENSION
403-
assert 'WEBP' in FORMAT_TO_EXTENSION
404-
405-
def test_jpeg_has_multiple_extensions(self):
406-
"""Test that JPEG format has multiple valid extensions"""
407-
assert '.jpg' in FORMAT_TO_EXTENSION['JPEG']
408-
assert '.jpeg' in FORMAT_TO_EXTENSION['JPEG']
409-
410-
411278
if __name__ == '__main__':
412279
pytest.main([__file__, '-v'])

0 commit comments

Comments
 (0)