From 7ad50d9185a7beef755ea7c19b8cfe6e5bea815e Mon Sep 17 00:00:00 2001 From: Yay295 Date: Sun, 15 Jan 2023 19:42:55 -0600 Subject: [PATCH 01/22] log expected & actual color in image access tests --- Tests/test_image_access.py | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/Tests/test_image_access.py b/Tests/test_image_access.py index 6c4f1ceec..83eb7a1b2 100644 --- a/Tests/test_image_access.py +++ b/Tests/test_image_access.py @@ -139,15 +139,18 @@ class TestImageGetPixel(AccessTest): # check putpixel im = Image.new(mode, (1, 1), None) im.putpixel((0, 0), c) + d = im.getpixel((0, 0)) assert ( - im.getpixel((0, 0)) == c - ), f"put/getpixel roundtrip failed for mode {mode}, color {c}" + d == c + ), f"put/getpixel roundtrip failed for mode {mode}, expected {c} got {d}" # check putpixel negative index im.putpixel((-1, -1), c) - assert ( - im.getpixel((-1, -1)) == c - ), f"put/getpixel roundtrip negative index failed for mode {mode}, color {c}" + d = im.getpixel((-1, -1)) + assert d == c, ( + f"put/getpixel roundtrip negative index failed for mode {mode}, " + f"expected {c} got {d}" + ) # Check 0 im = Image.new(mode, (0, 0), None) @@ -166,13 +169,15 @@ class TestImageGetPixel(AccessTest): # check initial color im = Image.new(mode, (1, 1), c) - assert ( - im.getpixel((0, 0)) == c - ), f"initial color failed for mode {mode}, color {c} " + d = im.getpixel((0, 0)) + assert d == c, f"initial color failed for mode {mode}, expected {c} got {d}" + # check initial color negative index - assert ( - im.getpixel((-1, -1)) == c - ), f"initial color failed with negative index for mode {mode}, color {c} " + d = im.getpixel((-1, -1)) + assert d == c, ( + f"initial color failed with negative index for mode {mode}, " + f"expected {c} got {d}" + ) # Check 0 im = Image.new(mode, (0, 0), c) From 1603872f244da741feeac5a87d235e570723853f Mon Sep 17 00:00:00 2001 From: Yay295 Date: Mon, 16 Jan 2023 07:46:11 -0600 Subject: [PATCH 02/22] use better variable names --- Tests/test_image_access.py | 46 +++++++++++++++++++++----------------- 1 file changed, 25 insertions(+), 21 deletions(-) diff --git a/Tests/test_image_access.py b/Tests/test_image_access.py index 83eb7a1b2..e22b8d74c 100644 --- a/Tests/test_image_access.py +++ b/Tests/test_image_access.py @@ -132,24 +132,25 @@ class TestImageGetPixel(AccessTest): return 1 return tuple(range(1, bands + 1)) - def check(self, mode, c=None): - if not c: - c = self.color(mode) + def check(self, mode, expected_color=None): + if not expected_color: + expected_color = self.color(mode) # check putpixel im = Image.new(mode, (1, 1), None) - im.putpixel((0, 0), c) - d = im.getpixel((0, 0)) - assert ( - d == c - ), f"put/getpixel roundtrip failed for mode {mode}, expected {c} got {d}" + im.putpixel((0, 0), expected_color) + actual_color = im.getpixel((0, 0)) + assert actual_color == expected_color, ( + f"put/getpixel roundtrip failed for mode {mode}, " + f"expected {expected_color} got {actual_color}" + ) # check putpixel negative index - im.putpixel((-1, -1), c) - d = im.getpixel((-1, -1)) - assert d == c, ( + im.putpixel((-1, -1), expected_color) + actual_color = im.getpixel((-1, -1)) + assert actual_color == expected_color, ( f"put/getpixel roundtrip negative index failed for mode {mode}, " - f"expected {c} got {d}" + f"expected {expected_color} got {actual_color}" ) # Check 0 @@ -158,29 +159,32 @@ class TestImageGetPixel(AccessTest): error = ValueError if self._need_cffi_access else IndexError with pytest.raises(error): - im.putpixel((0, 0), c) + im.putpixel((0, 0), expected_color) with pytest.raises(error): im.getpixel((0, 0)) # Check 0 negative index with pytest.raises(error): - im.putpixel((-1, -1), c) + im.putpixel((-1, -1), expected_color) with pytest.raises(error): im.getpixel((-1, -1)) # check initial color - im = Image.new(mode, (1, 1), c) - d = im.getpixel((0, 0)) - assert d == c, f"initial color failed for mode {mode}, expected {c} got {d}" + im = Image.new(mode, (1, 1), expected_color) + actual_color = im.getpixel((0, 0)) + assert actual_color == expected_color, ( + f"initial color failed for mode {mode}, " + f"expected {expected_color} got {actual_color}" + ) # check initial color negative index - d = im.getpixel((-1, -1)) - assert d == c, ( + actual_color = im.getpixel((-1, -1)) + assert actual_color == expected_color, ( f"initial color failed with negative index for mode {mode}, " - f"expected {c} got {d}" + f"expected {expected_color} got {actual_color}" ) # Check 0 - im = Image.new(mode, (0, 0), c) + im = Image.new(mode, (0, 0), expected_color) with pytest.raises(error): im.getpixel((0, 0)) # Check 0 negative index From e80707547f67493f565b65319e94a53262914f29 Mon Sep 17 00:00:00 2001 From: Yay295 Date: Mon, 16 Jan 2023 07:47:24 -0600 Subject: [PATCH 03/22] parametrize test_image_access::test_signedness() --- Tests/test_image_access.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Tests/test_image_access.py b/Tests/test_image_access.py index e22b8d74c..4079d9358 100644 --- a/Tests/test_image_access.py +++ b/Tests/test_image_access.py @@ -214,13 +214,13 @@ class TestImageGetPixel(AccessTest): self.check(mode) @pytest.mark.parametrize("mode", ("I;16", "I;16B")) - def test_signedness(self, mode): + @pytest.mark.parametrize( + "expected_color", (2**15 - 1, 2**15, 2**15 + 1, 2**16 - 1) + ) + def test_signedness(self, mode, expected_color): # see https://github.com/python-pillow/Pillow/issues/452 # pixelaccess is using signed int* instead of uint* - self.check(mode, 2**15 - 1) - self.check(mode, 2**15) - self.check(mode, 2**15 + 1) - self.check(mode, 2**16 - 1) + self.check(mode, expected_color) @pytest.mark.parametrize("mode", ("P", "PA")) @pytest.mark.parametrize("color", ((255, 0, 0), (255, 0, 0, 255))) From 5c8a9165abcf7c2d2ec2829681e88726dafddaf4 Mon Sep 17 00:00:00 2001 From: Aarni Koskela Date: Thu, 23 Feb 2023 15:18:11 +0200 Subject: [PATCH 04/22] Fix up pytest.raises lambda: uses --- Tests/test_imagefont.py | 37 ++++++++++++++-------------- Tests/test_imagefontctl.py | 49 +++++++++++++------------------------- 2 files changed, 34 insertions(+), 52 deletions(-) diff --git a/Tests/test_imagefont.py b/Tests/test_imagefont.py index 306a2f1bf..b115517ac 100644 --- a/Tests/test_imagefont.py +++ b/Tests/test_imagefont.py @@ -351,7 +351,8 @@ def test_rotated_transposed_font(font, orientation): assert bbox_b[3] == 20 + bbox_a[2] - bbox_a[0] # text length is undefined for vertical text - pytest.raises(ValueError, draw.textlength, word) + with pytest.raises(ValueError): + draw.textlength(word) @pytest.mark.parametrize( @@ -872,25 +873,23 @@ def test_anchor_invalid(font): d.font = font for anchor in ["", "l", "a", "lax", "sa", "xa", "lx"]: - pytest.raises(ValueError, lambda: font.getmask2("hello", anchor=anchor)) - pytest.raises(ValueError, lambda: font.getbbox("hello", anchor=anchor)) - pytest.raises(ValueError, lambda: d.text((0, 0), "hello", anchor=anchor)) - pytest.raises(ValueError, lambda: d.textbbox((0, 0), "hello", anchor=anchor)) - pytest.raises( - ValueError, lambda: d.multiline_text((0, 0), "foo\nbar", anchor=anchor) - ) - pytest.raises( - ValueError, - lambda: d.multiline_textbbox((0, 0), "foo\nbar", anchor=anchor), - ) + with pytest.raises(ValueError): + font.getmask2("hello", anchor=anchor) + with pytest.raises(ValueError): + font.getbbox("hello", anchor=anchor) + with pytest.raises(ValueError): + d.text((0, 0), "hello", anchor=anchor) + with pytest.raises(ValueError): + d.textbbox((0, 0), "hello", anchor=anchor) + with pytest.raises(ValueError): + d.multiline_text((0, 0), "foo\nbar", anchor=anchor) + with pytest.raises(ValueError): + d.multiline_textbbox((0, 0), "foo\nbar", anchor=anchor) for anchor in ["lt", "lb"]: - pytest.raises( - ValueError, lambda: d.multiline_text((0, 0), "foo\nbar", anchor=anchor) - ) - pytest.raises( - ValueError, - lambda: d.multiline_textbbox((0, 0), "foo\nbar", anchor=anchor), - ) + with pytest.raises(ValueError): + d.multiline_text((0, 0), "foo\nbar", anchor=anchor) + with pytest.raises(ValueError): + d.multiline_textbbox((0, 0), "foo\nbar", anchor=anchor) @pytest.mark.parametrize("bpp", (1, 2, 4, 8)) diff --git a/Tests/test_imagefontctl.py b/Tests/test_imagefontctl.py index cf039e86e..6099b04e4 100644 --- a/Tests/test_imagefontctl.py +++ b/Tests/test_imagefontctl.py @@ -360,37 +360,20 @@ def test_anchor_invalid_ttb(): d.font = font for anchor in ["", "l", "a", "lax", "xa", "la", "ls", "ld", "lx"]: - pytest.raises( - ValueError, lambda: font.getmask2("hello", anchor=anchor, direction="ttb") - ) - pytest.raises( - ValueError, lambda: font.getbbox("hello", anchor=anchor, direction="ttb") - ) - pytest.raises( - ValueError, lambda: d.text((0, 0), "hello", anchor=anchor, direction="ttb") - ) - pytest.raises( - ValueError, - lambda: d.textbbox((0, 0), "hello", anchor=anchor, direction="ttb"), - ) - pytest.raises( - ValueError, - lambda: d.multiline_text( - (0, 0), "foo\nbar", anchor=anchor, direction="ttb" - ), - ) - pytest.raises( - ValueError, - lambda: d.multiline_textbbox( - (0, 0), "foo\nbar", anchor=anchor, direction="ttb" - ), - ) + with pytest.raises(ValueError): + font.getmask2("hello", anchor=anchor, direction="ttb") + with pytest.raises(ValueError): + font.getbbox("hello", anchor=anchor, direction="ttb") + with pytest.raises(ValueError): + d.text((0, 0), "hello", anchor=anchor, direction="ttb") + with pytest.raises(ValueError): + d.textbbox((0, 0), "hello", anchor=anchor, direction="ttb") + with pytest.raises(ValueError): + d.multiline_text((0, 0), "foo\nbar", anchor=anchor, direction="ttb") + with pytest.raises(ValueError): + d.multiline_textbbox((0, 0), "foo\nbar", anchor=anchor, direction="ttb") # ttb multiline text does not support anchors at all - pytest.raises( - ValueError, - lambda: d.multiline_text((0, 0), "foo\nbar", anchor="mm", direction="ttb"), - ) - pytest.raises( - ValueError, - lambda: d.multiline_textbbox((0, 0), "foo\nbar", anchor="mm", direction="ttb"), - ) + with pytest.raises(ValueError): + d.multiline_text((0, 0), "foo\nbar", anchor="mm", direction="ttb") + with pytest.raises(ValueError): + d.multiline_textbbox((0, 0), "foo\nbar", anchor="mm", direction="ttb") From 43128ce7165528a8f2bb168e0c89369bbb61817c Mon Sep 17 00:00:00 2001 From: Aarni Koskela Date: Thu, 23 Feb 2023 15:30:38 +0200 Subject: [PATCH 05/22] Fix up pytest.warns lambda: uses --- Tests/test_core_resources.py | 21 +++++++++++---------- Tests/test_decompression_bomb.py | 10 +++++----- Tests/test_file_apng.py | 17 ++++------------- Tests/test_file_dcx.py | 5 ++--- Tests/test_file_fli.py | 5 ++--- Tests/test_file_gif.py | 8 ++++---- Tests/test_file_ico.py | 4 +--- Tests/test_file_im.py | 5 ++--- Tests/test_file_mpo.py | 5 ++--- Tests/test_file_psd.py | 5 ++--- Tests/test_file_spider.py | 5 ++--- Tests/test_file_tar.py | 4 +--- Tests/test_file_tga.py | 4 +++- Tests/test_file_tiff.py | 8 ++++---- Tests/test_file_tiff_metadata.py | 6 ++++-- Tests/test_file_webp.py | 4 +++- 16 files changed, 52 insertions(+), 64 deletions(-) diff --git a/Tests/test_core_resources.py b/Tests/test_core_resources.py index 385192a3c..e4c0001d1 100644 --- a/Tests/test_core_resources.py +++ b/Tests/test_core_resources.py @@ -177,13 +177,14 @@ class TestEnvVars: Image._apply_env_variables({"PILLOW_BLOCK_SIZE": "2m"}) assert Image.core.get_block_size() == 2 * 1024 * 1024 - def test_warnings(self): - pytest.warns( - UserWarning, Image._apply_env_variables, {"PILLOW_ALIGNMENT": "15"} - ) - pytest.warns( - UserWarning, Image._apply_env_variables, {"PILLOW_BLOCK_SIZE": "1024"} - ) - pytest.warns( - UserWarning, Image._apply_env_variables, {"PILLOW_BLOCKS_MAX": "wat"} - ) + @pytest.mark.parametrize( + "vars", + [ + {"PILLOW_ALIGNMENT": "15"}, + {"PILLOW_BLOCK_SIZE": "1024"}, + {"PILLOW_BLOCKS_MAX": "wat"}, + ], + ) + def test_warnings(self, vars): + with pytest.warns(UserWarning): + Image._apply_env_variables(vars) diff --git a/Tests/test_decompression_bomb.py b/Tests/test_decompression_bomb.py index 63071b78c..4fd02449c 100644 --- a/Tests/test_decompression_bomb.py +++ b/Tests/test_decompression_bomb.py @@ -36,12 +36,10 @@ class TestDecompressionBomb: Image.MAX_IMAGE_PIXELS = 128 * 128 - 1 assert Image.MAX_IMAGE_PIXELS == 128 * 128 - 1 - def open(): + with pytest.warns(Image.DecompressionBombWarning): with Image.open(TEST_FILE): pass - pytest.warns(Image.DecompressionBombWarning, open) - def test_exception(self): # Set limit to trigger exception on the test file Image.MAX_IMAGE_PIXELS = 64 * 128 - 1 @@ -87,7 +85,8 @@ class TestDecompressionCrop: # same decompression bomb warnings on them. with hopper() as src: box = (0, 0, src.width * 2, src.height * 2) - pytest.warns(Image.DecompressionBombWarning, src.crop, box) + with pytest.warns(Image.DecompressionBombWarning): + src.crop(box) def test_crop_decompression_checks(self): im = Image.new("RGB", (100, 100)) @@ -95,7 +94,8 @@ class TestDecompressionCrop: for value in ((-9999, -9999, -9990, -9990), (-999, -999, -990, -990)): assert im.crop(value).size == (9, 9) - pytest.warns(Image.DecompressionBombWarning, im.crop, (-160, -160, 99, 99)) + with pytest.warns(Image.DecompressionBombWarning): + im.crop((-160, -160, 99, 99)) with pytest.raises(Image.DecompressionBombError): im.crop((-99909, -99990, 99999, 99999)) diff --git a/Tests/test_file_apng.py b/Tests/test_file_apng.py index 51637c786..9f850d0e9 100644 --- a/Tests/test_file_apng.py +++ b/Tests/test_file_apng.py @@ -263,12 +263,9 @@ def test_apng_chunk_errors(): with Image.open("Tests/images/apng/chunk_no_actl.png") as im: assert not im.is_animated - def open(): + with pytest.warns(UserWarning): with Image.open("Tests/images/apng/chunk_multi_actl.png") as im: im.load() - assert not im.is_animated - - pytest.warns(UserWarning, open) with Image.open("Tests/images/apng/chunk_actl_after_idat.png") as im: assert not im.is_animated @@ -287,21 +284,17 @@ def test_apng_chunk_errors(): def test_apng_syntax_errors(): - def open_frames_zero(): + with pytest.warns(UserWarning): with Image.open("Tests/images/apng/syntax_num_frames_zero.png") as im: assert not im.is_animated with pytest.raises(OSError): im.load() - pytest.warns(UserWarning, open_frames_zero) - - def open_frames_zero_default(): + with pytest.warns(UserWarning): with Image.open("Tests/images/apng/syntax_num_frames_zero_default.png") as im: assert not im.is_animated im.load() - pytest.warns(UserWarning, open_frames_zero_default) - # we can handle this case gracefully exception = None with Image.open("Tests/images/apng/syntax_num_frames_low.png") as im: @@ -316,13 +309,11 @@ def test_apng_syntax_errors(): im.seek(im.n_frames - 1) im.load() - def open(): + with pytest.warns(UserWarning): with Image.open("Tests/images/apng/syntax_num_frames_invalid.png") as im: assert not im.is_animated im.load() - pytest.warns(UserWarning, open) - @pytest.mark.parametrize( "test_file", diff --git a/Tests/test_file_dcx.py b/Tests/test_file_dcx.py index ef378b24a..1adda7729 100644 --- a/Tests/test_file_dcx.py +++ b/Tests/test_file_dcx.py @@ -24,11 +24,10 @@ def test_sanity(): @pytest.mark.skipif(is_pypy(), reason="Requires CPython") def test_unclosed_file(): - def open(): + with pytest.warns(ResourceWarning): im = Image.open(TEST_FILE) im.load() - - pytest.warns(ResourceWarning, open) + del im def test_closed_file(): diff --git a/Tests/test_file_fli.py b/Tests/test_file_fli.py index 70d4d76db..cb767a0d8 100644 --- a/Tests/test_file_fli.py +++ b/Tests/test_file_fli.py @@ -32,11 +32,10 @@ def test_sanity(): @pytest.mark.skipif(is_pypy(), reason="Requires CPython") def test_unclosed_file(): - def open(): + with pytest.warns(ResourceWarning): im = Image.open(static_test_file) im.load() - - pytest.warns(ResourceWarning, open) + del im def test_closed_file(): diff --git a/Tests/test_file_gif.py b/Tests/test_file_gif.py index bce72d192..8f11f0a1c 100644 --- a/Tests/test_file_gif.py +++ b/Tests/test_file_gif.py @@ -32,11 +32,10 @@ def test_sanity(): @pytest.mark.skipif(is_pypy(), reason="Requires CPython") def test_unclosed_file(): - def open(): + with pytest.warns(ResourceWarning): im = Image.open(TEST_GIF) im.load() - - pytest.warns(ResourceWarning, open) + del im def test_closed_file(): @@ -1087,7 +1086,8 @@ def test_rgb_transparency(tmp_path): im = Image.new("RGB", (1, 1)) im.info["transparency"] = b"" ims = [Image.new("RGB", (1, 1))] - pytest.warns(UserWarning, im.save, out, save_all=True, append_images=ims) + with pytest.warns(UserWarning): + im.save(out, save_all=True, append_images=ims) with Image.open(out) as reloaded: assert "transparency" not in reloaded.info diff --git a/Tests/test_file_ico.py b/Tests/test_file_ico.py index 9c1c3cf17..4e6dbe6ed 100644 --- a/Tests/test_file_ico.py +++ b/Tests/test_file_ico.py @@ -212,12 +212,10 @@ def test_save_append_images(tmp_path): def test_unexpected_size(): # This image has been manually hexedited to state that it is 16x32 # while the image within is still 16x16 - def open(): + with pytest.warns(UserWarning): with Image.open("Tests/images/hopper_unexpected.ico") as im: assert im.size == (16, 16) - pytest.warns(UserWarning, open) - def test_draw_reloaded(tmp_path): with Image.open(TEST_ICO_FILE) as im: diff --git a/Tests/test_file_im.py b/Tests/test_file_im.py index 425e690d6..bdc704ee1 100644 --- a/Tests/test_file_im.py +++ b/Tests/test_file_im.py @@ -28,11 +28,10 @@ def test_name_limit(tmp_path): @pytest.mark.skipif(is_pypy(), reason="Requires CPython") def test_unclosed_file(): - def open(): + with pytest.warns(ResourceWarning): im = Image.open(TEST_IM) im.load() - - pytest.warns(ResourceWarning, open) + del im def test_closed_file(): diff --git a/Tests/test_file_mpo.py b/Tests/test_file_mpo.py index f0dedc2de..ea701f70d 100644 --- a/Tests/test_file_mpo.py +++ b/Tests/test_file_mpo.py @@ -38,11 +38,10 @@ def test_sanity(test_file): @pytest.mark.skipif(is_pypy(), reason="Requires CPython") def test_unclosed_file(): - def open(): + with pytest.warns(ResourceWarning): im = Image.open(test_files[0]) im.load() - - pytest.warns(ResourceWarning, open) + del im def test_closed_file(): diff --git a/Tests/test_file_psd.py b/Tests/test_file_psd.py index 036cb9d4b..ff78993fe 100644 --- a/Tests/test_file_psd.py +++ b/Tests/test_file_psd.py @@ -23,11 +23,10 @@ def test_sanity(): @pytest.mark.skipif(is_pypy(), reason="Requires CPython") def test_unclosed_file(): - def open(): + with pytest.warns(ResourceWarning): im = Image.open(test_file) im.load() - - pytest.warns(ResourceWarning, open) + del im def test_closed_file(): diff --git a/Tests/test_file_spider.py b/Tests/test_file_spider.py index 011e208d8..122690e34 100644 --- a/Tests/test_file_spider.py +++ b/Tests/test_file_spider.py @@ -21,11 +21,10 @@ def test_sanity(): @pytest.mark.skipif(is_pypy(), reason="Requires CPython") def test_unclosed_file(): - def open(): + with pytest.warns(ResourceWarning): im = Image.open(TEST_FILE) im.load() - - pytest.warns(ResourceWarning, open) + del im def test_closed_file(): diff --git a/Tests/test_file_tar.py b/Tests/test_file_tar.py index 799c243d6..b27fa25f3 100644 --- a/Tests/test_file_tar.py +++ b/Tests/test_file_tar.py @@ -29,11 +29,9 @@ def test_sanity(codec, test_path, format): @pytest.mark.skipif(is_pypy(), reason="Requires CPython") def test_unclosed_file(): - def open(): + with pytest.warns(ResourceWarning): TarIO.TarIO(TEST_TAR_FILE, "hopper.jpg") - pytest.warns(ResourceWarning, open) - def test_close(): with warnings.catch_warnings(): diff --git a/Tests/test_file_tga.py b/Tests/test_file_tga.py index bac00e855..1a5730f49 100644 --- a/Tests/test_file_tga.py +++ b/Tests/test_file_tga.py @@ -163,7 +163,9 @@ def test_save_id_section(tmp_path): # Save with custom id section greater than 255 characters id_section = b"Test content" * 25 - pytest.warns(UserWarning, lambda: im.save(out, id_section=id_section)) + with pytest.warns(UserWarning): + im.save(out, id_section=id_section) + with Image.open(out) as test_im: assert test_im.info["id_section"] == id_section[:255] diff --git a/Tests/test_file_tiff.py b/Tests/test_file_tiff.py index 70142747c..d0d9ed891 100644 --- a/Tests/test_file_tiff.py +++ b/Tests/test_file_tiff.py @@ -57,11 +57,10 @@ class TestFileTiff: @pytest.mark.skipif(is_pypy(), reason="Requires CPython") def test_unclosed_file(self): - def open(): + with pytest.warns(ResourceWarning): im = Image.open("Tests/images/multipage.tiff") im.load() - - pytest.warns(ResourceWarning, open) + del im def test_closed_file(self): with warnings.catch_warnings(): @@ -231,7 +230,8 @@ class TestFileTiff: def test_bad_exif(self): with Image.open("Tests/images/hopper_bad_exif.jpg") as i: # Should not raise struct.error. - pytest.warns(UserWarning, i._getexif) + with pytest.warns(UserWarning): + i._getexif() def test_save_rgba(self, tmp_path): im = hopper("RGBA") diff --git a/Tests/test_file_tiff_metadata.py b/Tests/test_file_tiff_metadata.py index fdabae3a3..9a5681526 100644 --- a/Tests/test_file_tiff_metadata.py +++ b/Tests/test_file_tiff_metadata.py @@ -252,7 +252,8 @@ def test_empty_metadata(): head = f.read(8) info = TiffImagePlugin.ImageFileDirectory(head) # Should not raise struct.error. - pytest.warns(UserWarning, info.load, f) + with pytest.warns(UserWarning): + info.load(f) def test_iccprofile(tmp_path): @@ -422,7 +423,8 @@ def test_too_many_entries(): ifd.tagtype[277] = TiffTags.SHORT # Should not raise ValueError. - pytest.warns(UserWarning, lambda: ifd[277]) + with pytest.warns(UserWarning): + _ = ifd[277] def test_tag_group_data(): diff --git a/Tests/test_file_webp.py b/Tests/test_file_webp.py index f1bdc59cf..335201fe1 100644 --- a/Tests/test_file_webp.py +++ b/Tests/test_file_webp.py @@ -29,7 +29,9 @@ class TestUnsupportedWebp: WebPImagePlugin.SUPPORTED = False file_path = "Tests/images/hopper.webp" - pytest.warns(UserWarning, lambda: pytest.raises(OSError, Image.open, file_path)) + with pytest.warns(UserWarning): + with pytest.raises(OSError): + Image.open(file_path) if HAVE_WEBP: WebPImagePlugin.SUPPORTED = True From 44c4e67fe13719672219aa2de67b8c19f921c191 Mon Sep 17 00:00:00 2001 From: Aarni Koskela Date: Fri, 24 Feb 2023 09:26:18 +0200 Subject: [PATCH 06/22] Fix `vars` to `var` Co-authored-by: Hugo van Kemenade --- Tests/test_core_resources.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Tests/test_core_resources.py b/Tests/test_core_resources.py index e4c0001d1..cb6cde8eb 100644 --- a/Tests/test_core_resources.py +++ b/Tests/test_core_resources.py @@ -178,13 +178,13 @@ class TestEnvVars: assert Image.core.get_block_size() == 2 * 1024 * 1024 @pytest.mark.parametrize( - "vars", + "var", [ {"PILLOW_ALIGNMENT": "15"}, {"PILLOW_BLOCK_SIZE": "1024"}, {"PILLOW_BLOCKS_MAX": "wat"}, ], ) - def test_warnings(self, vars): + def test_warnings(self, var): with pytest.warns(UserWarning): - Image._apply_env_variables(vars) + Image._apply_env_variables(var) From 1263018d2afbc19e9dce8b82d064cccc2e5ccfca Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Fri, 24 Feb 2023 23:00:29 +1100 Subject: [PATCH 07/22] Assert value instead of assigning unused variable --- Tests/test_file_tiff_metadata.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Tests/test_file_tiff_metadata.py b/Tests/test_file_tiff_metadata.py index 9a5681526..b7d100e7a 100644 --- a/Tests/test_file_tiff_metadata.py +++ b/Tests/test_file_tiff_metadata.py @@ -419,12 +419,12 @@ def test_too_many_entries(): ifd = TiffImagePlugin.ImageFileDirectory_v2() # 277: ("SamplesPerPixel", SHORT, 1), - ifd._tagdata[277] = struct.pack("hh", 4, 4) + ifd._tagdata[277] = struct.pack(" Date: Fri, 3 Mar 2023 07:50:52 +1100 Subject: [PATCH 08/22] Removed "del im" --- Tests/test_file_dcx.py | 6 ++++-- Tests/test_file_fli.py | 6 ++++-- Tests/test_file_gif.py | 6 ++++-- Tests/test_file_im.py | 6 ++++-- Tests/test_file_mpo.py | 6 ++++-- Tests/test_file_psd.py | 6 ++++-- Tests/test_file_spider.py | 6 ++++-- Tests/test_file_tiff.py | 6 ++++-- 8 files changed, 32 insertions(+), 16 deletions(-) diff --git a/Tests/test_file_dcx.py b/Tests/test_file_dcx.py index 1adda7729..22686af34 100644 --- a/Tests/test_file_dcx.py +++ b/Tests/test_file_dcx.py @@ -24,10 +24,12 @@ def test_sanity(): @pytest.mark.skipif(is_pypy(), reason="Requires CPython") def test_unclosed_file(): - with pytest.warns(ResourceWarning): + def open(): im = Image.open(TEST_FILE) im.load() - del im + + with pytest.warns(ResourceWarning): + open() def test_closed_file(): diff --git a/Tests/test_file_fli.py b/Tests/test_file_fli.py index cb767a0d8..f96afdc95 100644 --- a/Tests/test_file_fli.py +++ b/Tests/test_file_fli.py @@ -32,10 +32,12 @@ def test_sanity(): @pytest.mark.skipif(is_pypy(), reason="Requires CPython") def test_unclosed_file(): - with pytest.warns(ResourceWarning): + def open(): im = Image.open(static_test_file) im.load() - del im + + with pytest.warns(ResourceWarning): + open() def test_closed_file(): diff --git a/Tests/test_file_gif.py b/Tests/test_file_gif.py index 8f11f0a1c..8522f486a 100644 --- a/Tests/test_file_gif.py +++ b/Tests/test_file_gif.py @@ -32,10 +32,12 @@ def test_sanity(): @pytest.mark.skipif(is_pypy(), reason="Requires CPython") def test_unclosed_file(): - with pytest.warns(ResourceWarning): + def open(): im = Image.open(TEST_GIF) im.load() - del im + + with pytest.warns(ResourceWarning): + open() def test_closed_file(): diff --git a/Tests/test_file_im.py b/Tests/test_file_im.py index bdc704ee1..fd00f260e 100644 --- a/Tests/test_file_im.py +++ b/Tests/test_file_im.py @@ -28,10 +28,12 @@ def test_name_limit(tmp_path): @pytest.mark.skipif(is_pypy(), reason="Requires CPython") def test_unclosed_file(): - with pytest.warns(ResourceWarning): + def open(): im = Image.open(TEST_IM) im.load() - del im + + with pytest.warns(ResourceWarning): + open() def test_closed_file(): diff --git a/Tests/test_file_mpo.py b/Tests/test_file_mpo.py index ea701f70d..2e921e467 100644 --- a/Tests/test_file_mpo.py +++ b/Tests/test_file_mpo.py @@ -38,10 +38,12 @@ def test_sanity(test_file): @pytest.mark.skipif(is_pypy(), reason="Requires CPython") def test_unclosed_file(): - with pytest.warns(ResourceWarning): + def open(): im = Image.open(test_files[0]) im.load() - del im + + with pytest.warns(ResourceWarning): + open() def test_closed_file(): diff --git a/Tests/test_file_psd.py b/Tests/test_file_psd.py index ff78993fe..e405834b5 100644 --- a/Tests/test_file_psd.py +++ b/Tests/test_file_psd.py @@ -23,10 +23,12 @@ def test_sanity(): @pytest.mark.skipif(is_pypy(), reason="Requires CPython") def test_unclosed_file(): - with pytest.warns(ResourceWarning): + def open(): im = Image.open(test_file) im.load() - del im + + with pytest.warns(ResourceWarning): + open() def test_closed_file(): diff --git a/Tests/test_file_spider.py b/Tests/test_file_spider.py index 122690e34..09f1ef8e4 100644 --- a/Tests/test_file_spider.py +++ b/Tests/test_file_spider.py @@ -21,10 +21,12 @@ def test_sanity(): @pytest.mark.skipif(is_pypy(), reason="Requires CPython") def test_unclosed_file(): - with pytest.warns(ResourceWarning): + def open(): im = Image.open(TEST_FILE) im.load() - del im + + with pytest.warns(ResourceWarning): + open() def test_closed_file(): diff --git a/Tests/test_file_tiff.py b/Tests/test_file_tiff.py index d0d9ed891..b40f690f5 100644 --- a/Tests/test_file_tiff.py +++ b/Tests/test_file_tiff.py @@ -57,10 +57,12 @@ class TestFileTiff: @pytest.mark.skipif(is_pypy(), reason="Requires CPython") def test_unclosed_file(self): - with pytest.warns(ResourceWarning): + def open(): im = Image.open("Tests/images/multipage.tiff") im.load() - del im + + with pytest.warns(ResourceWarning): + open() def test_closed_file(self): with warnings.catch_warnings(): From 32bfee030bfc30626eb2165c0a69ff181c3bdaef Mon Sep 17 00:00:00 2001 From: Aarni Koskela Date: Fri, 3 Mar 2023 10:29:51 +0200 Subject: [PATCH 09/22] Update Tests/test_file_apng.py Co-authored-by: Andrew Murray <3112309+radarhere@users.noreply.github.com> --- Tests/test_file_apng.py | 1 + 1 file changed, 1 insertion(+) diff --git a/Tests/test_file_apng.py b/Tests/test_file_apng.py index 9f850d0e9..b2bec5984 100644 --- a/Tests/test_file_apng.py +++ b/Tests/test_file_apng.py @@ -266,6 +266,7 @@ def test_apng_chunk_errors(): with pytest.warns(UserWarning): with Image.open("Tests/images/apng/chunk_multi_actl.png") as im: im.load() + assert not im.is_animated with Image.open("Tests/images/apng/chunk_actl_after_idat.png") as im: assert not im.is_animated From 2299490082f3d53c6cf8a70c88bcef7ebf5329ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Carron?= Date: Fri, 3 Mar 2023 11:41:37 +0100 Subject: [PATCH 10/22] Close the file pointer copy (_fp) in the libtiff encoder if it is still open. --- src/PIL/TiffImagePlugin.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/PIL/TiffImagePlugin.py b/src/PIL/TiffImagePlugin.py index 04d246dd4..42038831c 100644 --- a/src/PIL/TiffImagePlugin.py +++ b/src/PIL/TiffImagePlugin.py @@ -1850,6 +1850,11 @@ def _save(im, fp, filename): fp.write(data) if errcode: break + if _fp: + try: + os.close(_fp) + except OSError: + pass if errcode < 0: msg = f"encoder error {errcode} when writing image file" raise OSError(msg) From 912ab3e0889a0475e6edef4149de980345b1eb88 Mon Sep 17 00:00:00 2001 From: Aarni Koskela Date: Fri, 3 Mar 2023 16:00:56 +0200 Subject: [PATCH 11/22] Apply suggestions from code review Co-authored-by: Andrew Murray <3112309+radarhere@users.noreply.github.com> --- Tests/test_core_resources.py | 4 ++-- Tests/test_file_webp.py | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Tests/test_core_resources.py b/Tests/test_core_resources.py index cb6cde8eb..9021a9fb3 100644 --- a/Tests/test_core_resources.py +++ b/Tests/test_core_resources.py @@ -179,11 +179,11 @@ class TestEnvVars: @pytest.mark.parametrize( "var", - [ + ( {"PILLOW_ALIGNMENT": "15"}, {"PILLOW_BLOCK_SIZE": "1024"}, {"PILLOW_BLOCKS_MAX": "wat"}, - ], + ), ) def test_warnings(self, var): with pytest.warns(UserWarning): diff --git a/Tests/test_file_webp.py b/Tests/test_file_webp.py index 335201fe1..a7b6c735a 100644 --- a/Tests/test_file_webp.py +++ b/Tests/test_file_webp.py @@ -31,7 +31,8 @@ class TestUnsupportedWebp: file_path = "Tests/images/hopper.webp" with pytest.warns(UserWarning): with pytest.raises(OSError): - Image.open(file_path) + with Image.open(file_path): + pass if HAVE_WEBP: WebPImagePlugin.SUPPORTED = True From e953978b31954549caf4e6fab185b344644ab0ce Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Sat, 4 Mar 2023 11:44:45 +1100 Subject: [PATCH 12/22] Added test --- Tests/test_file_libtiff.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Tests/test_file_libtiff.py b/Tests/test_file_libtiff.py index f886d3aae..871ad28b5 100644 --- a/Tests/test_file_libtiff.py +++ b/Tests/test_file_libtiff.py @@ -1065,3 +1065,9 @@ class TestFileLibTiff(LibTiffTestCase): out = str(tmp_path / "temp.tif") with pytest.raises(SystemError): im.save(out, compression=compression) + + def test_save_many_compressed(self, tmp_path): + im = hopper() + out = str(tmp_path / "temp.tif") + for _ in range(10000): + im.save(out, compression="jpeg") From 02afe1f13bb09df857c01cf820c511846a03df92 Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Sat, 4 Mar 2023 16:35:51 +1100 Subject: [PATCH 13/22] Removed unused profile_fromstring method --- src/_imagingcms.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/_imagingcms.c b/src/_imagingcms.c index 9b5a121d7..efb045667 100644 --- a/src/_imagingcms.c +++ b/src/_imagingcms.c @@ -116,7 +116,7 @@ cms_profile_open(PyObject *self, PyObject *args) { } static PyObject * -cms_profile_fromstring(PyObject *self, PyObject *args) { +cms_profile_frombytes(PyObject *self, PyObject *args) { cmsHPROFILE hProfile; char *pProfile; @@ -960,8 +960,7 @@ _is_intent_supported(CmsProfileObject *self, int clut) { static PyMethodDef pyCMSdll_methods[] = { {"profile_open", cms_profile_open, METH_VARARGS}, - {"profile_frombytes", cms_profile_fromstring, METH_VARARGS}, - {"profile_fromstring", cms_profile_fromstring, METH_VARARGS}, + {"profile_frombytes", cms_profile_frombytes, METH_VARARGS}, {"profile_tobytes", cms_profile_tobytes, METH_VARARGS}, /* profile and transform functions */ From 96e4e6160eadda1b2291aecb38263af4fb077491 Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Sat, 4 Mar 2023 21:00:18 +1100 Subject: [PATCH 14/22] Added release notes for #6961 and #6954 --- docs/reference/ImageDraw.rst | 2 +- docs/releasenotes/9.5.0.rst | 60 ++++++++++++++++++++++++++++++++++++ docs/releasenotes/index.rst | 1 + 3 files changed, 62 insertions(+), 1 deletion(-) create mode 100644 docs/releasenotes/9.5.0.rst diff --git a/docs/reference/ImageDraw.rst b/docs/reference/ImageDraw.rst index 9df4a5dad..9565ab149 100644 --- a/docs/reference/ImageDraw.rst +++ b/docs/reference/ImageDraw.rst @@ -338,7 +338,7 @@ Methods :param fill: Color to use for the fill. :param width: The line width, in pixels. :param corners: A tuple of whether to round each corner, - `(top_left, top_right, bottom_right, bottom_left)`. + ``(top_left, top_right, bottom_right, bottom_left)``. .. versionadded:: 8.2.0 diff --git a/docs/releasenotes/9.5.0.rst b/docs/releasenotes/9.5.0.rst new file mode 100644 index 000000000..c063d638e --- /dev/null +++ b/docs/releasenotes/9.5.0.rst @@ -0,0 +1,60 @@ +9.5.0 +----- + +Backwards Incompatible Changes +============================== + +TODO +^^^^ + +TODO + +Deprecations +============ + +TODO +^^^^ + +TODO + +API Changes +=========== + +TODO +^^^^ + +TODO + +API Additions +============= + +Added ``dpi`` argument when saving PDFs +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +When saving a PDF, resolution could already be specified using the +``resolution`` argument. Now, a tuple of ``(x_resolution, y_resolution)`` can +be provided as ``dpi``. If both are provided, ``dpi`` will override +``resolution``. + +Added ``corners`` argument to ``ImageDraw.rounded_rectangle()`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +:py:meth:`.ImageDraw.rounded_rectangle` now accepts a keyword argument of +``corners``. This a tuple of booleans, specifying whether to round each corner, +``(top_left, top_right, bottom_right, bottom_left)``. + +Security +======== + +TODO +^^^^ + +TODO + +Other Changes +============= + +TODO +^^^^ + +TODO diff --git a/docs/releasenotes/index.rst b/docs/releasenotes/index.rst index a2b588696..177fb65dd 100644 --- a/docs/releasenotes/index.rst +++ b/docs/releasenotes/index.rst @@ -14,6 +14,7 @@ expected to be backported to earlier versions. .. toctree:: :maxdepth: 2 + 9.5.0 9.4.0 9.3.0 9.2.0 From b9c772a889fc0018896d53bbae09830454447a35 Mon Sep 17 00:00:00 2001 From: Andrew Murray <3112309+radarhere@users.noreply.github.com> Date: Sat, 4 Mar 2023 22:08:36 +1100 Subject: [PATCH 15/22] Capitalised variable type Co-authored-by: Hugo van Kemenade --- docs/releasenotes/9.5.0.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/releasenotes/9.5.0.rst b/docs/releasenotes/9.5.0.rst index c063d638e..df2ec53fa 100644 --- a/docs/releasenotes/9.5.0.rst +++ b/docs/releasenotes/9.5.0.rst @@ -40,7 +40,7 @@ Added ``corners`` argument to ``ImageDraw.rounded_rectangle()`` ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ :py:meth:`.ImageDraw.rounded_rectangle` now accepts a keyword argument of -``corners``. This a tuple of booleans, specifying whether to round each corner, +``corners``. This a tuple of Booleans, specifying whether to round each corner, ``(top_left, top_right, bottom_right, bottom_left)``. Security From cb65bb672b66090b036c123565a783659c3edb44 Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade Date: Sat, 4 Mar 2023 15:44:56 +0200 Subject: [PATCH 16/22] Don't build docs in main tests or trigger main tests for docs-only --- .github/workflows/test-cygwin.yml | 11 ++++++++++- .github/workflows/test-docker.yml | 11 ++++++++++- .github/workflows/test-mingw.yml | 11 ++++++++++- .github/workflows/test-windows.yml | 11 ++++++++++- .github/workflows/test.yml | 16 ++++++++++------ 5 files changed, 50 insertions(+), 10 deletions(-) diff --git a/.github/workflows/test-cygwin.yml b/.github/workflows/test-cygwin.yml index 451181434..6c9ed66e3 100644 --- a/.github/workflows/test-cygwin.yml +++ b/.github/workflows/test-cygwin.yml @@ -1,6 +1,15 @@ name: Test Cygwin -on: [push, pull_request, workflow_dispatch] +on: + push: + paths-ignore: + - ".github/workflows/docs.yml" + - "docs/**" + pull_request: + paths-ignore: + - ".github/workflows/docs.yml" + - "docs/**" + workflow_dispatch: permissions: contents: read diff --git a/.github/workflows/test-docker.yml b/.github/workflows/test-docker.yml index 7d2b20d65..f7153386e 100644 --- a/.github/workflows/test-docker.yml +++ b/.github/workflows/test-docker.yml @@ -1,6 +1,15 @@ name: Test Docker -on: [push, pull_request, workflow_dispatch] +on: + push: + paths-ignore: + - ".github/workflows/docs.yml" + - "docs/**" + pull_request: + paths-ignore: + - ".github/workflows/docs.yml" + - "docs/**" + workflow_dispatch: permissions: contents: read diff --git a/.github/workflows/test-mingw.yml b/.github/workflows/test-mingw.yml index 737da7b94..ddfafc9d7 100644 --- a/.github/workflows/test-mingw.yml +++ b/.github/workflows/test-mingw.yml @@ -1,6 +1,15 @@ name: Test MinGW -on: [push, pull_request, workflow_dispatch] +on: + push: + paths-ignore: + - ".github/workflows/docs.yml" + - "docs/**" + pull_request: + paths-ignore: + - ".github/workflows/docs.yml" + - "docs/**" + workflow_dispatch: permissions: contents: read diff --git a/.github/workflows/test-windows.yml b/.github/workflows/test-windows.yml index 306e34ca9..833f096c3 100644 --- a/.github/workflows/test-windows.yml +++ b/.github/workflows/test-windows.yml @@ -1,6 +1,15 @@ name: Test Windows -on: [push, pull_request, workflow_dispatch] +on: + push: + paths-ignore: + - ".github/workflows/docs.yml" + - "docs/**" + pull_request: + paths-ignore: + - ".github/workflows/docs.yml" + - "docs/**" + workflow_dispatch: permissions: contents: read diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 33958bea8..10c3cd929 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -1,6 +1,15 @@ name: Test -on: [push, pull_request, workflow_dispatch] +on: + push: + paths-ignore: + - ".github/workflows/docs.yml" + - "docs/**" + pull_request: + paths-ignore: + - ".github/workflows/docs.yml" + - "docs/**" + workflow_dispatch: permissions: contents: read @@ -96,11 +105,6 @@ jobs: name: errors path: Tests/errors - - name: Docs - if: startsWith(matrix.os, 'ubuntu') && matrix.python-version == 3.11 - run: | - make doccheck - - name: After success run: | .ci/after_success.sh From 06cb3426efec840fd1e5bae1fd136bb77867cbc7 Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade Date: Sat, 4 Mar 2023 16:02:36 +0200 Subject: [PATCH 17/22] Build docs in own workflow --- .github/workflows/docs.yml | 50 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 .github/workflows/docs.yml diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml new file mode 100644 index 000000000..2ae14d468 --- /dev/null +++ b/.github/workflows/docs.yml @@ -0,0 +1,50 @@ +name: Docs + +on: + push: + paths: + - ".github/workflows/docs.yml" + - "docs/**" + pull_request: + paths: + - ".github/workflows/docs.yml" + - "docs/**" + workflow_dispatch: + +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + build: + + runs-on: ubuntu-latest + name: Docs + + steps: + - uses: actions/checkout@v3 + + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: "3.x" + cache: pip + cache-dependency-path: ".ci/*.sh" + + - name: Build system information + run: python3 .github/workflows/system-info.py + + - name: Install Linux dependencies + run: | + .ci/install.sh + + - name: Build + run: | + .ci/build.sh + + - name: Docs + run: | + make doccheck From 1497e9ef652fc1d9dfe529dc83a83d841d1c47de Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Sun, 5 Mar 2023 07:05:49 +1100 Subject: [PATCH 18/22] Run valgrind tests when GitHub Actions file changes --- .github/workflows/test-valgrind.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test-valgrind.yml b/.github/workflows/test-valgrind.yml index f8b050f76..6fab0ecd2 100644 --- a/.github/workflows/test-valgrind.yml +++ b/.github/workflows/test-valgrind.yml @@ -5,10 +5,12 @@ name: Test Valgrind on: push: paths: + - ".github/workflows/test-valgrind.yml" - "**.c" - "**.h" pull_request: paths: + - ".github/workflows/test-valgrind.yml" - "**.c" - "**.h" workflow_dispatch: @@ -16,7 +18,7 @@ on: permissions: contents: read -concurrency: +concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true From a7f836187dd3f3f7c220700966f1c4c58a07bcb9 Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Sun, 5 Mar 2023 21:51:46 +1100 Subject: [PATCH 19/22] Removed missing anchor from link --- docs/installation.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/installation.rst b/docs/installation.rst index 55d5ee832..f0aa0f399 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -186,8 +186,8 @@ Many of Pillow's features require external libraries: * Pillow wheels since version 8.2.0 include a modified version of libraqm that loads libfribidi at runtime if it is installed. On Windows this requires compiling FriBiDi and installing ``fribidi.dll`` - into a directory listed in the `Dynamic-Link Library Search Order (Microsoft Docs) - `_ + into a directory listed in the `Dynamic-link library search order (Microsoft Docs) + `_ (``fribidi-0.dll`` or ``libfribidi-0.dll`` are also detected). See `Build Options`_ to see how to build this version. * Previous versions of Pillow (5.0.0 to 8.1.2) linked libraqm dynamically at runtime. From 52cce5293d28394a375b8eb669acdb1cb31f58c0 Mon Sep 17 00:00:00 2001 From: nulano Date: Sun, 5 Mar 2023 19:14:41 +0000 Subject: [PATCH 20/22] restore link anchor --- docs/installation.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/installation.rst b/docs/installation.rst index f0aa0f399..98957335b 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -186,8 +186,8 @@ Many of Pillow's features require external libraries: * Pillow wheels since version 8.2.0 include a modified version of libraqm that loads libfribidi at runtime if it is installed. On Windows this requires compiling FriBiDi and installing ``fribidi.dll`` - into a directory listed in the `Dynamic-link library search order (Microsoft Docs) - `_ + into a directory listed in the `Dynamic-link library search order (Microsoft Learn) + `_ (``fribidi-0.dll`` or ``libfribidi-0.dll`` are also detected). See `Build Options`_ to see how to build this version. * Previous versions of Pillow (5.0.0 to 8.1.2) linked libraqm dynamically at runtime. From 29b6db4f8a271b0c90d2bf129b40f2f3ca65185d Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade Date: Mon, 6 Mar 2023 10:26:30 +0200 Subject: [PATCH 21/22] Add GHA_PYTHON_VERSION Co-authored-by: Andrew Murray <3112309+radarhere@users.noreply.github.com> --- .github/workflows/docs.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 2ae14d468..8a3265476 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -40,6 +40,8 @@ jobs: - name: Install Linux dependencies run: | .ci/install.sh + env: + GHA_PYTHON_VERSION: "3.x" - name: Build run: | From d93d0a3772cd8255b1b32dd9d71eefe5bac634c1 Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Mon, 6 Mar 2023 10:02:55 +1100 Subject: [PATCH 22/22] Run CIFuzz tests when GitHub Actions file changes --- .github/workflows/cifuzz.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/cifuzz.yml b/.github/workflows/cifuzz.yml index db0307046..560d6c7df 100644 --- a/.github/workflows/cifuzz.yml +++ b/.github/workflows/cifuzz.yml @@ -3,10 +3,12 @@ name: CIFuzz on: push: paths: + - ".github/workflows/cifuzz.yml" - "**.c" - "**.h" pull_request: paths: + - ".github/workflows/cifuzz.yml" - "**.c" - "**.h" workflow_dispatch: @@ -14,7 +16,7 @@ on: permissions: contents: read -concurrency: +concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true