types: make Image path extension check case-insensitive (#696)

The guard in Image.serialize_model compared the file extension without
normalizing case, so a non-existent path with an uppercase extension
(e.g. photo.PNG from a camera or a case-insensitive filesystem) skipped
the "File ... does not exist" branch and fell through to the base64
path. Filenames that happen to be valid base64 (PHOTO.PNG, DCIM0001.WEBP)
were then silently accepted and sent as garbage image data instead of
raising, defeating the extension guard for every uppercase-extension
path.

Lowercase the extracted extension before the membership test so
.PNG/.JPG/.JPEG/.WEBP behave the same as their lowercase counterparts.
Non-image strings still correctly fall through to the base64 check.

Signed-off-by: Anas Khan <83116240+anxkhn@users.noreply.github.com>
This commit is contained in:
Anas Khan
2026-08-12 16:08:59 +05:30
committed by GitHub
parent 25b93290d8
commit fa8509936b
2 changed files with 14 additions and 1 deletions
+1 -1
View File
@@ -175,7 +175,7 @@ class Image(BaseModel):
pass
# String might be a file path, but might not exist
if self.value.split('.')[-1] in ('png', 'jpg', 'jpeg', 'webp'):
if self.value.split('.')[-1].lower() in ('png', 'jpg', 'jpeg', 'webp'):
raise ValueError(f'File {self.value} does not exist')
try:
+13
View File
@@ -55,6 +55,19 @@ def test_image_serialization_string_path():
img.model_dump()
@pytest.mark.parametrize('extension', ['PNG', 'JPG', 'JPEG', 'WEBP'])
def test_image_serialization_string_path_uppercase_extension(extension):
# A non-existent path with an uppercase image extension must be rejected the
# same way its lowercase counterpart is, rather than being treated as base64.
with pytest.raises(ValueError, match='does not exist'):
Image(value=f'some_path/that/does/not/exist.{extension}').model_dump()
# A bare filename with an uppercase extension can be valid base64, so without a
# case-insensitive check it is silently accepted instead of raising.
with pytest.raises(ValueError, match='does not exist'):
Image(value=f'PHOTO.{extension}').model_dump()
def test_create_request_serialization():
request = CreateRequest(model='test-model', from_='base-model', quantize='q4_0', files={'file1': 'content1'}, adapters={'adapter1': 'content1'}, template='test template', license='MIT', system='test system', parameters={'param1': 'value1'})