From 4d6477af44330b56436c9656578e181da6ad6198 Mon Sep 17 00:00:00 2001 From: Yay295 Date: Wed, 17 Apr 2024 12:55:24 -0500 Subject: [PATCH 1/9] move getdata/putdata tests to same file --- Tests/test_image.py | 10 --- Tests/test_image_getdata.py | 30 --------- ...tdata.py => test_image_getdata_putdata.py} | 61 +++++++++++++++---- 3 files changed, 50 insertions(+), 51 deletions(-) delete mode 100644 Tests/test_image_getdata.py rename Tests/{test_image_putdata.py => test_image_getdata_putdata.py} (60%) diff --git a/Tests/test_image.py b/Tests/test_image.py index 9b65041f4b4..8b60eacec1f 100644 --- a/Tests/test_image.py +++ b/Tests/test_image.py @@ -30,7 +30,6 @@ assert_image_similar_tofile, assert_not_all_same, hopper, - is_big_endian, is_win32, mark_if_feature_version, skip_unless_feature, @@ -1139,15 +1138,6 @@ def test_roundtrip_bytes_method(self, mode: str) -> None: reloaded.frombytes(source_bytes) assert reloaded.tobytes() == source_bytes - @pytest.mark.parametrize("mode", Image.MODES + ["BGR;15", "BGR;16", "BGR;24"]) - def test_getdata_putdata(self, mode: str) -> None: - if is_big_endian() and mode == "BGR;15": - pytest.xfail("Known failure of BGR;15 on big-endian") - im = hopper(mode) - reloaded = helper_image_new(mode, im.size) - reloaded.putdata(im.getdata()) - assert_image_equal(im, reloaded) - class MockEncoder(ImageFile.PyEncoder): pass diff --git a/Tests/test_image_getdata.py b/Tests/test_image_getdata.py deleted file mode 100644 index dd3d70b3450..00000000000 --- a/Tests/test_image_getdata.py +++ /dev/null @@ -1,30 +0,0 @@ -from __future__ import annotations - -from PIL import Image - -from .helper import hopper - - -def test_sanity() -> None: - data = hopper().getdata() - - len(data) - list(data) - - assert data[0] == (20, 20, 70) - - -def test_mode() -> None: - def getdata(mode: str) -> tuple[float | tuple[int, ...], int, int]: - im = hopper(mode).resize((32, 30), Image.Resampling.NEAREST) - data = im.getdata() - return data[0], len(data), len(list(data)) - - assert getdata("1") == (0, 960, 960) - assert getdata("L") == (17, 960, 960) - assert getdata("I") == (17, 960, 960) - assert getdata("F") == (17.0, 960, 960) - assert getdata("RGB") == ((11, 13, 52), 960, 960) - assert getdata("RGBA") == ((11, 13, 52, 255), 960, 960) - assert getdata("CMYK") == ((244, 242, 203, 0), 960, 960) - assert getdata("YCbCr") == ((16, 147, 123), 960, 960) diff --git a/Tests/test_image_putdata.py b/Tests/test_image_getdata_putdata.py similarity index 60% rename from Tests/test_image_putdata.py rename to Tests/test_image_getdata_putdata.py index 27cb7c59d89..f863827aecd 100644 --- a/Tests/test_image_putdata.py +++ b/Tests/test_image_getdata_putdata.py @@ -7,10 +7,19 @@ from PIL import Image -from .helper import assert_image_equal, hopper +from .helper import assert_image_equal, hopper, is_big_endian -def test_sanity() -> None: +def test_getdata_sanity() -> None: + data = hopper().getdata() + + len(data) + list(data) + + assert data[0] == (20, 20, 70) + + +def test_putdata_sanity() -> None: im1 = hopper() data = list(im1.getdata()) @@ -29,7 +38,23 @@ def test_sanity() -> None: assert_image_equal(im1, im2) -def test_long_integers() -> None: +def test_getdata_roundtrip() -> None: + def getdata(mode: str) -> tuple[float | tuple[int, ...], int, int]: + im = hopper(mode).resize((32, 30), Image.Resampling.NEAREST) + data = im.getdata() + return data[0], len(data), len(list(data)) + + assert getdata("1") == (0, 960, 960) + assert getdata("L") == (17, 960, 960) + assert getdata("I") == (17, 960, 960) + assert getdata("F") == (17.0, 960, 960) + assert getdata("RGB") == ((11, 13, 52), 960, 960) + assert getdata("RGBA") == ((11, 13, 52, 255), 960, 960) + assert getdata("CMYK") == ((244, 242, 203, 0), 960, 960) + assert getdata("YCbCr") == ((16, 147, 123), 960, 960) + + +def test_putdata_long_integers() -> None: # see bug-200802-systemerror def put(value: int) -> float | tuple[int, ...] | None: im = Image.new("RGBA", (1, 1)) @@ -46,19 +71,19 @@ def put(value: int) -> float | tuple[int, ...] | None: assert put(sys.maxsize) == (255, 255, 255, 127) -def test_pypy_performance() -> None: +def test_putdata_pypy_performance() -> None: im = Image.new("L", (256, 256)) im.putdata(list(range(256)) * 256) -def test_mode_with_L_with_float() -> None: +def test_putdata_mode_with_L_with_float() -> None: im = Image.new("L", (1, 1), 0) im.putdata([2.0]) assert im.getpixel((0, 0)) == 2 @pytest.mark.parametrize("mode", ("I", "I;16", "I;16L", "I;16B")) -def test_mode_i(mode: str) -> None: +def test_putdata_mode_I(mode: str) -> None: src = hopper("L") data = list(src.getdata()) im = Image.new(mode, src.size, 0) @@ -68,7 +93,7 @@ def test_mode_i(mode: str) -> None: assert list(im.getdata()) == target -def test_mode_F() -> None: +def test_putdata_mode_F() -> None: src = hopper("L") data = list(src.getdata()) im = Image.new("F", src.size, 0) @@ -79,7 +104,7 @@ def test_mode_F() -> None: @pytest.mark.parametrize("mode", ("BGR;15", "BGR;16", "BGR;24")) -def test_mode_BGR(mode: str) -> None: +def test_putdata_mode_BGR(mode: str) -> None: data = [(16, 32, 49), (32, 32, 98)] with pytest.warns(DeprecationWarning): im = Image.new(mode, (1, 2)) @@ -88,7 +113,7 @@ def test_mode_BGR(mode: str) -> None: assert list(im.getdata()) == data -def test_array_B() -> None: +def test_putdata_array_B() -> None: # shouldn't segfault # see https://github.com/python-pillow/Pillow/issues/1008 @@ -99,7 +124,7 @@ def test_array_B() -> None: assert len(im.getdata()) == len(arr) -def test_array_F() -> None: +def test_putdata_array_F() -> None: # shouldn't segfault # see https://github.com/python-pillow/Pillow/issues/1008 @@ -110,7 +135,7 @@ def test_array_F() -> None: assert len(im.getdata()) == len(arr) -def test_not_flattened() -> None: +def test_putdata_not_flattened() -> None: im = Image.new("L", (1, 1)) with pytest.raises(TypeError): im.putdata([[0]]) @@ -123,3 +148,17 @@ def test_not_flattened() -> None: with pytest.raises(TypeError): im = Image.new("F", (1, 1)) im.putdata([[0]]) + + +@pytest.mark.parametrize("mode", Image.MODES + ["BGR;15", "BGR;16", "BGR;24"]) +def test_getdata_putdata(mode: str) -> None: + if is_big_endian() and mode == "BGR;15": + pytest.xfail("Known failure of BGR;15 on big-endian") + im = hopper(mode) + if mode.startswith("BGR;"): + with pytest.warns(DeprecationWarning): + reloaded = Image.new(mode, im.size) + else: + reloaded = Image.new(mode, im.size) + reloaded.putdata(im.getdata()) + assert_image_equal(im, reloaded) From 83270f780d8e0dcf222d370e9bb93224b4b8ec19 Mon Sep 17 00:00:00 2001 From: Yay295 Date: Wed, 17 Apr 2024 13:12:00 -0500 Subject: [PATCH 2/9] parametrize test_getdata_roundtrip() --- Tests/test_image_getdata_putdata.py | 35 +++++++++++++++++------------ 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/Tests/test_image_getdata_putdata.py b/Tests/test_image_getdata_putdata.py index f863827aecd..5ff8778867f 100644 --- a/Tests/test_image_getdata_putdata.py +++ b/Tests/test_image_getdata_putdata.py @@ -38,20 +38,27 @@ def test_putdata_sanity() -> None: assert_image_equal(im1, im2) -def test_getdata_roundtrip() -> None: - def getdata(mode: str) -> tuple[float | tuple[int, ...], int, int]: - im = hopper(mode).resize((32, 30), Image.Resampling.NEAREST) - data = im.getdata() - return data[0], len(data), len(list(data)) - - assert getdata("1") == (0, 960, 960) - assert getdata("L") == (17, 960, 960) - assert getdata("I") == (17, 960, 960) - assert getdata("F") == (17.0, 960, 960) - assert getdata("RGB") == ((11, 13, 52), 960, 960) - assert getdata("RGBA") == ((11, 13, 52, 255), 960, 960) - assert getdata("CMYK") == ((244, 242, 203, 0), 960, 960) - assert getdata("YCbCr") == ((16, 147, 123), 960, 960) +@pytest.mark.parametrize( + "mode, first_pixel, data_size", + ( + ("1", 0, 960), + ("L", 17, 960), + ("I", 17, 960), + ("F", 17.0, 960), + ("RGB", (11, 13, 52), 960), + ("RGBA", (11, 13, 52, 255), 960), + ("CMYK", (244, 242, 203, 0), 960), + ("YCbCr", (16, 147, 123), 960), + ), +) +def test_getdata_roundtrip( + mode: str, first_pixel: float | tuple[int, ...], data_size: int +) -> None: + im = hopper(mode).resize((32, 30), Image.Resampling.NEAREST) + data = im.getdata() + assert data[0] == first_pixel + assert len(data) == data_size + assert len(list(data)) == data_size def test_putdata_long_integers() -> None: From 2f56b8e0e63571d245e6cc41db1530811500c3b3 Mon Sep 17 00:00:00 2001 From: Yay295 Date: Wed, 17 Apr 2024 13:21:18 -0500 Subject: [PATCH 3/9] parametrize test_putdata_long_integers() This test had some duplicate checks because originally in Python 2 the numbers in those lines had a "L" suffix, which is no longer used in Python 3. --- Tests/test_image_getdata_putdata.py | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/Tests/test_image_getdata_putdata.py b/Tests/test_image_getdata_putdata.py index 5ff8778867f..d073769a570 100644 --- a/Tests/test_image_getdata_putdata.py +++ b/Tests/test_image_getdata_putdata.py @@ -61,21 +61,20 @@ def test_getdata_roundtrip( assert len(list(data)) == data_size -def test_putdata_long_integers() -> None: +@pytest.mark.parametrize( + "value, pixel", + ( + (0xFFFFFFFF, (255, 255, 255, 255)), + (-1, (255, 255, 255, 255)), + (sys.maxsize, (255, 255, 255, 255 if sys.maxsize > 2**32 else 127)), + ), +) +def test_putdata_long_integers(value: int, pixel: tuple[int, int, int, int]) -> None: # see bug-200802-systemerror - def put(value: int) -> float | tuple[int, ...] | None: - im = Image.new("RGBA", (1, 1)) - im.putdata([value]) - return im.getpixel((0, 0)) - - assert put(0xFFFFFFFF) == (255, 255, 255, 255) - assert put(0xFFFFFFFF) == (255, 255, 255, 255) - assert put(-1) == (255, 255, 255, 255) - assert put(-1) == (255, 255, 255, 255) - if sys.maxsize > 2**32: - assert put(sys.maxsize) == (255, 255, 255, 255) - else: - assert put(sys.maxsize) == (255, 255, 255, 127) + + im = Image.new("RGBA", (1, 1)) + im.putdata([value]) + assert im.getpixel((0, 0)) == pixel def test_putdata_pypy_performance() -> None: From bdbd689a94f4a48f95ebd5f047df70031f7746c5 Mon Sep 17 00:00:00 2001 From: Yay295 Date: Wed, 17 Apr 2024 16:20:16 -0500 Subject: [PATCH 4/9] remove old comment The original bug this was referring to seems to have been lost, but it looks to have been something to do with Python 2/3 compatibility and big numbers. See commit c8ce29c23903b5145ed0e1a23804e7e99faa5eb8 and https://github.com/python-pillow/Pillow/issues/7991. --- Tests/test_image_getdata_putdata.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/Tests/test_image_getdata_putdata.py b/Tests/test_image_getdata_putdata.py index d073769a570..06116df1b30 100644 --- a/Tests/test_image_getdata_putdata.py +++ b/Tests/test_image_getdata_putdata.py @@ -70,8 +70,6 @@ def test_getdata_roundtrip( ), ) def test_putdata_long_integers(value: int, pixel: tuple[int, int, int, int]) -> None: - # see bug-200802-systemerror - im = Image.new("RGBA", (1, 1)) im.putdata([value]) assert im.getpixel((0, 0)) == pixel From 291eb2b556f56ca0c46d7f7f0035c77431844215 Mon Sep 17 00:00:00 2001 From: Yay295 Date: Thu, 25 Apr 2024 16:56:55 -0500 Subject: [PATCH 5/9] rename variable "pixel" to "expected" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Ondrej Baranovič --- Tests/test_image_getdata_putdata.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Tests/test_image_getdata_putdata.py b/Tests/test_image_getdata_putdata.py index 06116df1b30..b45062720fc 100644 --- a/Tests/test_image_getdata_putdata.py +++ b/Tests/test_image_getdata_putdata.py @@ -62,17 +62,17 @@ def test_getdata_roundtrip( @pytest.mark.parametrize( - "value, pixel", + "value, expected", ( (0xFFFFFFFF, (255, 255, 255, 255)), (-1, (255, 255, 255, 255)), (sys.maxsize, (255, 255, 255, 255 if sys.maxsize > 2**32 else 127)), ), ) -def test_putdata_long_integers(value: int, pixel: tuple[int, int, int, int]) -> None: +def test_putdata_long_integers(value: int, expected: tuple[int, int, int, int]) -> None: im = Image.new("RGBA", (1, 1)) im.putdata([value]) - assert im.getpixel((0, 0)) == pixel + assert im.getpixel((0, 0)) == expected def test_putdata_pypy_performance() -> None: From f3b5659f3f23c889cb9470f4e7bc37390769e447 Mon Sep 17 00:00:00 2001 From: Yay295 Date: Sat, 27 Apr 2024 22:41:16 -0500 Subject: [PATCH 6/9] rename test_image_getdata_putdata.py to test_image_data.py --- Tests/{test_image_getdata_putdata.py => test_image_data.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename Tests/{test_image_getdata_putdata.py => test_image_data.py} (100%) diff --git a/Tests/test_image_getdata_putdata.py b/Tests/test_image_data.py similarity index 100% rename from Tests/test_image_getdata_putdata.py rename to Tests/test_image_data.py From 561505eb96c8c744c88d8d1b370bffeb356cdcf1 Mon Sep 17 00:00:00 2001 From: Yay295 Date: Sun, 28 Apr 2024 00:16:32 -0500 Subject: [PATCH 7/9] parametrize test_putdata_array() --- Tests/test_image_data.py | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/Tests/test_image_data.py b/Tests/test_image_data.py index b45062720fc..6f935b6d40c 100644 --- a/Tests/test_image_data.py +++ b/Tests/test_image_data.py @@ -117,23 +117,19 @@ def test_putdata_mode_BGR(mode: str) -> None: assert list(im.getdata()) == data -def test_putdata_array_B() -> None: - # shouldn't segfault - # see https://github.com/python-pillow/Pillow/issues/1008 - - arr = array("B", [0]) * 15000 - im = Image.new("L", (150, 100)) - im.putdata(arr) - - assert len(im.getdata()) == len(arr) - - -def test_putdata_array_F() -> None: +@pytest.mark.parametrize( + "mode, type, value", + ( + ("L", "B", 0), # B = unsigned char + ("F", "f", 0.0), # f = float + ), +) +def test_putdata_array(mode: str, type: str, value: float) -> None: # shouldn't segfault # see https://github.com/python-pillow/Pillow/issues/1008 - im = Image.new("F", (150, 100)) - arr = array("f", [0.0]) * 15000 + im = Image.new(mode, (150, 100)) + arr = array(type, [value]) * 15000 im.putdata(arr) assert len(im.getdata()) == len(arr) From 2bddc204f8720f256f2e89d1ae7047e1d6ede4aa Mon Sep 17 00:00:00 2001 From: Yay295 Date: Sun, 28 Apr 2024 00:25:32 -0500 Subject: [PATCH 8/9] merge test_putdata_mode_I() and test_putdata_mode_F() as test_putdata_scale_and_offset() --- Tests/test_image_data.py | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/Tests/test_image_data.py b/Tests/test_image_data.py index 6f935b6d40c..94edbe532f4 100644 --- a/Tests/test_image_data.py +++ b/Tests/test_image_data.py @@ -86,24 +86,23 @@ def test_putdata_mode_with_L_with_float() -> None: assert im.getpixel((0, 0)) == 2 -@pytest.mark.parametrize("mode", ("I", "I;16", "I;16L", "I;16B")) -def test_putdata_mode_I(mode: str) -> None: +@pytest.mark.parametrize( + "mode, scale, offset", + ( + ("I", 2, 256), + ("I;16", 2, 256), + ("I;16L", 2, 256), + ("I;16B", 2, 256), + ("F", 2.0, 256.0), + ), +) +def test_putdata_scale_and_offset(mode: str, scale: float, offset: float) -> None: src = hopper("L") data = list(src.getdata()) im = Image.new(mode, src.size, 0) - im.putdata(data, 2, 256) - - target = [2 * elt + 256 for elt in data] - assert list(im.getdata()) == target - - -def test_putdata_mode_F() -> None: - src = hopper("L") - data = list(src.getdata()) - im = Image.new("F", src.size, 0) - im.putdata(data, 2.0, 256.0) + im.putdata(data, scale, offset) - target = [2.0 * float(elt) + 256.0 for elt in data] + target = [scale * val + offset for val in data] assert list(im.getdata()) == target From c0e1c7c3299df67bcfe30db2a3ae8682fb95338c Mon Sep 17 00:00:00 2001 From: Yay295 Date: Sun, 28 Apr 2024 00:32:07 -0500 Subject: [PATCH 9/9] remove test_putdata_mode_BGR(), superseded by test_getdata_putdata() --- Tests/test_image_data.py | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/Tests/test_image_data.py b/Tests/test_image_data.py index 94edbe532f4..5379355e952 100644 --- a/Tests/test_image_data.py +++ b/Tests/test_image_data.py @@ -106,16 +106,6 @@ def test_putdata_scale_and_offset(mode: str, scale: float, offset: float) -> Non assert list(im.getdata()) == target -@pytest.mark.parametrize("mode", ("BGR;15", "BGR;16", "BGR;24")) -def test_putdata_mode_BGR(mode: str) -> None: - data = [(16, 32, 49), (32, 32, 98)] - with pytest.warns(DeprecationWarning): - im = Image.new(mode, (1, 2)) - im.putdata(data) - - assert list(im.getdata()) == data - - @pytest.mark.parametrize( "mode, type, value", (