diff --git a/Tests/test_features.py b/Tests/test_features.py index 284f72205..c4e9cd368 100644 --- a/Tests/test_features.py +++ b/Tests/test_features.py @@ -70,14 +70,14 @@ def test_libimagequant_version(): assert re.search(r"\d+\.\d+\.\d+$", features.version("libimagequant")) -def test_check_modules(): - for feature in features.modules: - assert features.check_module(feature) in [True, False] +@pytest.mark.parametrize("feature", features.modules) +def test_check_modules(feature): + assert features.check_module(feature) in [True, False] -def test_check_codecs(): - for feature in features.codecs: - assert features.check_codec(feature) in [True, False] +@pytest.mark.parametrize("feature", features.codecs) +def test_check_codecs(feature): + assert features.check_codec(feature) in [True, False] def test_check_warns_on_nonexistent(): diff --git a/Tests/test_file_apng.py b/Tests/test_file_apng.py index 0ff05f608..cdaad5940 100644 --- a/Tests/test_file_apng.py +++ b/Tests/test_file_apng.py @@ -39,13 +39,12 @@ def test_apng_basic(): assert im.getpixel((64, 32)) == (0, 255, 0, 255) -def test_apng_fdat(): - with Image.open("Tests/images/apng/split_fdat.png") as im: - im.seek(im.n_frames - 1) - assert im.getpixel((0, 0)) == (0, 255, 0, 255) - assert im.getpixel((64, 32)) == (0, 255, 0, 255) - - with Image.open("Tests/images/apng/split_fdat_zero_chunk.png") as im: +@pytest.mark.parametrize( + "filename", + ("Tests/images/apng/split_fdat.png", "Tests/images/apng/split_fdat_zero_chunk.png"), +) +def test_apng_fdat(filename): + with Image.open(filename) as im: im.seek(im.n_frames - 1) assert im.getpixel((0, 0)) == (0, 255, 0, 255) assert im.getpixel((64, 32)) == (0, 255, 0, 255) diff --git a/Tests/test_file_eps.py b/Tests/test_file_eps.py index cbb89aeda..015dda992 100644 --- a/Tests/test_file_eps.py +++ b/Tests/test_file_eps.py @@ -195,25 +195,23 @@ def test_render_scale2(): @pytest.mark.skipif(not HAS_GHOSTSCRIPT, reason="Ghostscript not available") -def test_resize(): - files = [FILE1, FILE2, "Tests/images/illu10_preview.eps"] - for fn in files: - with Image.open(fn) as im: - new_size = (100, 100) - im = im.resize(new_size) - assert im.size == new_size +@pytest.mark.parametrize("filename", (FILE1, FILE2, "Tests/images/illu10_preview.eps")) +def test_resize(filename): + with Image.open(filename) as im: + new_size = (100, 100) + im = im.resize(new_size) + assert im.size == new_size @pytest.mark.skipif(not HAS_GHOSTSCRIPT, reason="Ghostscript not available") -def test_thumbnail(): +@pytest.mark.parametrize("filename", (FILE1, FILE2)) +def test_thumbnail(filename): # Issue #619 # Arrange - files = [FILE1, FILE2] - for fn in files: - with Image.open(FILE1) as im: - new_size = (100, 100) - im.thumbnail(new_size) - assert max(im.size) == max(new_size) + with Image.open(filename) as im: + new_size = (100, 100) + im.thumbnail(new_size) + assert max(im.size) == max(new_size) def test_read_binary_preview(): @@ -258,20 +256,19 @@ def test_readline(tmp_path): _test_readline_file_psfile(s, ending) -def test_open_eps(): - # https://github.com/python-pillow/Pillow/issues/1104 - # Arrange - FILES = [ +@pytest.mark.parametrize( + "filename", + ( "Tests/images/illu10_no_preview.eps", "Tests/images/illu10_preview.eps", "Tests/images/illuCS6_no_preview.eps", "Tests/images/illuCS6_preview.eps", - ] - - # Act / Assert - for filename in FILES: - with Image.open(filename) as img: - assert img.mode == "RGB" + ), +) +def test_open_eps(filename): + # https://github.com/python-pillow/Pillow/issues/1104 + with Image.open(filename) as img: + assert img.mode == "RGB" @pytest.mark.skipif(not HAS_GHOSTSCRIPT, reason="Ghostscript not available") diff --git a/Tests/test_file_gif.py b/Tests/test_file_gif.py index 4e967faec..637be2be4 100644 --- a/Tests/test_file_gif.py +++ b/Tests/test_file_gif.py @@ -793,24 +793,24 @@ def test_identical_frames(tmp_path): assert reread.info["duration"] == 4500 -def test_identical_frames_to_single_frame(tmp_path): - for duration in ([1000, 1500, 2000, 4000], (1000, 1500, 2000, 4000), 8500): - out = str(tmp_path / "temp.gif") - im_list = [ - Image.new("L", (100, 100), "#000"), - Image.new("L", (100, 100), "#000"), - Image.new("L", (100, 100), "#000"), - ] +@pytest.mark.parametrize( + "duration", ([1000, 1500, 2000, 4000], (1000, 1500, 2000, 4000), 8500) +) +def test_identical_frames_to_single_frame(duration, tmp_path): + out = str(tmp_path / "temp.gif") + im_list = [ + Image.new("L", (100, 100), "#000"), + Image.new("L", (100, 100), "#000"), + Image.new("L", (100, 100), "#000"), + ] - im_list[0].save( - out, save_all=True, append_images=im_list[1:], duration=duration - ) - with Image.open(out) as reread: - # Assert that all frames were combined - assert reread.n_frames == 1 + im_list[0].save(out, save_all=True, append_images=im_list[1:], duration=duration) + with Image.open(out) as reread: + # Assert that all frames were combined + assert reread.n_frames == 1 - # Assert that the new duration is the total of the identical frames - assert reread.info["duration"] == 8500 + # Assert that the new duration is the total of the identical frames + assert reread.info["duration"] == 8500 def test_number_of_loops(tmp_path): diff --git a/Tests/test_file_jpeg.py b/Tests/test_file_jpeg.py index 12edd7582..adbb72aa5 100644 --- a/Tests/test_file_jpeg.py +++ b/Tests/test_file_jpeg.py @@ -150,27 +150,30 @@ class TestFileJpeg: assert not im1.info.get("icc_profile") assert im2.info.get("icc_profile") - def test_icc_big(self): + @pytest.mark.parametrize( + "n", + ( + 0, + 1, + 3, + 4, + 5, + 65533 - 14, # full JPEG marker block + 65533 - 14 + 1, # full block plus one byte + ImageFile.MAXBLOCK, # full buffer block + ImageFile.MAXBLOCK + 1, # full buffer block plus one byte + ImageFile.MAXBLOCK * 4 + 3, # large block + ), + ) + def test_icc_big(self, n): # Make sure that the "extra" support handles large blocks - def test(n): - # The ICC APP marker can store 65519 bytes per marker, so - # using a 4-byte test code should allow us to detect out of - # order issues. - icc_profile = (b"Test" * int(n / 4 + 1))[:n] - assert len(icc_profile) == n # sanity - im1 = self.roundtrip(hopper(), icc_profile=icc_profile) - assert im1.info.get("icc_profile") == (icc_profile or None) - - test(0) - test(1) - test(3) - test(4) - test(5) - test(65533 - 14) # full JPEG marker block - test(65533 - 14 + 1) # full block plus one byte - test(ImageFile.MAXBLOCK) # full buffer block - test(ImageFile.MAXBLOCK + 1) # full buffer block plus one byte - test(ImageFile.MAXBLOCK * 4 + 3) # large block + # The ICC APP marker can store 65519 bytes per marker, so + # using a 4-byte test code should allow us to detect out of + # order issues. + icc_profile = (b"Test" * int(n / 4 + 1))[:n] + assert len(icc_profile) == n # sanity + im1 = self.roundtrip(hopper(), icc_profile=icc_profile) + assert im1.info.get("icc_profile") == (icc_profile or None) @mark_if_feature_version( pytest.mark.valgrind_known_error, "libjpeg_turbo", "2.0", reason="Known Failing" @@ -649,19 +652,19 @@ class TestFileJpeg: # Assert assert im.format == "JPEG" - def test_save_correct_modes(self): + @pytest.mark.parametrize("mode", ("1", "L", "RGB", "RGBX", "CMYK", "YCbCr")) + def test_save_correct_modes(self, mode): out = BytesIO() - for mode in ["1", "L", "RGB", "RGBX", "CMYK", "YCbCr"]: - img = Image.new(mode, (20, 20)) - img.save(out, "JPEG") + img = Image.new(mode, (20, 20)) + img.save(out, "JPEG") - def test_save_wrong_modes(self): + @pytest.mark.parametrize("mode", ("LA", "La", "RGBA", "RGBa", "P")) + def test_save_wrong_modes(self, mode): # ref https://github.com/python-pillow/Pillow/issues/2005 out = BytesIO() - for mode in ["LA", "La", "RGBA", "RGBa", "P"]: - img = Image.new(mode, (20, 20)) - with pytest.raises(OSError): - img.save(out, "JPEG") + img = Image.new(mode, (20, 20)) + with pytest.raises(OSError): + img.save(out, "JPEG") def test_save_tiff_with_dpi(self, tmp_path): # Arrange diff --git a/Tests/test_file_jpeg2k.py b/Tests/test_file_jpeg2k.py index 7942d6b9a..cd142e67f 100644 --- a/Tests/test_file_jpeg2k.py +++ b/Tests/test_file_jpeg2k.py @@ -126,14 +126,14 @@ def test_prog_res_rt(): assert_image_equal(im, test_card) -def test_default_num_resolutions(): - for num_resolutions in range(2, 6): - d = 1 << (num_resolutions - 1) - im = test_card.resize((d - 1, d - 1)) - with pytest.raises(OSError): - roundtrip(im, num_resolutions=num_resolutions) - reloaded = roundtrip(im) - assert_image_equal(im, reloaded) +@pytest.mark.parametrize("num_resolutions", range(2, 6)) +def test_default_num_resolutions(num_resolutions): + d = 1 << (num_resolutions - 1) + im = test_card.resize((d - 1, d - 1)) + with pytest.raises(OSError): + roundtrip(im, num_resolutions=num_resolutions) + reloaded = roundtrip(im) + assert_image_equal(im, reloaded) def test_reduce(): @@ -266,14 +266,11 @@ def test_rgba(): assert jp2.mode == "RGBA" -def test_16bit_monochrome_has_correct_mode(): - with Image.open("Tests/images/16bit.cropped.j2k") as j2k: - j2k.load() - assert j2k.mode == "I;16" - - with Image.open("Tests/images/16bit.cropped.jp2") as jp2: - jp2.load() - assert jp2.mode == "I;16" +@pytest.mark.parametrize("ext", (".j2k", ".jp2")) +def test_16bit_monochrome_has_correct_mode(ext): + with Image.open("Tests/images/16bit.cropped" + ext) as im: + im.load() + assert im.mode == "I;16" def test_16bit_monochrome_jp2_like_tiff(): diff --git a/Tests/test_file_libtiff.py b/Tests/test_file_libtiff.py index 86a0fda04..6015a8fec 100644 --- a/Tests/test_file_libtiff.py +++ b/Tests/test_file_libtiff.py @@ -509,7 +509,8 @@ class TestFileLibTiff(LibTiffTestCase): # colormap/palette tag assert len(reloaded.tag_v2[320]) == 768 - def xtest_bw_compression_w_rgb(self, tmp_path): + @pytest.mark.parametrize("compression", ("tiff_ccitt", "group3", "group4")) + def xtest_bw_compression_w_rgb(self, compression, tmp_path): """This test passes, but when running all tests causes a failure due to output on stderr from the error thrown by libtiff. We need to capture that but not now""" @@ -518,11 +519,7 @@ class TestFileLibTiff(LibTiffTestCase): out = str(tmp_path / "temp.tif") with pytest.raises(OSError): - im.save(out, compression="tiff_ccitt") - with pytest.raises(OSError): - im.save(out, compression="group3") - with pytest.raises(OSError): - im.save(out, compression="group4") + im.save(out, compression=compression) def test_fp_leak(self): im = Image.open("Tests/images/hopper_g4_500.tif") diff --git a/Tests/test_file_palm.py b/Tests/test_file_palm.py index e1c1c361b..be7c8d0c8 100644 --- a/Tests/test_file_palm.py +++ b/Tests/test_file_palm.py @@ -63,19 +63,7 @@ def test_p_mode(tmp_path): roundtrip(tmp_path, mode) -def test_l_oserror(tmp_path): - # Arrange - mode = "L" - - # Act / Assert - with pytest.raises(OSError): - helper_save_as_palm(tmp_path, mode) - - -def test_rgb_oserror(tmp_path): - # Arrange - mode = "RGB" - - # Act / Assert +@pytest.mark.parametrize("mode", ("L", "RGB")) +def test_oserror(tmp_path, mode): with pytest.raises(OSError): helper_save_as_palm(tmp_path, mode) diff --git a/Tests/test_file_pcx.py b/Tests/test_file_pcx.py index ba6663cd3..485adf785 100644 --- a/Tests/test_file_pcx.py +++ b/Tests/test_file_pcx.py @@ -39,14 +39,14 @@ def test_invalid_file(): PcxImagePlugin.PcxImageFile(invalid_file) -def test_odd(tmp_path): +@pytest.mark.parametrize("mode", ("1", "L", "P", "RGB")) +def test_odd(tmp_path, mode): # See issue #523, odd sized images should have a stride that's even. # Not that ImageMagick or GIMP write PCX that way. # We were not handling properly. - for mode in ("1", "L", "P", "RGB"): - # larger, odd sized images are better here to ensure that - # we handle interrupted scan lines properly. - _roundtrip(tmp_path, hopper(mode).resize((511, 511))) + # larger, odd sized images are better here to ensure that + # we handle interrupted scan lines properly. + _roundtrip(tmp_path, hopper(mode).resize((511, 511))) def test_odd_read(): diff --git a/Tests/test_file_pdf.py b/Tests/test_file_pdf.py index b5273353c..4129e8783 100644 --- a/Tests/test_file_pdf.py +++ b/Tests/test_file_pdf.py @@ -37,6 +37,11 @@ def helper_save_as_pdf(tmp_path, mode, **kwargs): return outfile +@pytest.mark.parametrize("mode", ("L", "P", "RGB", "CMYK")) +def test_save(tmp_path, mode): + helper_save_as_pdf(tmp_path, mode) + + @pytest.mark.valgrind_known_error(reason="Temporary skip") def test_monochrome(tmp_path): # Arrange @@ -47,38 +52,6 @@ def test_monochrome(tmp_path): assert os.path.getsize(outfile) < (5000 if features.check("libtiff") else 15000) -def test_greyscale(tmp_path): - # Arrange - mode = "L" - - # Act / Assert - helper_save_as_pdf(tmp_path, mode) - - -def test_rgb(tmp_path): - # Arrange - mode = "RGB" - - # Act / Assert - helper_save_as_pdf(tmp_path, mode) - - -def test_p_mode(tmp_path): - # Arrange - mode = "P" - - # Act / Assert - helper_save_as_pdf(tmp_path, mode) - - -def test_cmyk_mode(tmp_path): - # Arrange - mode = "CMYK" - - # Act / Assert - helper_save_as_pdf(tmp_path, mode) - - def test_unsupported_mode(tmp_path): im = hopper("LA") outfile = str(tmp_path / "temp_LA.pdf") diff --git a/Tests/test_file_tiff.py b/Tests/test_file_tiff.py index ac0bd7f60..1a5ba594f 100644 --- a/Tests/test_file_tiff.py +++ b/Tests/test_file_tiff.py @@ -311,14 +311,17 @@ class TestFileTiff: with Image.open("Tests/images/hopper_unknown_pixel_mode.tif"): pass - def test_n_frames(self): - for path, n_frames in [ - ["Tests/images/multipage-lastframe.tif", 1], - ["Tests/images/multipage.tiff", 3], - ]: - with Image.open(path) as im: - assert im.n_frames == n_frames - assert im.is_animated == (n_frames != 1) + @pytest.mark.parametrize( + "path, n_frames", + ( + ("Tests/images/multipage-lastframe.tif", 1), + ("Tests/images/multipage.tiff", 3), + ), + ) + def test_n_frames(self, path, n_frames): + with Image.open(path) as im: + assert im.n_frames == n_frames + assert im.is_animated == (n_frames != 1) def test_eoferror(self): with Image.open("Tests/images/multipage-lastframe.tif") as im: @@ -434,12 +437,12 @@ class TestFileTiff: len_after = len(dict(im.ifd)) assert len_before == len_after + 1 - def test_load_byte(self): - for legacy_api in [False, True]: - ifd = TiffImagePlugin.ImageFileDirectory_v2() - data = b"abc" - ret = ifd.load_byte(data, legacy_api) - assert ret == b"abc" + @pytest.mark.parametrize("legacy_api", (False, True)) + def test_load_byte(self, legacy_api): + ifd = TiffImagePlugin.ImageFileDirectory_v2() + data = b"abc" + ret = ifd.load_byte(data, legacy_api) + assert ret == b"abc" def test_load_string(self): ifd = TiffImagePlugin.ImageFileDirectory_v2() @@ -685,18 +688,15 @@ class TestFileTiff: with Image.open(outfile) as reloaded: assert_image_equal_tofile(reloaded, infile) - def test_palette(self, tmp_path): - def roundtrip(mode): - outfile = str(tmp_path / "temp.tif") + @pytest.mark.parametrize("mode", ("P", "PA")) + def test_palette(self, mode, tmp_path): + outfile = str(tmp_path / "temp.tif") - im = hopper(mode) - im.save(outfile) + im = hopper(mode) + im.save(outfile) - with Image.open(outfile) as reloaded: - assert_image_equal(im.convert("RGB"), reloaded.convert("RGB")) - - for mode in ["P", "PA"]: - roundtrip(mode) + with Image.open(outfile) as reloaded: + assert_image_equal(im.convert("RGB"), reloaded.convert("RGB")) def test_tiff_save_all(self): mp = BytesIO() diff --git a/Tests/test_font_pcf_charsets.py b/Tests/test_font_pcf_charsets.py index 4477ee29d..664663fd6 100644 --- a/Tests/test_font_pcf_charsets.py +++ b/Tests/test_font_pcf_charsets.py @@ -1,5 +1,7 @@ import os +import pytest + from PIL import FontFile, Image, ImageDraw, ImageFont, PcfFontFile from .helper import ( @@ -59,23 +61,13 @@ def save_font(request, tmp_path, encoding): return tempname -def _test_sanity(request, tmp_path, encoding): +@pytest.mark.parametrize("encoding", ("iso8859-1", "iso8859-2", "cp1250")) +def test_sanity(request, tmp_path, encoding): save_font(request, tmp_path, encoding) -def test_sanity_iso8859_1(request, tmp_path): - _test_sanity(request, tmp_path, "iso8859-1") - - -def test_sanity_iso8859_2(request, tmp_path): - _test_sanity(request, tmp_path, "iso8859-2") - - -def test_sanity_cp1250(request, tmp_path): - _test_sanity(request, tmp_path, "cp1250") - - -def _test_draw(request, tmp_path, encoding): +@pytest.mark.parametrize("encoding", ("iso8859-1", "iso8859-2", "cp1250")) +def test_draw(request, tmp_path, encoding): tempname = save_font(request, tmp_path, encoding) font = ImageFont.load(tempname) im = Image.new("L", (150, 30), "white") @@ -85,19 +77,8 @@ def _test_draw(request, tmp_path, encoding): assert_image_similar_tofile(im, charsets[encoding]["image1"], 0) -def test_draw_iso8859_1(request, tmp_path): - _test_draw(request, tmp_path, "iso8859-1") - - -def test_draw_iso8859_2(request, tmp_path): - _test_draw(request, tmp_path, "iso8859-2") - - -def test_draw_cp1250(request, tmp_path): - _test_draw(request, tmp_path, "cp1250") - - -def _test_textsize(request, tmp_path, encoding): +@pytest.mark.parametrize("encoding", ("iso8859-1", "iso8859-2", "cp1250")) +def test_textsize(request, tmp_path, encoding): tempname = save_font(request, tmp_path, encoding) font = ImageFont.load(tempname) for i in range(255): @@ -112,15 +93,3 @@ def _test_textsize(request, tmp_path, encoding): msg = message[: i + 1] assert font.getlength(msg) == len(msg) * 10 assert font.getbbox(msg) == (0, 0, len(msg) * 10, 20) - - -def test_textsize_iso8859_1(request, tmp_path): - _test_textsize(request, tmp_path, "iso8859-1") - - -def test_textsize_iso8859_2(request, tmp_path): - _test_textsize(request, tmp_path, "iso8859-2") - - -def test_textsize_cp1250(request, tmp_path): - _test_textsize(request, tmp_path, "cp1250") diff --git a/Tests/test_image_reduce.py b/Tests/test_image_reduce.py index 801161511..ae8d740a0 100644 --- a/Tests/test_image_reduce.py +++ b/Tests/test_image_reduce.py @@ -196,11 +196,11 @@ def assert_compare_images(a, b, max_average_diff, max_diff=255): ) -def test_mode_L(): +@pytest.mark.parametrize("factor", remarkable_factors) +def test_mode_L(factor): im = get_image("L") - for factor in remarkable_factors: - compare_reduce_with_reference(im, factor) - compare_reduce_with_box(im, factor) + compare_reduce_with_reference(im, factor) + compare_reduce_with_box(im, factor) @pytest.mark.parametrize("factor", remarkable_factors) diff --git a/Tests/test_image_resample.py b/Tests/test_image_resample.py index 5ce98a235..53ceb6df0 100644 --- a/Tests/test_image_resample.py +++ b/Tests/test_image_resample.py @@ -554,44 +554,48 @@ class TestCoreResampleBox: # check that the difference at least that much assert_image_similar(res, im.crop(box), 20, f">>> {size} {box}") - def test_skip_horizontal(self): + @pytest.mark.parametrize( + "flt", (Image.Resampling.NEAREST, Image.Resampling.BICUBIC) + ) + def test_skip_horizontal(self, flt): # Can skip resize for one dimension im = hopper() - for flt in [Image.Resampling.NEAREST, Image.Resampling.BICUBIC]: - for size, box in [ - ((40, 50), (0, 0, 40, 90)), - ((40, 50), (0, 20, 40, 90)), - ((40, 50), (10, 0, 50, 90)), - ((40, 50), (10, 20, 50, 90)), - ]: - res = im.resize(size, flt, box) - assert res.size == size - # Borders should be slightly different - assert_image_similar( - res, - im.crop(box).resize(size, flt), - 0.4, - f">>> {size} {box} {flt}", - ) + for size, box in [ + ((40, 50), (0, 0, 40, 90)), + ((40, 50), (0, 20, 40, 90)), + ((40, 50), (10, 0, 50, 90)), + ((40, 50), (10, 20, 50, 90)), + ]: + res = im.resize(size, flt, box) + assert res.size == size + # Borders should be slightly different + assert_image_similar( + res, + im.crop(box).resize(size, flt), + 0.4, + f">>> {size} {box} {flt}", + ) - def test_skip_vertical(self): + @pytest.mark.parametrize( + "flt", (Image.Resampling.NEAREST, Image.Resampling.BICUBIC) + ) + def test_skip_vertical(self, flt): # Can skip resize for one dimension im = hopper() - for flt in [Image.Resampling.NEAREST, Image.Resampling.BICUBIC]: - for size, box in [ - ((40, 50), (0, 0, 90, 50)), - ((40, 50), (20, 0, 90, 50)), - ((40, 50), (0, 10, 90, 60)), - ((40, 50), (20, 10, 90, 60)), - ]: - res = im.resize(size, flt, box) - assert res.size == size - # Borders should be slightly different - assert_image_similar( - res, - im.crop(box).resize(size, flt), - 0.4, - f">>> {size} {box} {flt}", - ) + for size, box in [ + ((40, 50), (0, 0, 90, 50)), + ((40, 50), (20, 0, 90, 50)), + ((40, 50), (0, 10, 90, 60)), + ((40, 50), (20, 10, 90, 60)), + ]: + res = im.resize(size, flt, box) + assert res.size == size + # Borders should be slightly different + assert_image_similar( + res, + im.crop(box).resize(size, flt), + 0.4, + f">>> {size} {box} {flt}", + ) diff --git a/Tests/test_image_split.py b/Tests/test_image_split.py index fbed276b8..5cb7c9a8b 100644 --- a/Tests/test_image_split.py +++ b/Tests/test_image_split.py @@ -1,3 +1,5 @@ +import pytest + from PIL import Image, features from .helper import assert_image_equal, hopper @@ -29,19 +31,12 @@ def test_split(): assert split("YCbCr") == [("L", 128, 128), ("L", 128, 128), ("L", 128, 128)] -def test_split_merge(): - def split_merge(mode): - return Image.merge(mode, hopper(mode).split()) - - assert_image_equal(hopper("1"), split_merge("1")) - assert_image_equal(hopper("L"), split_merge("L")) - assert_image_equal(hopper("I"), split_merge("I")) - assert_image_equal(hopper("F"), split_merge("F")) - assert_image_equal(hopper("P"), split_merge("P")) - assert_image_equal(hopper("RGB"), split_merge("RGB")) - assert_image_equal(hopper("RGBA"), split_merge("RGBA")) - assert_image_equal(hopper("CMYK"), split_merge("CMYK")) - assert_image_equal(hopper("YCbCr"), split_merge("YCbCr")) +@pytest.mark.parametrize( + "mode", ("1", "L", "I", "F", "P", "RGB", "RGBA", "CMYK", "YCbCr") +) +def test_split_merge(mode): + expected = Image.merge(mode, hopper(mode).split()) + assert_image_equal(hopper(mode), expected) def test_split_open(tmp_path): diff --git a/Tests/test_imagedraw.py b/Tests/test_imagedraw.py index d1dd1e47c..76b7c65cc 100644 --- a/Tests/test_imagedraw.py +++ b/Tests/test_imagedraw.py @@ -64,7 +64,9 @@ def test_mode_mismatch(): ImageDraw.ImageDraw(im, mode="L") -def helper_arc(bbox, start, end): +@pytest.mark.parametrize("bbox", (BBOX1, BBOX2)) +@pytest.mark.parametrize("start, end", ((0, 180), (0.5, 180.4))) +def test_arc(bbox, start, end): # Arrange im = Image.new("RGB", (W, H)) draw = ImageDraw.Draw(im) @@ -76,16 +78,6 @@ def helper_arc(bbox, start, end): assert_image_similar_tofile(im, "Tests/images/imagedraw_arc.png", 1) -def test_arc1(): - helper_arc(BBOX1, 0, 180) - helper_arc(BBOX1, 0.5, 180.4) - - -def test_arc2(): - helper_arc(BBOX2, 0, 180) - helper_arc(BBOX2, 0.5, 180.4) - - def test_arc_end_le_start(): # Arrange im = Image.new("RGB", (W, H)) @@ -192,29 +184,21 @@ def test_bitmap(): assert_image_equal_tofile(im, "Tests/images/imagedraw_bitmap.png") -def helper_chord(mode, bbox, start, end): +@pytest.mark.parametrize("mode", ("RGB", "L")) +@pytest.mark.parametrize("bbox", (BBOX1, BBOX2)) +def test_chord(mode, bbox): # Arrange im = Image.new(mode, (W, H)) draw = ImageDraw.Draw(im) expected = f"Tests/images/imagedraw_chord_{mode}.png" # Act - draw.chord(bbox, start, end, fill="red", outline="yellow") + draw.chord(bbox, 0, 180, fill="red", outline="yellow") # Assert assert_image_similar_tofile(im, expected, 1) -def test_chord1(): - for mode in ["RGB", "L"]: - helper_chord(mode, BBOX1, 0, 180) - - -def test_chord2(): - for mode in ["RGB", "L"]: - helper_chord(mode, BBOX2, 0, 180) - - def test_chord_width(): # Arrange im = Image.new("RGB", (W, H)) @@ -263,7 +247,9 @@ def test_chord_too_fat(): assert_image_equal_tofile(im, "Tests/images/imagedraw_chord_too_fat.png") -def helper_ellipse(mode, bbox): +@pytest.mark.parametrize("mode", ("RGB", "L")) +@pytest.mark.parametrize("bbox", (BBOX1, BBOX2)) +def test_ellipse(mode, bbox): # Arrange im = Image.new(mode, (W, H)) draw = ImageDraw.Draw(im) @@ -276,16 +262,6 @@ def helper_ellipse(mode, bbox): assert_image_similar_tofile(im, expected, 1) -def test_ellipse1(): - for mode in ["RGB", "L"]: - helper_ellipse(mode, BBOX1) - - -def test_ellipse2(): - for mode in ["RGB", "L"]: - helper_ellipse(mode, BBOX2) - - def test_ellipse_translucent(): # Arrange im = Image.new("RGB", (W, H)) @@ -405,7 +381,8 @@ def test_ellipse_various_sizes_filled(): ) -def helper_line(points): +@pytest.mark.parametrize("points", (POINTS1, POINTS2)) +def test_line(points): # Arrange im = Image.new("RGB", (W, H)) draw = ImageDraw.Draw(im) @@ -417,14 +394,6 @@ def helper_line(points): assert_image_equal_tofile(im, "Tests/images/imagedraw_line.png") -def test_line1(): - helper_line(POINTS1) - - -def test_line2(): - helper_line(POINTS2) - - def test_shape1(): # Arrange im = Image.new("RGB", (100, 100), "white") @@ -484,7 +453,9 @@ def test_transform(): assert_image_equal(im, expected) -def helper_pieslice(bbox, start, end): +@pytest.mark.parametrize("bbox", (BBOX1, BBOX2)) +@pytest.mark.parametrize("start, end", ((-92, 46), (-92.2, 46.2))) +def test_pieslice(bbox, start, end): # Arrange im = Image.new("RGB", (W, H)) draw = ImageDraw.Draw(im) @@ -496,16 +467,6 @@ def helper_pieslice(bbox, start, end): assert_image_similar_tofile(im, "Tests/images/imagedraw_pieslice.png", 1) -def test_pieslice1(): - helper_pieslice(BBOX1, -92, 46) - helper_pieslice(BBOX1, -92.2, 46.2) - - -def test_pieslice2(): - helper_pieslice(BBOX2, -92, 46) - helper_pieslice(BBOX2, -92.2, 46.2) - - def test_pieslice_width(): # Arrange im = Image.new("RGB", (W, H)) @@ -585,7 +546,8 @@ def test_pieslice_no_spikes(): assert_image_equal(im, im_pre_erase) -def helper_point(points): +@pytest.mark.parametrize("points", (POINTS1, POINTS2)) +def test_point(points): # Arrange im = Image.new("RGB", (W, H)) draw = ImageDraw.Draw(im) @@ -597,15 +559,8 @@ def helper_point(points): assert_image_equal_tofile(im, "Tests/images/imagedraw_point.png") -def test_point1(): - helper_point(POINTS1) - - -def test_point2(): - helper_point(POINTS2) - - -def helper_polygon(points): +@pytest.mark.parametrize("points", (POINTS1, POINTS2)) +def test_polygon(points): # Arrange im = Image.new("RGB", (W, H)) draw = ImageDraw.Draw(im) @@ -617,14 +572,6 @@ def helper_polygon(points): assert_image_equal_tofile(im, "Tests/images/imagedraw_polygon.png") -def test_polygon1(): - helper_polygon(POINTS1) - - -def test_polygon2(): - helper_polygon(POINTS2) - - @pytest.mark.parametrize("mode", ("RGB", "L")) def test_polygon_kite(mode): # Test drawing lines of different gradients (dx>dy, dy>dx) and @@ -682,7 +629,8 @@ def test_polygon_translucent(): assert_image_equal_tofile(im, expected) -def helper_rectangle(bbox): +@pytest.mark.parametrize("bbox", (BBOX1, BBOX2)) +def test_rectangle(bbox): # Arrange im = Image.new("RGB", (W, H)) draw = ImageDraw.Draw(im) @@ -694,14 +642,6 @@ def helper_rectangle(bbox): assert_image_equal_tofile(im, "Tests/images/imagedraw_rectangle.png") -def test_rectangle1(): - helper_rectangle(BBOX1) - - -def test_rectangle2(): - helper_rectangle(BBOX2) - - def test_big_rectangle(): # Test drawing a rectangle bigger than the image # Arrange @@ -1503,7 +1443,7 @@ def test_discontiguous_corners_polygon(): assert_image_similar_tofile(img, expected, 1) -def test_polygon(): +def test_polygon2(): im = Image.new("RGB", (W, H)) draw = ImageDraw.Draw(im) draw.polygon([(18, 30), (19, 31), (18, 30), (85, 30), (60, 72)], "red") diff --git a/Tests/test_imagedraw2.py b/Tests/test_imagedraw2.py index e4e8a38cb..6fc829f1a 100644 --- a/Tests/test_imagedraw2.py +++ b/Tests/test_imagedraw2.py @@ -52,27 +52,19 @@ def test_sanity(): draw.line(list(range(10)), pen) -def helper_ellipse(mode, bbox): +@pytest.mark.parametrize("bbox", (BBOX1, BBOX2)) +def test_ellipse(bbox): # Arrange im = Image.new("RGB", (W, H)) draw = ImageDraw2.Draw(im) pen = ImageDraw2.Pen("blue", width=2) brush = ImageDraw2.Brush("green") - expected = f"Tests/images/imagedraw_ellipse_{mode}.png" # Act draw.ellipse(bbox, pen, brush) # Assert - assert_image_similar_tofile(im, expected, 1) - - -def test_ellipse1(): - helper_ellipse("RGB", BBOX1) - - -def test_ellipse2(): - helper_ellipse("RGB", BBOX2) + assert_image_similar_tofile(im, "Tests/images/imagedraw_ellipse_RGB.png", 1) def test_ellipse_edge(): @@ -88,7 +80,8 @@ def test_ellipse_edge(): assert_image_similar_tofile(im, "Tests/images/imagedraw_ellipse_edge.png", 1) -def helper_line(points): +@pytest.mark.parametrize("points", (POINTS1, POINTS2)) +def test_line(points): # Arrange im = Image.new("RGB", (W, H)) draw = ImageDraw2.Draw(im) @@ -101,14 +94,6 @@ def helper_line(points): assert_image_equal_tofile(im, "Tests/images/imagedraw_line.png") -def test_line1_pen(): - helper_line(POINTS1) - - -def test_line2_pen(): - helper_line(POINTS2) - - def test_line_pen_as_brush(): # Arrange im = Image.new("RGB", (W, H)) @@ -124,7 +109,8 @@ def test_line_pen_as_brush(): assert_image_equal_tofile(im, "Tests/images/imagedraw_line.png") -def helper_polygon(points): +@pytest.mark.parametrize("points", (POINTS1, POINTS2)) +def test_polygon(points): # Arrange im = Image.new("RGB", (W, H)) draw = ImageDraw2.Draw(im) @@ -138,15 +124,8 @@ def helper_polygon(points): assert_image_equal_tofile(im, "Tests/images/imagedraw_polygon.png") -def test_polygon1(): - helper_polygon(POINTS1) - - -def test_polygon2(): - helper_polygon(POINTS2) - - -def helper_rectangle(bbox): +@pytest.mark.parametrize("bbox", (BBOX1, BBOX2)) +def test_rectangle(bbox): # Arrange im = Image.new("RGB", (W, H)) draw = ImageDraw2.Draw(im) @@ -160,14 +139,6 @@ def helper_rectangle(bbox): assert_image_equal_tofile(im, "Tests/images/imagedraw_rectangle.png") -def test_rectangle1(): - helper_rectangle(BBOX1) - - -def test_rectangle2(): - helper_rectangle(BBOX2) - - def test_big_rectangle(): # Test drawing a rectangle bigger than the image # Arrange diff --git a/Tests/test_imageenhance.py b/Tests/test_imageenhance.py index 8bc94401e..221ef8cdb 100644 --- a/Tests/test_imageenhance.py +++ b/Tests/test_imageenhance.py @@ -1,3 +1,5 @@ +import pytest + from PIL import Image, ImageEnhance from .helper import assert_image_equal, hopper @@ -39,17 +41,17 @@ def _check_alpha(im, original, op, amount): ) -def test_alpha(): +@pytest.mark.parametrize("op", ("Color", "Brightness", "Contrast", "Sharpness")) +def test_alpha(op): # Issue https://github.com/python-pillow/Pillow/issues/899 # Is alpha preserved through image enhancement? original = _half_transparent_image() - for op in ["Color", "Brightness", "Contrast", "Sharpness"]: - for amount in [0, 0.5, 1.0]: - _check_alpha( - getattr(ImageEnhance, op)(original).enhance(amount), - original, - op, - amount, - ) + for amount in [0, 0.5, 1.0]: + _check_alpha( + getattr(ImageEnhance, op)(original).enhance(amount), + original, + op, + amount, + ) diff --git a/Tests/test_imagefont.py b/Tests/test_imagefont.py index 09e5370e2..a374e24c5 100644 --- a/Tests/test_imagefont.py +++ b/Tests/test_imagefont.py @@ -632,24 +632,24 @@ def test_imagefont_getters(font): assert len(log) == 11 -def test_getsize_stroke(font): - for stroke_width in [0, 2]: - assert font.getbbox("A", stroke_width=stroke_width) == ( - 0 - stroke_width, - 4 - stroke_width, - 12 + stroke_width, - 16 + stroke_width, +@pytest.mark.parametrize("stroke_width", (0, 2)) +def test_getsize_stroke(font, stroke_width): + assert font.getbbox("A", stroke_width=stroke_width) == ( + 0 - stroke_width, + 4 - stroke_width, + 12 + stroke_width, + 16 + stroke_width, + ) + with pytest.warns(DeprecationWarning) as log: + assert font.getsize("A", stroke_width=stroke_width) == ( + 12 + stroke_width * 2, + 16 + stroke_width * 2, ) - with pytest.warns(DeprecationWarning) as log: - assert font.getsize("A", stroke_width=stroke_width) == ( - 12 + stroke_width * 2, - 16 + stroke_width * 2, - ) - assert font.getsize_multiline("ABC\nAaaa", stroke_width=stroke_width) == ( - 48 + stroke_width * 2, - 36 + stroke_width * 4, - ) - assert len(log) == 2 + assert font.getsize_multiline("ABC\nAaaa", stroke_width=stroke_width) == ( + 48 + stroke_width * 2, + 36 + stroke_width * 4, + ) + assert len(log) == 2 def test_complex_font_settings(): diff --git a/Tests/test_imagemorph.py b/Tests/test_imagemorph.py index 6de953068..29c71f917 100644 --- a/Tests/test_imagemorph.py +++ b/Tests/test_imagemorph.py @@ -65,14 +65,16 @@ def create_lut(): # create_lut() -def test_lut(): - for op in ("corner", "dilation4", "dilation8", "erosion4", "erosion8", "edge"): - lb = ImageMorph.LutBuilder(op_name=op) - assert lb.get_lut() is None +@pytest.mark.parametrize( + "op", ("corner", "dilation4", "dilation8", "erosion4", "erosion8", "edge") +) +def test_lut(op): + lb = ImageMorph.LutBuilder(op_name=op) + assert lb.get_lut() is None - lut = lb.build_lut() - with open(f"Tests/images/{op}.lut", "rb") as f: - assert lut == bytearray(f.read()) + lut = lb.build_lut() + with open(f"Tests/images/{op}.lut", "rb") as f: + assert lut == bytearray(f.read()) def test_no_operator_loaded(): diff --git a/Tests/test_imageshow.py b/Tests/test_imageshow.py index 55d7c9479..3e147a9ef 100644 --- a/Tests/test_imageshow.py +++ b/Tests/test_imageshow.py @@ -45,10 +45,10 @@ def test_viewer_show(order): not on_ci() or is_win32(), reason="Only run on CIs; hangs on Windows CIs", ) -def test_show(): - for mode in ("1", "I;16", "LA", "RGB", "RGBA"): - im = hopper(mode) - assert ImageShow.show(im) +@pytest.mark.parametrize("mode", ("1", "I;16", "LA", "RGB", "RGBA")) +def test_show(mode): + im = hopper(mode) + assert ImageShow.show(im) def test_show_without_viewers(): @@ -70,12 +70,12 @@ def test_viewer(): viewer.get_command(None) -def test_viewers(): - for viewer in ImageShow._viewers: - try: - viewer.get_command("test.jpg") - except NotImplementedError: - pass +@pytest.mark.parametrize("viewer", ImageShow._viewers) +def test_viewers(viewer): + try: + viewer.get_command("test.jpg") + except NotImplementedError: + pass def test_ipythonviewer(): @@ -95,14 +95,14 @@ def test_ipythonviewer(): not on_ci() or is_win32(), reason="Only run on CIs; hangs on Windows CIs", ) -def test_file_deprecated(tmp_path): +@pytest.mark.parametrize("viewer", ImageShow._viewers) +def test_file_deprecated(tmp_path, viewer): f = str(tmp_path / "temp.jpg") - for viewer in ImageShow._viewers: - hopper().save(f) - with pytest.warns(DeprecationWarning): - try: - viewer.show_file(file=f) - except NotImplementedError: - pass - with pytest.raises(TypeError): - viewer.show_file() + hopper().save(f) + with pytest.warns(DeprecationWarning): + try: + viewer.show_file(file=f) + except NotImplementedError: + pass + with pytest.raises(TypeError): + viewer.show_file() diff --git a/Tests/test_imagetk.py b/Tests/test_imagetk.py index a848c786f..995d0ee1f 100644 --- a/Tests/test_imagetk.py +++ b/Tests/test_imagetk.py @@ -54,19 +54,19 @@ def test_kw(): assert im is None -def test_photoimage(): - for mode in TK_MODES: - # test as image: - im = hopper(mode) +@pytest.mark.parametrize("mode", TK_MODES) +def test_photoimage(mode): + # test as image: + im = hopper(mode) - # this should not crash - im_tk = ImageTk.PhotoImage(im) + # this should not crash + im_tk = ImageTk.PhotoImage(im) - assert im_tk.width() == im.width - assert im_tk.height() == im.height + assert im_tk.width() == im.width + assert im_tk.height() == im.height - reloaded = ImageTk.getimage(im_tk) - assert_image_equal(reloaded, im.convert("RGBA")) + reloaded = ImageTk.getimage(im_tk) + assert_image_equal(reloaded, im.convert("RGBA")) def test_photoimage_apply_transparency(): @@ -76,17 +76,17 @@ def test_photoimage_apply_transparency(): assert_image_equal(reloaded, im.convert("RGBA")) -def test_photoimage_blank(): +@pytest.mark.parametrize("mode", TK_MODES) +def test_photoimage_blank(mode): # test a image using mode/size: - for mode in TK_MODES: - im_tk = ImageTk.PhotoImage(mode, (100, 100)) + im_tk = ImageTk.PhotoImage(mode, (100, 100)) - assert im_tk.width() == 100 - assert im_tk.height() == 100 + assert im_tk.width() == 100 + assert im_tk.height() == 100 - im = Image.new(mode, (100, 100)) - reloaded = ImageTk.getimage(im_tk) - assert_image_equal(reloaded.convert(mode), im) + im = Image.new(mode, (100, 100)) + reloaded = ImageTk.getimage(im_tk) + assert_image_equal(reloaded.convert(mode), im) def test_box_deprecation(): diff --git a/Tests/test_mode_i16.py b/Tests/test_mode_i16.py index 6e8a2ac58..efcdab9ec 100644 --- a/Tests/test_mode_i16.py +++ b/Tests/test_mode_i16.py @@ -1,3 +1,5 @@ +import pytest + from PIL import Image from .helper import hopper @@ -20,65 +22,56 @@ def verify(im1): ), f"got {repr(p1)} from mode {im1.mode} at {xy}, expected {repr(p2)}" -def test_basic(tmp_path): +@pytest.mark.parametrize("mode", ("L", "I;16", "I;16B", "I;16L", "I")) +def test_basic(tmp_path, mode): # PIL 1.1 has limited support for 16-bit image data. Check that # create/copy/transform and save works as expected. - def basic(mode): + im_in = original.convert(mode) + verify(im_in) - im_in = original.convert(mode) - verify(im_in) + w, h = im_in.size - w, h = im_in.size + im_out = im_in.copy() + verify(im_out) # copy - im_out = im_in.copy() - verify(im_out) # copy + im_out = im_in.transform((w, h), Image.Transform.EXTENT, (0, 0, w, h)) + verify(im_out) # transform - im_out = im_in.transform((w, h), Image.Transform.EXTENT, (0, 0, w, h)) - verify(im_out) # transform + filename = str(tmp_path / "temp.im") + im_in.save(filename) - filename = str(tmp_path / "temp.im") - im_in.save(filename) - - with Image.open(filename) as im_out: - - verify(im_in) - verify(im_out) - - im_out = im_in.crop((0, 0, w, h)) - verify(im_out) - - im_out = Image.new(mode, (w, h), None) - im_out.paste(im_in.crop((0, 0, w // 2, h)), (0, 0)) - im_out.paste(im_in.crop((w // 2, 0, w, h)), (w // 2, 0)) + with Image.open(filename) as im_out: verify(im_in) verify(im_out) - im_in = Image.new(mode, (1, 1), 1) - assert im_in.getpixel((0, 0)) == 1 + im_out = im_in.crop((0, 0, w, h)) + verify(im_out) - im_in.putpixel((0, 0), 2) - assert im_in.getpixel((0, 0)) == 2 + im_out = Image.new(mode, (w, h), None) + im_out.paste(im_in.crop((0, 0, w // 2, h)), (0, 0)) + im_out.paste(im_in.crop((w // 2, 0, w, h)), (w // 2, 0)) - if mode == "L": - maximum = 255 - else: - maximum = 32767 + verify(im_in) + verify(im_out) - im_in = Image.new(mode, (1, 1), 256) - assert im_in.getpixel((0, 0)) == min(256, maximum) + im_in = Image.new(mode, (1, 1), 1) + assert im_in.getpixel((0, 0)) == 1 - im_in.putpixel((0, 0), 512) - assert im_in.getpixel((0, 0)) == min(512, maximum) + im_in.putpixel((0, 0), 2) + assert im_in.getpixel((0, 0)) == 2 - basic("L") + if mode == "L": + maximum = 255 + else: + maximum = 32767 - basic("I;16") - basic("I;16B") - basic("I;16L") + im_in = Image.new(mode, (1, 1), 256) + assert im_in.getpixel((0, 0)) == min(256, maximum) - basic("I") + im_in.putpixel((0, 0), 512) + assert im_in.getpixel((0, 0)) == min(512, maximum) def test_tobytes(): diff --git a/Tests/test_numpy.py b/Tests/test_numpy.py index 9735837bc..185e477ec 100644 --- a/Tests/test_numpy.py +++ b/Tests/test_numpy.py @@ -137,19 +137,9 @@ def test_save_tiff_uint16(): assert img_px[0, 0] == pixel_value -def test_to_array(): - def _to_array(mode, dtype): - img = hopper(mode) - - # Resize to non-square - img = img.crop((3, 0, 124, 127)) - assert img.size == (121, 127) - - np_img = numpy.array(img) - _test_img_equals_nparray(img, np_img) - assert np_img.dtype == dtype - - modes = [ +@pytest.mark.parametrize( + "mode, dtype", + ( ("L", numpy.uint8), ("I", numpy.int32), ("F", numpy.float32), @@ -163,10 +153,18 @@ def test_to_array(): ("I;16B", ">u2"), ("I;16L", "