From f2872fa9e8e727b53cc987f88311a02b82e0f996 Mon Sep 17 00:00:00 2001 From: LuShadowX Date: Sat, 25 Jul 2026 23:10:02 +0530 Subject: [PATCH 1/4] Raise ValueError instead of asserting colorize() arguments --- Tests/test_imageops.py | 26 ++++++++++++++++++++++++++ src/PIL/ImageOps.py | 18 ++++++++++++------ 2 files changed, 38 insertions(+), 6 deletions(-) diff --git a/Tests/test_imageops.py b/Tests/test_imageops.py index a1dc65e6f11..46fa4772c11 100644 --- a/Tests/test_imageops.py +++ b/Tests/test_imageops.py @@ -423,6 +423,32 @@ def test_colorize_3color_offset() -> None: ) +def test_colorize_invalid_mode() -> None: + with pytest.raises(ValueError, match="mode must be L, not RGB"): + ImageOps.colorize(hopper("RGB"), "black", "white") + + +@pytest.mark.parametrize(("blackpoint", "whitepoint"), ((-1, 255), (0, 256), (200, 50))) +def test_colorize_invalid_points(blackpoint: int, whitepoint: int) -> None: + with pytest.raises(ValueError, match="blackpoint and whitepoint must satisfy"): + ImageOps.colorize( + hopper("L"), "black", "white", blackpoint=blackpoint, whitepoint=whitepoint + ) + + +def test_colorize_invalid_midpoint() -> None: + with pytest.raises(ValueError, match="midpoint must satisfy"): + ImageOps.colorize( + hopper("L"), + "black", + "white", + mid="blue", + blackpoint=0, + midpoint=200, + whitepoint=100, + ) + + def test_exif_transpose() -> None: exts = [".jpg"] if features.check("webp"): diff --git a/src/PIL/ImageOps.py b/src/PIL/ImageOps.py index b98bd79b816..c909a5ad5d7 100644 --- a/src/PIL/ImageOps.py +++ b/src/PIL/ImageOps.py @@ -200,12 +200,18 @@ def colorize( :return: An image. """ - # Initial asserts - assert image.mode == "L" - if mid is None: - assert 0 <= blackpoint <= whitepoint <= 255 - else: - assert 0 <= blackpoint <= midpoint <= whitepoint <= 255 + if image.mode != "L": + msg = f"mode must be L, not {image.mode}" + raise ValueError(msg) + if not 0 <= blackpoint <= whitepoint <= 255: + msg = ( + "blackpoint and whitepoint must satisfy" + " 0 <= blackpoint <= whitepoint <= 255" + ) + raise ValueError(msg) + if mid is not None and not blackpoint <= midpoint <= whitepoint: + msg = "midpoint must satisfy blackpoint <= midpoint <= whitepoint" + raise ValueError(msg) # Define colors from arguments rgb_black = cast(Sequence[int], _color(black, "RGB")) From 4a06ff675e283cb2ee59be530024bef6afc149d9 Mon Sep 17 00:00:00 2001 From: LuShadowX Date: Sun, 26 Jul 2026 09:07:20 +0530 Subject: [PATCH 2/4] Use a comma-separated string for parametrize names Co-authored-by: Andrew Murray <3112309+radarhere@users.noreply.github.com> --- Tests/test_imageops.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/test_imageops.py b/Tests/test_imageops.py index 46fa4772c11..fb0da7e6141 100644 --- a/Tests/test_imageops.py +++ b/Tests/test_imageops.py @@ -428,7 +428,7 @@ def test_colorize_invalid_mode() -> None: ImageOps.colorize(hopper("RGB"), "black", "white") -@pytest.mark.parametrize(("blackpoint", "whitepoint"), ((-1, 255), (0, 256), (200, 50))) +@pytest.mark.parametrize("blackpoint, whitepoint", ((-1, 255), (0, 256), (200, 50))) def test_colorize_invalid_points(blackpoint: int, whitepoint: int) -> None: with pytest.raises(ValueError, match="blackpoint and whitepoint must satisfy"): ImageOps.colorize( From cfb29c144ef7bb090897d0ae70b42b3c43d800d8 Mon Sep 17 00:00:00 2001 From: LuShadowX Date: Sun, 26 Jul 2026 23:51:01 +0530 Subject: [PATCH 3/4] Use natural wording in the error messages, and test midpoint on both sides Co-authored-by: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com> Co-authored-by: Andrew Murray <3112309+radarhere@users.noreply.github.com> --- Tests/test_imageops.py | 13 +++++++------ src/PIL/ImageOps.py | 6 +++--- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/Tests/test_imageops.py b/Tests/test_imageops.py index fb0da7e6141..b996afc55e8 100644 --- a/Tests/test_imageops.py +++ b/Tests/test_imageops.py @@ -430,22 +430,23 @@ def test_colorize_invalid_mode() -> None: @pytest.mark.parametrize("blackpoint, whitepoint", ((-1, 255), (0, 256), (200, 50))) def test_colorize_invalid_points(blackpoint: int, whitepoint: int) -> None: - with pytest.raises(ValueError, match="blackpoint and whitepoint must satisfy"): + with pytest.raises(ValueError, match="blackpoint and whitepoint must each be"): ImageOps.colorize( hopper("L"), "black", "white", blackpoint=blackpoint, whitepoint=whitepoint ) -def test_colorize_invalid_midpoint() -> None: - with pytest.raises(ValueError, match="midpoint must satisfy"): +@pytest.mark.parametrize("midpoint", (100, 200)) +def test_colorize_invalid_midpoint(midpoint: int) -> None: + with pytest.raises(ValueError, match="midpoint must be between"): ImageOps.colorize( hopper("L"), "black", "white", mid="blue", - blackpoint=0, - midpoint=200, - whitepoint=100, + blackpoint=125, + midpoint=midpoint, + whitepoint=175, ) diff --git a/src/PIL/ImageOps.py b/src/PIL/ImageOps.py index c909a5ad5d7..d7a34963cf5 100644 --- a/src/PIL/ImageOps.py +++ b/src/PIL/ImageOps.py @@ -205,12 +205,12 @@ def colorize( raise ValueError(msg) if not 0 <= blackpoint <= whitepoint <= 255: msg = ( - "blackpoint and whitepoint must satisfy" - " 0 <= blackpoint <= whitepoint <= 255" + "blackpoint and whitepoint must each be between 0 and 255, " + "with blackpoint less than or equal to whitepoint" ) raise ValueError(msg) if mid is not None and not blackpoint <= midpoint <= whitepoint: - msg = "midpoint must satisfy blackpoint <= midpoint <= whitepoint" + msg = "midpoint must be between blackpoint and whitepoint" raise ValueError(msg) # Define colors from arguments From 518f41f47f39a5d38ef10a3e3238b127165f0136 Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Mon, 27 Jul 2026 12:16:17 +1000 Subject: [PATCH 4/4] Add "or equal to" --- Tests/test_imageops.py | 2 +- src/PIL/ImageOps.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Tests/test_imageops.py b/Tests/test_imageops.py index b996afc55e8..f2519a284cf 100644 --- a/Tests/test_imageops.py +++ b/Tests/test_imageops.py @@ -438,7 +438,7 @@ def test_colorize_invalid_points(blackpoint: int, whitepoint: int) -> None: @pytest.mark.parametrize("midpoint", (100, 200)) def test_colorize_invalid_midpoint(midpoint: int) -> None: - with pytest.raises(ValueError, match="midpoint must be between"): + with pytest.raises(ValueError, match="midpoint must be between or equal to"): ImageOps.colorize( hopper("L"), "black", diff --git a/src/PIL/ImageOps.py b/src/PIL/ImageOps.py index d7a34963cf5..cdec4d5dc7d 100644 --- a/src/PIL/ImageOps.py +++ b/src/PIL/ImageOps.py @@ -205,12 +205,12 @@ def colorize( raise ValueError(msg) if not 0 <= blackpoint <= whitepoint <= 255: msg = ( - "blackpoint and whitepoint must each be between 0 and 255, " + "blackpoint and whitepoint must each be between or equal to 0 and 255, " "with blackpoint less than or equal to whitepoint" ) raise ValueError(msg) if mid is not None and not blackpoint <= midpoint <= whitepoint: - msg = "midpoint must be between blackpoint and whitepoint" + msg = "midpoint must be between or equal to blackpoint and whitepoint" raise ValueError(msg) # Define colors from arguments