From f4cd5e750217c8d0c0d5cb5378a49c651d5aa7d8 Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Thu, 3 Apr 2025 18:44:45 +1100 Subject: [PATCH] Assert image type --- Tests/test_file_avif.py | 9 +++++++++ Tests/test_file_fli.py | 2 ++ Tests/test_file_gif.py | 3 +++ Tests/test_file_jpeg.py | 26 +++++++++++++++++++++----- Tests/test_file_mpo.py | 8 ++++++++ Tests/test_file_png.py | 30 ++++++++++++++++++++++-------- Tests/test_file_webp_metadata.py | 2 ++ 7 files changed, 67 insertions(+), 13 deletions(-) diff --git a/Tests/test_file_avif.py b/Tests/test_file_avif.py index 392a4bbd5..069a48940 100644 --- a/Tests/test_file_avif.py +++ b/Tests/test_file_avif.py @@ -14,6 +14,7 @@ import pytest from PIL import ( AvifImagePlugin, + GifImagePlugin, Image, ImageDraw, ImageFile, @@ -240,6 +241,7 @@ class TestFileAvif: with Image.open("Tests/images/chi.gif") as im: im.save(temp_file) with Image.open(temp_file) as im: + assert isinstance(im, AvifImagePlugin.AvifImageFile) assert im.n_frames == 1 def test_invalid_file(self) -> None: @@ -595,10 +597,12 @@ class TestAvifAnimation: """ with Image.open(TEST_AVIF_FILE) as im: + assert isinstance(im, AvifImagePlugin.AvifImageFile) assert im.n_frames == 1 assert not im.is_animated with Image.open("Tests/images/avif/star.avifs") as im: + assert isinstance(im, AvifImagePlugin.AvifImageFile) assert im.n_frames == 5 assert im.is_animated @@ -609,11 +613,13 @@ class TestAvifAnimation: """ with Image.open("Tests/images/avif/star.gif") as original: + assert isinstance(original, GifImagePlugin.GifImageFile) assert original.n_frames > 1 temp_file = tmp_path / "temp.avif" original.save(temp_file, save_all=True) with Image.open(temp_file) as im: + assert isinstance(im, AvifImagePlugin.AvifImageFile) assert im.n_frames == original.n_frames # Compare first frame in P mode to frame from original GIF @@ -633,6 +639,7 @@ class TestAvifAnimation: def check(temp_file: Path) -> None: with Image.open(temp_file) as im: + assert isinstance(im, AvifImagePlugin.AvifImageFile) assert im.n_frames == 4 # Compare first frame to original @@ -705,6 +712,7 @@ class TestAvifAnimation: ) with Image.open(temp_file) as im: + assert isinstance(im, AvifImagePlugin.AvifImageFile) assert im.n_frames == 5 assert im.is_animated @@ -734,6 +742,7 @@ class TestAvifAnimation: ) with Image.open(temp_file) as im: + assert isinstance(im, AvifImagePlugin.AvifImageFile) assert im.n_frames == 5 assert im.is_animated diff --git a/Tests/test_file_fli.py b/Tests/test_file_fli.py index 81df1ab0b..ff80c92f7 100644 --- a/Tests/test_file_fli.py +++ b/Tests/test_file_fli.py @@ -43,6 +43,7 @@ def test_sanity() -> None: def test_prefix_chunk(monkeypatch: pytest.MonkeyPatch) -> None: monkeypatch.setattr(ImageFile, "LOAD_TRUNCATED_IMAGES", True) with Image.open(animated_test_file_with_prefix_chunk) as im: + assert isinstance(im, FliImagePlugin.FliImageFile) assert im.mode == "P" assert im.size == (320, 200) assert im.format == "FLI" @@ -50,6 +51,7 @@ def test_prefix_chunk(monkeypatch: pytest.MonkeyPatch) -> None: assert im.is_animated palette = im.getpalette() + assert palette is not None assert palette[3:6] == [255, 255, 255] assert palette[381:384] == [204, 204, 12] assert palette[765:] == [252, 0, 0] diff --git a/Tests/test_file_gif.py b/Tests/test_file_gif.py index 20d58a9dd..3d07159f3 100644 --- a/Tests/test_file_gif.py +++ b/Tests/test_file_gif.py @@ -280,6 +280,7 @@ def test_roundtrip_save_all(tmp_path: Path) -> None: im.save(out, save_all=True) with Image.open(out) as reread: + assert isinstance(reread, GifImagePlugin.GifImageFile) assert reread.n_frames == 5 @@ -1357,8 +1358,10 @@ def test_palette_save_all_P(tmp_path: Path) -> None: with Image.open(out) as im: # Assert that the frames are correct, and each frame has the same palette + assert isinstance(im, GifImagePlugin.GifImageFile) assert_image_equal(im.convert("RGB"), frames[0].convert("RGB")) assert im.palette is not None + assert im.global_palette is not None assert im.palette.palette == im.global_palette.palette im.seek(1) diff --git a/Tests/test_file_jpeg.py b/Tests/test_file_jpeg.py index 79f0ec1a8..9164882d3 100644 --- a/Tests/test_file_jpeg.py +++ b/Tests/test_file_jpeg.py @@ -334,8 +334,10 @@ class TestFileJpeg: # Reading with Image.open("Tests/images/exif_gps.jpg") as im: - exif = im._getexif() - assert exif[gps_index] == expected_exif_gps + assert isinstance(im, JpegImagePlugin.JpegImageFile) + exif_data = im._getexif() + assert exif_data is not None + assert exif_data[gps_index] == expected_exif_gps # Writing f = tmp_path / "temp.jpg" @@ -344,8 +346,10 @@ class TestFileJpeg: hopper().save(f, exif=exif) with Image.open(f) as reloaded: - exif = reloaded._getexif() - assert exif[gps_index] == expected_exif_gps + assert isinstance(reloaded, JpegImagePlugin.JpegImageFile) + exif_data = reloaded._getexif() + assert exif_data is not None + assert exif_data[gps_index] == expected_exif_gps def test_empty_exif_gps(self) -> None: with Image.open("Tests/images/empty_gps_ifd.jpg") as im: @@ -372,6 +376,7 @@ class TestFileJpeg: exifs = [] for i in range(2): with Image.open("Tests/images/exif-200dpcm.jpg") as im: + assert isinstance(im, JpegImagePlugin.JpegImageFile) exifs.append(im._getexif()) assert exifs[0] == exifs[1] @@ -405,13 +410,17 @@ class TestFileJpeg: } with Image.open("Tests/images/exif_gps.jpg") as im: + assert isinstance(im, JpegImagePlugin.JpegImageFile) exif = im._getexif() + assert exif is not None for tag, value in expected_exif.items(): assert value == exif[tag] def test_exif_gps_typeerror(self) -> None: with Image.open("Tests/images/exif_gps_typeerror.jpg") as im: + assert isinstance(im, JpegImagePlugin.JpegImageFile) + # Should not raise a TypeError im._getexif() @@ -491,7 +500,9 @@ class TestFileJpeg: def test_exif(self) -> None: with Image.open("Tests/images/pil_sample_rgb.jpg") as im: + assert isinstance(im, JpegImagePlugin.JpegImageFile) info = im._getexif() + assert info is not None assert info[305] == "Adobe Photoshop CS Macintosh" def test_get_child_images(self) -> None: @@ -676,11 +687,13 @@ class TestFileJpeg: def test_save_multiple_16bit_qtables(self) -> None: with Image.open("Tests/images/hopper_16bit_qtables.jpg") as im: + assert isinstance(im, JpegImagePlugin.JpegImageFile) im2 = self.roundtrip(im, qtables="keep") assert im.quantization == im2.quantization def test_save_single_16bit_qtable(self) -> None: with Image.open("Tests/images/hopper_16bit_qtables.jpg") as im: + assert isinstance(im, JpegImagePlugin.JpegImageFile) im2 = self.roundtrip(im, qtables={0: im.quantization[0]}) assert len(im2.quantization) == 1 assert im2.quantization[0] == im.quantization[0] @@ -889,7 +902,10 @@ class TestFileJpeg: # in contrast to normal 8 with Image.open("Tests/images/exif-ifd-offset.jpg") as im: # Act / Assert - assert im._getexif()[306] == "2017:03:13 23:03:09" + assert isinstance(im, JpegImagePlugin.JpegImageFile) + exif = im._getexif() + assert exif is not None + assert exif[306] == "2017:03:13 23:03:09" def test_multiple_exif(self) -> None: with Image.open("Tests/images/multiple_exif.jpg") as im: diff --git a/Tests/test_file_mpo.py b/Tests/test_file_mpo.py index 73838ef44..c5d3142e8 100644 --- a/Tests/test_file_mpo.py +++ b/Tests/test_file_mpo.py @@ -120,9 +120,11 @@ def test_ignore_frame_size() -> None: # Ignore the different size of the second frame # since this is not a "Large Thumbnail" image with Image.open("Tests/images/ignore_frame_size.mpo") as im: + assert isinstance(im, MpoImagePlugin.MpoImageFile) assert im.size == (64, 64) im.seek(1) + assert im.mpinfo is not None assert ( im.mpinfo[0xB002][1]["Attribute"]["MPType"] == "Multi-Frame Image: (Disparity)" @@ -155,7 +157,9 @@ def test_reload_exif_after_seek() -> None: @pytest.mark.parametrize("test_file", test_files) def test_mp(test_file: str) -> None: with Image.open(test_file) as im: + assert isinstance(im, MpoImagePlugin.MpoImageFile) mpinfo = im._getmp() + assert mpinfo is not None assert mpinfo[45056] == b"0100" assert mpinfo[45057] == 2 @@ -164,7 +168,9 @@ def test_mp_offset() -> None: # This image has been manually hexedited to have an IFD offset of 10 # in APP2 data, in contrast to normal 8 with Image.open("Tests/images/sugarshack_ifd_offset.mpo") as im: + assert isinstance(im, MpoImagePlugin.MpoImageFile) mpinfo = im._getmp() + assert mpinfo is not None assert mpinfo[45056] == b"0100" assert mpinfo[45057] == 2 @@ -180,7 +186,9 @@ def test_mp_no_data() -> None: @pytest.mark.parametrize("test_file", test_files) def test_mp_attribute(test_file: str) -> None: with Image.open(test_file) as im: + assert isinstance(im, MpoImagePlugin.MpoImageFile) mpinfo = im._getmp() + assert mpinfo is not None for frame_number, mpentry in enumerate(mpinfo[0xB002]): mpattr = mpentry["Attribute"] if frame_number: diff --git a/Tests/test_file_png.py b/Tests/test_file_png.py index 0f0886ab8..13e1c80f4 100644 --- a/Tests/test_file_png.py +++ b/Tests/test_file_png.py @@ -671,6 +671,9 @@ class TestFilePng: im.save(out, bits=4, save_all=save_all) with Image.open(out) as reloaded: + assert isinstance(reloaded, PngImagePlugin.PngImageFile) + assert reloaded.png is not None + assert reloaded.png.im_palette is not None assert len(reloaded.png.im_palette[1]) == 48 def test_plte_length(self, tmp_path: Path) -> None: @@ -681,6 +684,9 @@ class TestFilePng: im.save(out) with Image.open(out) as reloaded: + assert isinstance(reloaded, PngImagePlugin.PngImageFile) + assert reloaded.png is not None + assert reloaded.png.im_palette is not None assert len(reloaded.png.im_palette[1]) == 3 def test_getxmp(self) -> None: @@ -702,13 +708,17 @@ class TestFilePng: def test_exif(self) -> None: # With an EXIF chunk with Image.open("Tests/images/exif.png") as im: - exif = im._getexif() - assert exif[274] == 1 + assert isinstance(im, PngImagePlugin.PngImageFile) + exif_data = im._getexif() + assert exif_data is not None + assert exif_data[274] == 1 # With an ImageMagick zTXt chunk with Image.open("Tests/images/exif_imagemagick.png") as im: - exif = im._getexif() - assert exif[274] == 1 + assert isinstance(im, PngImagePlugin.PngImageFile) + exif_data = im._getexif() + assert exif_data is not None + assert exif_data[274] == 1 # Assert that info still can be extracted # when the image is no longer a PngImageFile instance @@ -717,8 +727,10 @@ class TestFilePng: # With a tEXt chunk with Image.open("Tests/images/exif_text.png") as im: - exif = im._getexif() - assert exif[274] == 1 + assert isinstance(im, PngImagePlugin.PngImageFile) + exif_data = im._getexif() + assert exif_data is not None + assert exif_data[274] == 1 # With XMP tags with Image.open("Tests/images/xmp_tags_orientation.png") as im: @@ -740,8 +752,10 @@ class TestFilePng: im.save(test_file, exif=im.getexif()) with Image.open(test_file) as reloaded: - exif = reloaded._getexif() - assert exif[274] == 1 + assert isinstance(reloaded, PngImagePlugin.PngImageFile) + exif_data = reloaded._getexif() + assert exif_data is not None + assert exif_data[274] == 1 @mark_if_feature_version( pytest.mark.valgrind_known_error, "libjpeg_turbo", "2.0", reason="Known Failing" diff --git a/Tests/test_file_webp_metadata.py b/Tests/test_file_webp_metadata.py index 7543d22da..3de412b83 100644 --- a/Tests/test_file_webp_metadata.py +++ b/Tests/test_file_webp_metadata.py @@ -22,11 +22,13 @@ except ImportError: def test_read_exif_metadata() -> None: file_path = "Tests/images/flower.webp" with Image.open(file_path) as image: + assert isinstance(image, WebPImagePlugin.WebPImageFile) assert image.format == "WEBP" exif_data = image.info.get("exif", None) assert exif_data exif = image._getexif() + assert exif is not None # Camera make assert exif[271] == "Canon"