Repository: python-pillow/Pillow

Issue:
Incorrect documentation for ImagePalette size parameter (and maybe not needed at all)
The documentation for the `ImagePalette` initializer in version 8.3.1 says the `palette` parameter must be "of length `size` times the number of colors in `mode`". Therefore, for an RGB image, I would expect `len(palette) == size * 3`. However, the code asserts that `len(palette) == size`, so I believe the code and documentation are inconsistent. (The same problem existed in 8.2.0 before some ImagePalette improvements were made, so this wasn't introduced with that change.)

Furthermore, it isn't clear to me that the `size` parameter is needed at all. It isn't stored on `self`, and the only place it's used in the initializer is to assert that its value is `0` or `len(palette)`, so it doesn't seem to provide any benefit. The only reason to keep it that I can think of is to maintain backwards compatibility with existing code that explicitly passes the parameter.


Discussion:
The incorrect documentation was added in #1381. I've created #5638 to fix it.

As background, the `size` parameter was originally added in #537. Before #5552, it was there to override a default length check. Afterwards though, the default length check was gone, so `size` is now just adding an arbitrary constraint on the user.

While I acknowledge that 8.2.0 changed ImagePalette significantly, this is removing an API parameter. If it is to be removed, deprecation is preferred first.

As an aside, you would probably appreciate knowing that there is another PR in the pipeline to update the documentation for the channel order used by the `palette` argument - #5599
Thank you @radarhere for the background and addressing this so quickly. The changes you made in #5638 sound great to me. I came across #5599 when searching for prior discussion of this issue, so I was already familiar with that upcoming change (which is also appreciated).
#5638 has been merged, and I've created PR #5641 to deprecate the size parameter, resolving this.

Resolving patch:
diff --git a/src/PIL/ImagePalette.py b/src/PIL/ImagePalette.py
--- a/src/PIL/ImagePalette.py
+++ b/src/PIL/ImagePalette.py
@@ -17,6 +17,7 @@
 #
 
 import array
+import warnings
 
 from . import GimpGradientFile, GimpPaletteFile, ImageColor, PaletteFile
 
@@ -40,8 +41,14 @@ def __init__(self, mode="RGB", palette=None, size=0):
         self.rawmode = None  # if set, palette contains raw data
         self.palette = palette or bytearray()
         self.dirty = None
-        if size != 0 and size != len(self.palette):
-            raise ValueError("wrong palette size")
+        if size != 0:
+            warnings.warn(
+                "The size parameter is deprecated and will be removed in Pillow 10 "
+                "(2023-01-02).",
+                DeprecationWarning,
+            )
+            if size != len(self.palette):
+                raise ValueError("wrong palette size")
 
     @property
     def palette(self):


Test patch:
diff --git a/Tests/test_imagepalette.py b/Tests/test_imagepalette.py
--- a/Tests/test_imagepalette.py
+++ b/Tests/test_imagepalette.py
@@ -10,8 +10,9 @@ def test_sanity():
     palette = ImagePalette.ImagePalette("RGB", list(range(256)) * 3)
     assert len(palette.colors) == 256
 
-    with pytest.raises(ValueError):
-        ImagePalette.ImagePalette("RGB", list(range(256)) * 3, 10)
+    with pytest.warns(DeprecationWarning):
+        with pytest.raises(ValueError):
+            ImagePalette.ImagePalette("RGB", list(range(256)) * 3, 10)
 
 
 def test_reload():