{
    "file_diffs": [
        {
            "old_file_content": "import pytest\n\nfrom PIL import Image, ImagePalette\n\nfrom .helper import assert_image_equal, assert_image_equal_tofile\n\n\ndef test_sanity():\n\n    palette = ImagePalette.ImagePalette(\"RGB\", list(range(256)) * 3)\n    assert len(palette.colors) == 256\n\n    with pytest.raises(ValueError):\n        ImagePalette.ImagePalette(\"RGB\", list(range(256)) * 3, 10)\n\n\ndef test_reload():\n    im = Image.open(\"Tests/images/hopper.gif\")\n    original = im.copy()\n    im.palette.dirty = 1\n    assert_image_equal(im.convert(\"RGB\"), original.convert(\"RGB\"))\n\n\ndef test_getcolor():\n\n    palette = ImagePalette.ImagePalette()\n    assert len(palette.palette) == 0\n    assert len(palette.colors) == 0\n\n    test_map = {}\n    for i in range(256):\n        test_map[palette.getcolor((i, i, i))] = i\n    assert len(test_map) == 256\n\n    # Colors can be converted between RGB and RGBA\n    rgba_palette = ImagePalette.ImagePalette(\"RGBA\")\n    assert rgba_palette.getcolor((0, 0, 0)) == rgba_palette.getcolor((0, 0, 0, 255))\n\n    assert palette.getcolor((0, 0, 0)) == palette.getcolor((0, 0, 0, 255))\n\n    # An error is raised when the palette is full\n    with pytest.raises(ValueError):\n        palette.getcolor((1, 2, 3))\n    # But not if the image is not using one of the palette entries\n    palette.getcolor((1, 2, 3), image=Image.new(\"P\", (1, 1)))\n\n    # Test unknown color specifier\n    with pytest.raises(ValueError):\n        palette.getcolor(\"unknown\")\n\n\n@pytest.mark.parametrize(\n    \"index, palette\",\n    [\n        # Test when the palette is not full\n        (0, ImagePalette.ImagePalette()),\n        # Test when the palette is full\n        (255, ImagePalette.ImagePalette(\"RGB\", list(range(256)) * 3)),\n    ],\n)\ndef test_getcolor_not_special(index, palette):\n    im = Image.new(\"P\", (1, 1))\n\n    # Do not use transparency index as a new color\n    im.info[\"transparency\"] = index\n    index1 = palette.getcolor((0, 0, 0), im)\n    assert index1 != index\n\n    # Do not use background index as a new color\n    im.info[\"background\"] = index1\n    index2 = palette.getcolor((0, 0, 1), im)\n    assert index2 not in (index, index1)\n\n\ndef test_file(tmp_path):\n\n    palette = ImagePalette.ImagePalette(\"RGB\", list(range(256)) * 3)\n\n    f = str(tmp_path / \"temp.lut\")\n\n    palette.save(f)\n\n    p = ImagePalette.load(f)\n\n    # load returns raw palette information\n    assert len(p[0]) == 768\n    assert p[1] == \"RGB\"\n\n    p = ImagePalette.raw(p[1], p[0])\n    assert isinstance(p, ImagePalette.ImagePalette)\n    assert p.palette == palette.tobytes()\n\n\ndef test_make_linear_lut():\n    # Arrange\n    black = 0\n    white = 255\n\n    # Act\n    lut = ImagePalette.make_linear_lut(black, white)\n\n    # Assert\n    assert isinstance(lut, list)\n    assert len(lut) == 256\n    # Check values\n    for i in range(0, len(lut)):\n        assert lut[i] == i\n\n\ndef test_make_linear_lut_not_yet_implemented():\n    # Update after FIXME\n    # Arrange\n    black = 1\n    white = 255\n\n    # Act\n    with pytest.raises(NotImplementedError):\n        ImagePalette.make_linear_lut(black, white)\n\n\ndef test_make_gamma_lut():\n    # Arrange\n    exp = 5\n\n    # Act\n    lut = ImagePalette.make_gamma_lut(exp)\n\n    # Assert\n    assert isinstance(lut, list)\n    assert len(lut) == 256\n    # Check a few values\n    assert lut[0] == 0\n    assert lut[63] == 0\n    assert lut[127] == 8\n    assert lut[191] == 60\n    assert lut[255] == 255\n\n\ndef test_rawmode_valueerrors(tmp_path):\n    # Arrange\n    palette = ImagePalette.raw(\"RGB\", list(range(256)) * 3)\n\n    # Act / Assert\n    with pytest.raises(ValueError):\n        palette.tobytes()\n    with pytest.raises(ValueError):\n        palette.getcolor((1, 2, 3))\n    f = str(tmp_path / \"temp.lut\")\n    with pytest.raises(ValueError):\n        palette.save(f)\n\n\ndef test_getdata():\n    # Arrange\n    data_in = list(range(256)) * 3\n    palette = ImagePalette.ImagePalette(\"RGB\", data_in)\n\n    # Act\n    mode, data_out = palette.getdata()\n\n    # Assert\n    assert mode == \"RGB\"\n\n\ndef test_rawmode_getdata():\n    # Arrange\n    data_in = list(range(256)) * 3\n    palette = ImagePalette.raw(\"RGB\", data_in)\n\n    # Act\n    rawmode, data_out = palette.getdata()\n\n    # Assert\n    assert rawmode == \"RGB\"\n    assert data_in == data_out\n\n\ndef test_2bit_palette(tmp_path):\n    # issue #2258, 2 bit palettes are corrupted.\n    outfile = str(tmp_path / \"temp.png\")\n\n    rgb = b\"\\x00\" * 2 + b\"\\x01\" * 2 + b\"\\x02\" * 2\n    img = Image.frombytes(\"P\", (6, 1), rgb)\n    img.putpalette(b\"\\xFF\\x00\\x00\\x00\\xFF\\x00\\x00\\x00\\xFF\")  # RGB\n    img.save(outfile, format=\"PNG\")\n\n    assert_image_equal_tofile(img, outfile)\n\n\ndef test_invalid_palette():\n    with pytest.raises(OSError):\n        ImagePalette.load(\"Tests/images/hopper.jpg\")\n",
            "new_file_content": "import pytest\n\nfrom PIL import Image, ImagePalette\n\nfrom .helper import assert_image_equal, assert_image_equal_tofile\n\n\ndef test_sanity():\n\n    palette = ImagePalette.ImagePalette(\"RGB\", list(range(256)) * 3)\n    assert len(palette.colors) == 256\n\n    with pytest.warns(DeprecationWarning):\n        with pytest.raises(ValueError):\n            ImagePalette.ImagePalette(\"RGB\", list(range(256)) * 3, 10)\n\n\ndef test_reload():\n    im = Image.open(\"Tests/images/hopper.gif\")\n    original = im.copy()\n    im.palette.dirty = 1\n    assert_image_equal(im.convert(\"RGB\"), original.convert(\"RGB\"))\n\n\ndef test_getcolor():\n\n    palette = ImagePalette.ImagePalette()\n    assert len(palette.palette) == 0\n    assert len(palette.colors) == 0\n\n    test_map = {}\n    for i in range(256):\n        test_map[palette.getcolor((i, i, i))] = i\n    assert len(test_map) == 256\n\n    # Colors can be converted between RGB and RGBA\n    rgba_palette = ImagePalette.ImagePalette(\"RGBA\")\n    assert rgba_palette.getcolor((0, 0, 0)) == rgba_palette.getcolor((0, 0, 0, 255))\n\n    assert palette.getcolor((0, 0, 0)) == palette.getcolor((0, 0, 0, 255))\n\n    # An error is raised when the palette is full\n    with pytest.raises(ValueError):\n        palette.getcolor((1, 2, 3))\n    # But not if the image is not using one of the palette entries\n    palette.getcolor((1, 2, 3), image=Image.new(\"P\", (1, 1)))\n\n    # Test unknown color specifier\n    with pytest.raises(ValueError):\n        palette.getcolor(\"unknown\")\n\n\n@pytest.mark.parametrize(\n    \"index, palette\",\n    [\n        # Test when the palette is not full\n        (0, ImagePalette.ImagePalette()),\n        # Test when the palette is full\n        (255, ImagePalette.ImagePalette(\"RGB\", list(range(256)) * 3)),\n    ],\n)\ndef test_getcolor_not_special(index, palette):\n    im = Image.new(\"P\", (1, 1))\n\n    # Do not use transparency index as a new color\n    im.info[\"transparency\"] = index\n    index1 = palette.getcolor((0, 0, 0), im)\n    assert index1 != index\n\n    # Do not use background index as a new color\n    im.info[\"background\"] = index1\n    index2 = palette.getcolor((0, 0, 1), im)\n    assert index2 not in (index, index1)\n\n\ndef test_file(tmp_path):\n\n    palette = ImagePalette.ImagePalette(\"RGB\", list(range(256)) * 3)\n\n    f = str(tmp_path / \"temp.lut\")\n\n    palette.save(f)\n\n    p = ImagePalette.load(f)\n\n    # load returns raw palette information\n    assert len(p[0]) == 768\n    assert p[1] == \"RGB\"\n\n    p = ImagePalette.raw(p[1], p[0])\n    assert isinstance(p, ImagePalette.ImagePalette)\n    assert p.palette == palette.tobytes()\n\n\ndef test_make_linear_lut():\n    # Arrange\n    black = 0\n    white = 255\n\n    # Act\n    lut = ImagePalette.make_linear_lut(black, white)\n\n    # Assert\n    assert isinstance(lut, list)\n    assert len(lut) == 256\n    # Check values\n    for i in range(0, len(lut)):\n        assert lut[i] == i\n\n\ndef test_make_linear_lut_not_yet_implemented():\n    # Update after FIXME\n    # Arrange\n    black = 1\n    white = 255\n\n    # Act\n    with pytest.raises(NotImplementedError):\n        ImagePalette.make_linear_lut(black, white)\n\n\ndef test_make_gamma_lut():\n    # Arrange\n    exp = 5\n\n    # Act\n    lut = ImagePalette.make_gamma_lut(exp)\n\n    # Assert\n    assert isinstance(lut, list)\n    assert len(lut) == 256\n    # Check a few values\n    assert lut[0] == 0\n    assert lut[63] == 0\n    assert lut[127] == 8\n    assert lut[191] == 60\n    assert lut[255] == 255\n\n\ndef test_rawmode_valueerrors(tmp_path):\n    # Arrange\n    palette = ImagePalette.raw(\"RGB\", list(range(256)) * 3)\n\n    # Act / Assert\n    with pytest.raises(ValueError):\n        palette.tobytes()\n    with pytest.raises(ValueError):\n        palette.getcolor((1, 2, 3))\n    f = str(tmp_path / \"temp.lut\")\n    with pytest.raises(ValueError):\n        palette.save(f)\n\n\ndef test_getdata():\n    # Arrange\n    data_in = list(range(256)) * 3\n    palette = ImagePalette.ImagePalette(\"RGB\", data_in)\n\n    # Act\n    mode, data_out = palette.getdata()\n\n    # Assert\n    assert mode == \"RGB\"\n\n\ndef test_rawmode_getdata():\n    # Arrange\n    data_in = list(range(256)) * 3\n    palette = ImagePalette.raw(\"RGB\", data_in)\n\n    # Act\n    rawmode, data_out = palette.getdata()\n\n    # Assert\n    assert rawmode == \"RGB\"\n    assert data_in == data_out\n\n\ndef test_2bit_palette(tmp_path):\n    # issue #2258, 2 bit palettes are corrupted.\n    outfile = str(tmp_path / \"temp.png\")\n\n    rgb = b\"\\x00\" * 2 + b\"\\x01\" * 2 + b\"\\x02\" * 2\n    img = Image.frombytes(\"P\", (6, 1), rgb)\n    img.putpalette(b\"\\xFF\\x00\\x00\\x00\\xFF\\x00\\x00\\x00\\xFF\")  # RGB\n    img.save(outfile, format=\"PNG\")\n\n    assert_image_equal_tofile(img, outfile)\n\n\ndef test_invalid_palette():\n    with pytest.raises(OSError):\n        ImagePalette.load(\"Tests/images/hopper.jpg\")\n",
            "header": {
                "file": {
                    "path": "Tests/test_imagepalette.py"
                },
                "misc_line": null
            },
            "index_line": {
                "old_commit_hash": "ecfbda1d8",
                "new_commit_hash": "5a59b7799",
                "mode": "100644"
            },
            "is_binary_file": false,
            "binary_line": null,
            "minus_file": {
                "path": "a/Tests/test_imagepalette.py"
            },
            "plus_file": {
                "path": "b/Tests/test_imagepalette.py"
            },
            "hunks": [
                {
                    "descriptor": {
                        "old_range": {
                            "start": 10,
                            "length": 8
                        },
                        "new_range": {
                            "start": 10,
                            "length": 9
                        },
                        "section": "def test_sanity():"
                    },
                    "line_group": {
                        "all_lines": [
                            {
                                "content": "    palette = ImagePalette.ImagePalette(\"RGB\", list(range(256)) * 3)",
                                "type": "context"
                            },
                            {
                                "content": "    assert len(palette.colors) == 256",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "    with pytest.raises(ValueError):",
                                "type": "deleted"
                            },
                            {
                                "content": "        ImagePalette.ImagePalette(\"RGB\", list(range(256)) * 3, 10)",
                                "type": "deleted"
                            },
                            {
                                "content": "    with pytest.warns(DeprecationWarning):",
                                "type": "added"
                            },
                            {
                                "content": "        with pytest.raises(ValueError):",
                                "type": "added"
                            },
                            {
                                "content": "            ImagePalette.ImagePalette(\"RGB\", list(range(256)) * 3, 10)",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "def test_reload():",
                                "type": "context"
                            }
                        ]
                    },
                    "modified_entities": [
                        {
                            "file_name": "Tests/test_imagepalette.py",
                            "type": "function",
                            "name": "test_sanity",
                            "content": "def test_sanity():\n\n    palette = ImagePalette.ImagePalette(\"RGB\", list(range(256)) * 3)\n    assert len(palette.colors) == 256\n\n    with pytest.raises(ValueError):\n        ImagePalette.ImagePalette(\"RGB\", list(range(256)) * 3, 10)",
                            "ast_type_str": "FunctionDef",
                            "start_lineno": 8,
                            "end_lineno": 14,
                            "parent": null
                        }
                    ],
                    "added_entities": [],
                    "deleted_entities": []
                }
            ]
        },
        {
            "old_file_content": ".. _deprecations:\n\nDeprecations and removals\n=========================\n\nThis page lists Pillow features that are deprecated, or have been removed in\npast major releases, and gives the alternatives to use instead.\n\nDeprecated features\n-------------------\n\nBelow are features which are considered deprecated. Where appropriate,\na ``DeprecationWarning`` is issued.\n\nFreeType 2.7\n~~~~~~~~~~~~\n\n.. deprecated:: 8.1.0\n\nSupport for FreeType 2.7 is deprecated and will be removed in Pillow 9.0.0 (2022-01-02),\nwhen FreeType 2.8 will be the minimum supported.\n\nWe recommend upgrading to at least FreeType `2.10.4`_, which fixed a severe\nvulnerability introduced in FreeType 2.6 (:cve:`CVE-2020-15999`).\n\n.. _2.10.4: https://sourceforge.net/projects/freetype/files/freetype2/2.10.4/\n\nImage.show command parameter\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n.. deprecated:: 7.2.0\n\nThe ``command`` parameter will be removed in Pillow 9.0.0 (2022-01-02).\nUse a subclass of :py:class:`.ImageShow.Viewer` instead.\n\nImage._showxv\n~~~~~~~~~~~~~\n\n.. deprecated:: 7.2.0\n\n``Image._showxv`` will be removed in Pillow 9.0.0 (2022-01-02).\nUse :py:meth:`.Image.Image.show` instead. If custom behaviour is required, use\n:py:func:`.ImageShow.register` to add a custom :py:class:`.ImageShow.Viewer` class.\n\nImageFile.raise_ioerror\n~~~~~~~~~~~~~~~~~~~~~~~\n\n.. deprecated:: 7.2.0\n\n``IOError`` was merged into ``OSError`` in Python 3.3.\nSo, ``ImageFile.raise_ioerror`` will be removed in Pillow 9.0.0 (2022-01-02).\nUse ``ImageFile.raise_oserror`` instead.\n\nPILLOW_VERSION constant\n~~~~~~~~~~~~~~~~~~~~~~~\n\n.. deprecated:: 5.2.0\n\n``PILLOW_VERSION`` will be removed in Pillow 9.0.0 (2022-01-02).\nUse ``__version__`` instead.\n\nIt was initially removed in Pillow 7.0.0, but brought back in 7.1.0 to give projects\nmore time to upgrade.\n\nTk/Tcl 8.4\n~~~~~~~~~~\n\n.. deprecated:: 8.2.0\n\nSupport for Tk/Tcl 8.4 is deprecated and will be removed in Pillow 10.0.0 (2023-01-02),\nwhen Tk/Tcl 8.5 will be the minimum supported.\n\nCategories\n~~~~~~~~~~\n\n.. deprecated:: 8.2.0\n\n``im.category`` is deprecated and will be removed in Pillow 10.0.0 (2023-01-02),\nalong with the related ``Image.NORMAL``, ``Image.SEQUENCE`` and\n``Image.CONTAINER`` attributes.\n\nTo determine if an image has multiple frames or not,\n``getattr(im, \"is_animated\", False)`` can be used instead.\n\nJpegImagePlugin.convert_dict_qtables\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n.. deprecated:: 8.3.0\n\nJPEG ``quantization`` is now automatically converted, but still returned as a\ndictionary. The :py:attr:`~PIL.JpegImagePlugin.convert_dict_qtables` method no longer\nperforms any operations on the data given to it, has been deprecated and will be\nremoved in Pillow 10.0.0 (2023-01-02).\n\nRemoved features\n----------------\n\nDeprecated features are only removed in major releases after an appropriate\nperiod of deprecation has passed.\n\nim.offset\n~~~~~~~~~\n\n.. deprecated:: 1.1.2\n.. versionremoved:: 8.0.0\n\n``im.offset()`` has been removed, call :py:func:`.ImageChops.offset()` instead.\n\nIt was documented as deprecated in PIL 1.1.2,\nraised a ``DeprecationWarning`` since 1.1.5,\nan ``Exception`` since Pillow 3.0.0\nand ``NotImplementedError`` since 3.3.0.\n\nImage.fromstring, im.fromstring and im.tostring\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n.. deprecated:: 2.0.0\n.. versionremoved:: 8.0.0\n\n* ``Image.fromstring()`` has been removed, call :py:func:`.Image.frombytes()` instead.\n* ``im.fromstring()`` has been removed, call :py:meth:`~PIL.Image.Image.frombytes()` instead.\n* ``im.tostring()`` has been removed, call :py:meth:`~PIL.Image.Image.tobytes()` instead.\n\nThey issued a ``DeprecationWarning`` since 2.0.0,\nan ``Exception`` since 3.0.0\nand ``NotImplementedError`` since 3.3.0.\n\nImageCms.CmsProfile attributes\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n.. deprecated:: 3.2.0\n.. versionremoved:: 8.0.0\n\nSome attributes in :py:class:`PIL.ImageCms.CmsProfile` have been removed. From 6.0.0,\nthey issued a ``DeprecationWarning``:\n\n========================  ===================================================\nRemoved                   Use instead\n========================  ===================================================\n``color_space``           Padded :py:attr:`~.CmsProfile.xcolor_space`\n``pcs``                   Padded :py:attr:`~.CmsProfile.connection_space`\n``product_copyright``     Unicode :py:attr:`~.CmsProfile.copyright`\n``product_desc``          Unicode :py:attr:`~.CmsProfile.profile_description`\n``product_description``   Unicode :py:attr:`~.CmsProfile.profile_description`\n``product_manufacturer``  Unicode :py:attr:`~.CmsProfile.manufacturer`\n``product_model``         Unicode :py:attr:`~.CmsProfile.model`\n========================  ===================================================\n\nPython 2.7\n~~~~~~~~~~\n\n.. deprecated:: 6.0.0\n.. versionremoved:: 7.0.0\n\nPython 2.7 reached end-of-life on 2020-01-01. Pillow 6.x was the last series to\nsupport Python 2.\n\nImage.__del__\n~~~~~~~~~~~~~\n\n.. deprecated:: 6.1.0\n.. versionremoved:: 7.0.0\n\nImplicitly closing the image's underlying file in ``Image.__del__`` has been removed.\nUse a context manager or call ``Image.close()`` instead to close the file in a\ndeterministic way.\n\nPrevious method:\n\n.. code-block:: python\n\n    im = Image.open(\"hopper.png\")\n    im.save(\"out.jpg\")\n\nUse instead:\n\n.. code-block:: python\n\n    with Image.open(\"hopper.png\") as im:\n        im.save(\"out.jpg\")\n\nPIL.*ImagePlugin.__version__ attributes\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n.. deprecated:: 6.0.0\n.. versionremoved:: 7.0.0\n\nThe version constants of individual plugins have been removed. Use ``PIL.__version__``\ninstead.\n\n===============================  =================================  ==================================\nRemoved                          Removed                            Removed\n===============================  =================================  ==================================\n``BmpImagePlugin.__version__``   ``Jpeg2KImagePlugin.__version__``  ``PngImagePlugin.__version__``\n``CurImagePlugin.__version__``   ``JpegImagePlugin.__version__``    ``PpmImagePlugin.__version__``\n``DcxImagePlugin.__version__``   ``McIdasImagePlugin.__version__``  ``PsdImagePlugin.__version__``\n``EpsImagePlugin.__version__``   ``MicImagePlugin.__version__``     ``SgiImagePlugin.__version__``\n``FliImagePlugin.__version__``   ``MpegImagePlugin.__version__``    ``SunImagePlugin.__version__``\n``FpxImagePlugin.__version__``   ``MpoImagePlugin.__version__``     ``TgaImagePlugin.__version__``\n``GdImageFile.__version__``      ``MspImagePlugin.__version__``     ``TiffImagePlugin.__version__``\n``GifImagePlugin.__version__``   ``PalmImagePlugin.__version__``    ``WmfImagePlugin.__version__``\n``IcoImagePlugin.__version__``   ``PcdImagePlugin.__version__``     ``XbmImagePlugin.__version__``\n``ImImagePlugin.__version__``    ``PcxImagePlugin.__version__``     ``XpmImagePlugin.__version__``\n``ImtImagePlugin.__version__``   ``PdfImagePlugin.__version__``     ``XVThumbImagePlugin.__version__``\n``IptcImagePlugin.__version__``  ``PixarImagePlugin.__version__``\n===============================  =================================  ==================================\n\nPyQt4 and PySide\n~~~~~~~~~~~~~~~~\n\n.. deprecated:: 6.0.0\n.. versionremoved:: 7.0.0\n\nQt 4 reached end-of-life on 2015-12-19. Its Python bindings are also EOL: PyQt4 since\n2018-08-31 and PySide since 2015-10-14.\n\nSupport for PyQt4 and PySide has been removed  from ``ImageQt``. Please upgrade to PyQt5\nor PySide2.\n\nSetting the size of TIFF images\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n.. deprecated:: 5.3.0\n.. versionremoved:: 7.0.0\n\nSetting the size of a TIFF image directly (eg. ``im.size = (256, 256)``) throws\nan error. Use ``Image.resize`` instead.\n\nVERSION constant\n~~~~~~~~~~~~~~~~\n\n.. deprecated:: 5.2.0\n.. versionremoved:: 6.0.0\n\n``VERSION`` (the old PIL version, always 1.1.7) has been removed. Use\n``__version__`` instead.\n\nUndocumented ImageOps functions\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n.. deprecated:: 4.3.0\n.. versionremoved:: 6.0.0\n\nSeveral undocumented functions in ``ImageOps`` have been removed. Use the equivalents\nin ``ImageFilter`` instead:\n\n==========================  ============================\nRemoved                     Use instead\n==========================  ============================\n``ImageOps.box_blur``       ``ImageFilter.BoxBlur``\n``ImageOps.gaussian_blur``  ``ImageFilter.GaussianBlur``\n``ImageOps.gblur``          ``ImageFilter.GaussianBlur``\n``ImageOps.usm``            ``ImageFilter.UnsharpMask``\n``ImageOps.unsharp_mask``   ``ImageFilter.UnsharpMask``\n==========================  ============================\n\nPIL.OleFileIO\n~~~~~~~~~~~~~\n\n.. deprecated:: 4.0.0\n.. versionremoved:: 6.0.0\n\nPIL.OleFileIO was removed as a vendored file in Pillow 4.0.0 (2017-01) in favour of\nthe upstream olefile Python package, and replaced with an ``ImportError`` in 5.0.0\n(2018-01). The deprecated file has now been removed from Pillow. If needed, install from\nPyPI (eg. ``python3 -m pip install olefile``).\n",
            "new_file_content": ".. _deprecations:\n\nDeprecations and removals\n=========================\n\nThis page lists Pillow features that are deprecated, or have been removed in\npast major releases, and gives the alternatives to use instead.\n\nDeprecated features\n-------------------\n\nBelow are features which are considered deprecated. Where appropriate,\na ``DeprecationWarning`` is issued.\n\nFreeType 2.7\n~~~~~~~~~~~~\n\n.. deprecated:: 8.1.0\n\nSupport for FreeType 2.7 is deprecated and will be removed in Pillow 9.0.0 (2022-01-02),\nwhen FreeType 2.8 will be the minimum supported.\n\nWe recommend upgrading to at least FreeType `2.10.4`_, which fixed a severe\nvulnerability introduced in FreeType 2.6 (:cve:`CVE-2020-15999`).\n\n.. _2.10.4: https://sourceforge.net/projects/freetype/files/freetype2/2.10.4/\n\nImage.show command parameter\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n.. deprecated:: 7.2.0\n\nThe ``command`` parameter will be removed in Pillow 9.0.0 (2022-01-02).\nUse a subclass of :py:class:`.ImageShow.Viewer` instead.\n\nImage._showxv\n~~~~~~~~~~~~~\n\n.. deprecated:: 7.2.0\n\n``Image._showxv`` will be removed in Pillow 9.0.0 (2022-01-02).\nUse :py:meth:`.Image.Image.show` instead. If custom behaviour is required, use\n:py:func:`.ImageShow.register` to add a custom :py:class:`.ImageShow.Viewer` class.\n\nImageFile.raise_ioerror\n~~~~~~~~~~~~~~~~~~~~~~~\n\n.. deprecated:: 7.2.0\n\n``IOError`` was merged into ``OSError`` in Python 3.3.\nSo, ``ImageFile.raise_ioerror`` will be removed in Pillow 9.0.0 (2022-01-02).\nUse ``ImageFile.raise_oserror`` instead.\n\nPILLOW_VERSION constant\n~~~~~~~~~~~~~~~~~~~~~~~\n\n.. deprecated:: 5.2.0\n\n``PILLOW_VERSION`` will be removed in Pillow 9.0.0 (2022-01-02).\nUse ``__version__`` instead.\n\nIt was initially removed in Pillow 7.0.0, but brought back in 7.1.0 to give projects\nmore time to upgrade.\n\nTk/Tcl 8.4\n~~~~~~~~~~\n\n.. deprecated:: 8.2.0\n\nSupport for Tk/Tcl 8.4 is deprecated and will be removed in Pillow 10.0.0 (2023-01-02),\nwhen Tk/Tcl 8.5 will be the minimum supported.\n\nCategories\n~~~~~~~~~~\n\n.. deprecated:: 8.2.0\n\n``im.category`` is deprecated and will be removed in Pillow 10.0.0 (2023-01-02),\nalong with the related ``Image.NORMAL``, ``Image.SEQUENCE`` and\n``Image.CONTAINER`` attributes.\n\nTo determine if an image has multiple frames or not,\n``getattr(im, \"is_animated\", False)`` can be used instead.\n\nJpegImagePlugin.convert_dict_qtables\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n.. deprecated:: 8.3.0\n\nJPEG ``quantization`` is now automatically converted, but still returned as a\ndictionary. The :py:attr:`~PIL.JpegImagePlugin.convert_dict_qtables` method no longer\nperforms any operations on the data given to it, has been deprecated and will be\nremoved in Pillow 10.0.0 (2023-01-02).\n\nImagePalette size parameter\n~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n.. deprecated:: 8.4.0\n\nThe ``size`` parameter will be removed in Pillow 10.0.0 (2023-01-02).\n\nBefore Pillow 8.3.0, ``ImagePalette`` required palette data of particular lengths by\ndefault, and the size parameter could be used to override that. Pillow 8.3.0 removed\nthe default required length, also removing the need for the size parameter.\n\nRemoved features\n----------------\n\nDeprecated features are only removed in major releases after an appropriate\nperiod of deprecation has passed.\n\nim.offset\n~~~~~~~~~\n\n.. deprecated:: 1.1.2\n.. versionremoved:: 8.0.0\n\n``im.offset()`` has been removed, call :py:func:`.ImageChops.offset()` instead.\n\nIt was documented as deprecated in PIL 1.1.2,\nraised a ``DeprecationWarning`` since 1.1.5,\nan ``Exception`` since Pillow 3.0.0\nand ``NotImplementedError`` since 3.3.0.\n\nImage.fromstring, im.fromstring and im.tostring\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n.. deprecated:: 2.0.0\n.. versionremoved:: 8.0.0\n\n* ``Image.fromstring()`` has been removed, call :py:func:`.Image.frombytes()` instead.\n* ``im.fromstring()`` has been removed, call :py:meth:`~PIL.Image.Image.frombytes()` instead.\n* ``im.tostring()`` has been removed, call :py:meth:`~PIL.Image.Image.tobytes()` instead.\n\nThey issued a ``DeprecationWarning`` since 2.0.0,\nan ``Exception`` since 3.0.0\nand ``NotImplementedError`` since 3.3.0.\n\nImageCms.CmsProfile attributes\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n.. deprecated:: 3.2.0\n.. versionremoved:: 8.0.0\n\nSome attributes in :py:class:`PIL.ImageCms.CmsProfile` have been removed. From 6.0.0,\nthey issued a ``DeprecationWarning``:\n\n========================  ===================================================\nRemoved                   Use instead\n========================  ===================================================\n``color_space``           Padded :py:attr:`~.CmsProfile.xcolor_space`\n``pcs``                   Padded :py:attr:`~.CmsProfile.connection_space`\n``product_copyright``     Unicode :py:attr:`~.CmsProfile.copyright`\n``product_desc``          Unicode :py:attr:`~.CmsProfile.profile_description`\n``product_description``   Unicode :py:attr:`~.CmsProfile.profile_description`\n``product_manufacturer``  Unicode :py:attr:`~.CmsProfile.manufacturer`\n``product_model``         Unicode :py:attr:`~.CmsProfile.model`\n========================  ===================================================\n\nPython 2.7\n~~~~~~~~~~\n\n.. deprecated:: 6.0.0\n.. versionremoved:: 7.0.0\n\nPython 2.7 reached end-of-life on 2020-01-01. Pillow 6.x was the last series to\nsupport Python 2.\n\nImage.__del__\n~~~~~~~~~~~~~\n\n.. deprecated:: 6.1.0\n.. versionremoved:: 7.0.0\n\nImplicitly closing the image's underlying file in ``Image.__del__`` has been removed.\nUse a context manager or call ``Image.close()`` instead to close the file in a\ndeterministic way.\n\nPrevious method:\n\n.. code-block:: python\n\n    im = Image.open(\"hopper.png\")\n    im.save(\"out.jpg\")\n\nUse instead:\n\n.. code-block:: python\n\n    with Image.open(\"hopper.png\") as im:\n        im.save(\"out.jpg\")\n\nPIL.*ImagePlugin.__version__ attributes\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n.. deprecated:: 6.0.0\n.. versionremoved:: 7.0.0\n\nThe version constants of individual plugins have been removed. Use ``PIL.__version__``\ninstead.\n\n===============================  =================================  ==================================\nRemoved                          Removed                            Removed\n===============================  =================================  ==================================\n``BmpImagePlugin.__version__``   ``Jpeg2KImagePlugin.__version__``  ``PngImagePlugin.__version__``\n``CurImagePlugin.__version__``   ``JpegImagePlugin.__version__``    ``PpmImagePlugin.__version__``\n``DcxImagePlugin.__version__``   ``McIdasImagePlugin.__version__``  ``PsdImagePlugin.__version__``\n``EpsImagePlugin.__version__``   ``MicImagePlugin.__version__``     ``SgiImagePlugin.__version__``\n``FliImagePlugin.__version__``   ``MpegImagePlugin.__version__``    ``SunImagePlugin.__version__``\n``FpxImagePlugin.__version__``   ``MpoImagePlugin.__version__``     ``TgaImagePlugin.__version__``\n``GdImageFile.__version__``      ``MspImagePlugin.__version__``     ``TiffImagePlugin.__version__``\n``GifImagePlugin.__version__``   ``PalmImagePlugin.__version__``    ``WmfImagePlugin.__version__``\n``IcoImagePlugin.__version__``   ``PcdImagePlugin.__version__``     ``XbmImagePlugin.__version__``\n``ImImagePlugin.__version__``    ``PcxImagePlugin.__version__``     ``XpmImagePlugin.__version__``\n``ImtImagePlugin.__version__``   ``PdfImagePlugin.__version__``     ``XVThumbImagePlugin.__version__``\n``IptcImagePlugin.__version__``  ``PixarImagePlugin.__version__``\n===============================  =================================  ==================================\n\nPyQt4 and PySide\n~~~~~~~~~~~~~~~~\n\n.. deprecated:: 6.0.0\n.. versionremoved:: 7.0.0\n\nQt 4 reached end-of-life on 2015-12-19. Its Python bindings are also EOL: PyQt4 since\n2018-08-31 and PySide since 2015-10-14.\n\nSupport for PyQt4 and PySide has been removed  from ``ImageQt``. Please upgrade to PyQt5\nor PySide2.\n\nSetting the size of TIFF images\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n.. deprecated:: 5.3.0\n.. versionremoved:: 7.0.0\n\nSetting the size of a TIFF image directly (eg. ``im.size = (256, 256)``) throws\nan error. Use ``Image.resize`` instead.\n\nVERSION constant\n~~~~~~~~~~~~~~~~\n\n.. deprecated:: 5.2.0\n.. versionremoved:: 6.0.0\n\n``VERSION`` (the old PIL version, always 1.1.7) has been removed. Use\n``__version__`` instead.\n\nUndocumented ImageOps functions\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n.. deprecated:: 4.3.0\n.. versionremoved:: 6.0.0\n\nSeveral undocumented functions in ``ImageOps`` have been removed. Use the equivalents\nin ``ImageFilter`` instead:\n\n==========================  ============================\nRemoved                     Use instead\n==========================  ============================\n``ImageOps.box_blur``       ``ImageFilter.BoxBlur``\n``ImageOps.gaussian_blur``  ``ImageFilter.GaussianBlur``\n``ImageOps.gblur``          ``ImageFilter.GaussianBlur``\n``ImageOps.usm``            ``ImageFilter.UnsharpMask``\n``ImageOps.unsharp_mask``   ``ImageFilter.UnsharpMask``\n==========================  ============================\n\nPIL.OleFileIO\n~~~~~~~~~~~~~\n\n.. deprecated:: 4.0.0\n.. versionremoved:: 6.0.0\n\nPIL.OleFileIO was removed as a vendored file in Pillow 4.0.0 (2017-01) in favour of\nthe upstream olefile Python package, and replaced with an ``ImportError`` in 5.0.0\n(2018-01). The deprecated file has now been removed from Pillow. If needed, install from\nPyPI (eg. ``python3 -m pip install olefile``).\n",
            "header": {
                "file": {
                    "path": "docs/deprecations.rst"
                },
                "misc_line": null
            },
            "index_line": {
                "old_commit_hash": "9ce2fe7b3",
                "new_commit_hash": "45720ccc0",
                "mode": "100644"
            },
            "is_binary_file": false,
            "binary_line": null,
            "minus_file": {
                "path": "a/docs/deprecations.rst"
            },
            "plus_file": {
                "path": "b/docs/deprecations.rst"
            },
            "hunks": [
                {
                    "descriptor": {
                        "old_range": {
                            "start": 92,
                            "length": 6
                        },
                        "new_range": {
                            "start": 92,
                            "length": 17
                        },
                        "section": "dictionary. The :py:attr:`~PIL.JpegImagePlugin.convert_dict_qtables` method no l"
                    },
                    "line_group": {
                        "all_lines": [
                            {
                                "content": "performs any operations on the data given to it, has been deprecated and will be",
                                "type": "context"
                            },
                            {
                                "content": "removed in Pillow 10.0.0 (2023-01-02).",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "ImagePalette size parameter",
                                "type": "added"
                            },
                            {
                                "content": "~~~~~~~~~~~~~~~~~~~~~~~~~~~",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "added"
                            },
                            {
                                "content": ".. deprecated:: 8.4.0",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "added"
                            },
                            {
                                "content": "The ``size`` parameter will be removed in Pillow 10.0.0 (2023-01-02).",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "added"
                            },
                            {
                                "content": "Before Pillow 8.3.0, ``ImagePalette`` required palette data of particular lengths by",
                                "type": "added"
                            },
                            {
                                "content": "default, and the size parameter could be used to override that. Pillow 8.3.0 removed",
                                "type": "added"
                            },
                            {
                                "content": "the default required length, also removing the need for the size parameter.",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "added"
                            },
                            {
                                "content": "Removed features",
                                "type": "context"
                            },
                            {
                                "content": "----------------",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            }
                        ]
                    },
                    "modified_entities": [],
                    "added_entities": [],
                    "deleted_entities": []
                }
            ]
        },
        {
            "old_file_content": "#\n# The Python Imaging Library.\n# $Id$\n#\n# image palette object\n#\n# History:\n# 1996-03-11 fl   Rewritten.\n# 1997-01-03 fl   Up and running.\n# 1997-08-23 fl   Added load hack\n# 2001-04-16 fl   Fixed randint shadow bug in random()\n#\n# Copyright (c) 1997-2001 by Secret Labs AB\n# Copyright (c) 1996-1997 by Fredrik Lundh\n#\n# See the README file for information on usage and redistribution.\n#\n\nimport array\n\nfrom . import GimpGradientFile, GimpPaletteFile, ImageColor, PaletteFile\n\n\nclass ImagePalette:\n    \"\"\"\n    Color palette for palette mapped images\n\n    :param mode: The mode to use for the Palette. See:\n        :ref:`concept-modes`. Defaults to \"RGB\"\n    :param palette: An optional palette. If given, it must be a bytearray,\n        an array or a list of ints between 0-255. The list must be aligned\n        by channel (All R values must be contiguous in the list before G\n        and B values.) Defaults to 0 through 255 per channel.\n    :param size: An optional palette size. If given, an error is raised\n        if ``palette`` is not of equal length.\n    \"\"\"\n\n    def __init__(self, mode=\"RGB\", palette=None, size=0):\n        self.mode = mode\n        self.rawmode = None  # if set, palette contains raw data\n        self.palette = palette or bytearray()\n        self.dirty = None\n        if size != 0 and size != len(self.palette):\n            raise ValueError(\"wrong palette size\")\n\n    @property\n    def palette(self):\n        return self._palette\n\n    @palette.setter\n    def palette(self, palette):\n        self._palette = palette\n\n        mode_len = len(self.mode)\n        self.colors = {}\n        for i in range(0, len(self.palette), mode_len):\n            color = tuple(self.palette[i : i + mode_len])\n            if color in self.colors:\n                continue\n            self.colors[color] = i // mode_len\n\n    def copy(self):\n        new = ImagePalette()\n\n        new.mode = self.mode\n        new.rawmode = self.rawmode\n        if self.palette is not None:\n            new.palette = self.palette[:]\n        new.dirty = self.dirty\n\n        return new\n\n    def getdata(self):\n        \"\"\"\n        Get palette contents in format suitable for the low-level\n        ``im.putpalette`` primitive.\n\n        .. warning:: This method is experimental.\n        \"\"\"\n        if self.rawmode:\n            return self.rawmode, self.palette\n        return self.mode, self.tobytes()\n\n    def tobytes(self):\n        \"\"\"Convert palette to bytes.\n\n        .. warning:: This method is experimental.\n        \"\"\"\n        if self.rawmode:\n            raise ValueError(\"palette contains raw palette data\")\n        if isinstance(self.palette, bytes):\n            return self.palette\n        arr = array.array(\"B\", self.palette)\n        return arr.tobytes()\n\n    # Declare tostring as an alias for tobytes\n    tostring = tobytes\n\n    def getcolor(self, color, image=None):\n        \"\"\"Given an rgb tuple, allocate palette entry.\n\n        .. warning:: This method is experimental.\n        \"\"\"\n        if self.rawmode:\n            raise ValueError(\"palette contains raw palette data\")\n        if isinstance(color, tuple):\n            if self.mode == \"RGB\":\n                if len(color) == 4 and color[3] == 255:\n                    color = color[:3]\n            elif self.mode == \"RGBA\":\n                if len(color) == 3:\n                    color += (255,)\n            try:\n                return self.colors[color]\n            except KeyError as e:\n                # allocate new color slot\n                if not isinstance(self.palette, bytearray):\n                    self._palette = bytearray(self.palette)\n                index = len(self.palette) // 3\n                special_colors = ()\n                if image:\n                    special_colors = (\n                        image.info.get(\"background\"),\n                        image.info.get(\"transparency\"),\n                    )\n                while index in special_colors:\n                    index += 1\n                if index >= 256:\n                    if image:\n                        # Search for an unused index\n                        for i, count in reversed(list(enumerate(image.histogram()))):\n                            if count == 0 and i not in special_colors:\n                                index = i\n                                break\n                    if index >= 256:\n                        raise ValueError(\"cannot allocate more than 256 colors\") from e\n                self.colors[color] = index\n                if index * 3 < len(self.palette):\n                    self._palette = (\n                        self.palette[: index * 3]\n                        + bytes(color)\n                        + self.palette[index * 3 + 3 :]\n                    )\n                else:\n                    self._palette += bytes(color)\n                self.dirty = 1\n                return index\n        else:\n            raise ValueError(f\"unknown color specifier: {repr(color)}\")\n\n    def save(self, fp):\n        \"\"\"Save palette to text file.\n\n        .. warning:: This method is experimental.\n        \"\"\"\n        if self.rawmode:\n            raise ValueError(\"palette contains raw palette data\")\n        if isinstance(fp, str):\n            fp = open(fp, \"w\")\n        fp.write(\"# Palette\\n\")\n        fp.write(f\"# Mode: {self.mode}\\n\")\n        for i in range(256):\n            fp.write(f\"{i}\")\n            for j in range(i * len(self.mode), (i + 1) * len(self.mode)):\n                try:\n                    fp.write(f\" {self.palette[j]}\")\n                except IndexError:\n                    fp.write(\" 0\")\n            fp.write(\"\\n\")\n        fp.close()\n\n\n# --------------------------------------------------------------------\n# Internal\n\n\ndef raw(rawmode, data):\n    palette = ImagePalette()\n    palette.rawmode = rawmode\n    palette.palette = data\n    palette.dirty = 1\n    return palette\n\n\n# --------------------------------------------------------------------\n# Factories\n\n\ndef make_linear_lut(black, white):\n    lut = []\n    if black == 0:\n        for i in range(256):\n            lut.append(white * i // 255)\n    else:\n        raise NotImplementedError  # FIXME\n    return lut\n\n\ndef make_gamma_lut(exp):\n    lut = []\n    for i in range(256):\n        lut.append(int(((i / 255.0) ** exp) * 255.0 + 0.5))\n    return lut\n\n\ndef negative(mode=\"RGB\"):\n    palette = list(range(256))\n    palette.reverse()\n    return ImagePalette(mode, palette * len(mode))\n\n\ndef random(mode=\"RGB\"):\n    from random import randint\n\n    palette = []\n    for i in range(256 * len(mode)):\n        palette.append(randint(0, 255))\n    return ImagePalette(mode, palette)\n\n\ndef sepia(white=\"#fff0c0\"):\n    r, g, b = ImageColor.getrgb(white)\n    r = make_linear_lut(0, r)\n    g = make_linear_lut(0, g)\n    b = make_linear_lut(0, b)\n    return ImagePalette(\"RGB\", r + g + b)\n\n\ndef wedge(mode=\"RGB\"):\n    return ImagePalette(mode, list(range(256)) * len(mode))\n\n\ndef load(filename):\n\n    # FIXME: supports GIMP gradients only\n\n    with open(filename, \"rb\") as fp:\n\n        for paletteHandler in [\n            GimpPaletteFile.GimpPaletteFile,\n            GimpGradientFile.GimpGradientFile,\n            PaletteFile.PaletteFile,\n        ]:\n            try:\n                fp.seek(0)\n                lut = paletteHandler(fp).getpalette()\n                if lut:\n                    break\n            except (SyntaxError, ValueError):\n                # import traceback\n                # traceback.print_exc()\n                pass\n        else:\n            raise OSError(\"cannot load palette\")\n\n    return lut  # data, rawmode\n",
            "new_file_content": "#\n# The Python Imaging Library.\n# $Id$\n#\n# image palette object\n#\n# History:\n# 1996-03-11 fl   Rewritten.\n# 1997-01-03 fl   Up and running.\n# 1997-08-23 fl   Added load hack\n# 2001-04-16 fl   Fixed randint shadow bug in random()\n#\n# Copyright (c) 1997-2001 by Secret Labs AB\n# Copyright (c) 1996-1997 by Fredrik Lundh\n#\n# See the README file for information on usage and redistribution.\n#\n\nimport array\nimport warnings\n\nfrom . import GimpGradientFile, GimpPaletteFile, ImageColor, PaletteFile\n\n\nclass ImagePalette:\n    \"\"\"\n    Color palette for palette mapped images\n\n    :param mode: The mode to use for the Palette. See:\n        :ref:`concept-modes`. Defaults to \"RGB\"\n    :param palette: An optional palette. If given, it must be a bytearray,\n        an array or a list of ints between 0-255. The list must be aligned\n        by channel (All R values must be contiguous in the list before G\n        and B values.) Defaults to 0 through 255 per channel.\n    :param size: An optional palette size. If given, an error is raised\n        if ``palette`` is not of equal length.\n    \"\"\"\n\n    def __init__(self, mode=\"RGB\", palette=None, size=0):\n        self.mode = mode\n        self.rawmode = None  # if set, palette contains raw data\n        self.palette = palette or bytearray()\n        self.dirty = None\n        if size != 0:\n            warnings.warn(\n                \"The size parameter is deprecated and will be removed in Pillow 10 \"\n                \"(2023-01-02).\",\n                DeprecationWarning,\n            )\n            if size != len(self.palette):\n                raise ValueError(\"wrong palette size\")\n\n    @property\n    def palette(self):\n        return self._palette\n\n    @palette.setter\n    def palette(self, palette):\n        self._palette = palette\n\n        mode_len = len(self.mode)\n        self.colors = {}\n        for i in range(0, len(self.palette), mode_len):\n            color = tuple(self.palette[i : i + mode_len])\n            if color in self.colors:\n                continue\n            self.colors[color] = i // mode_len\n\n    def copy(self):\n        new = ImagePalette()\n\n        new.mode = self.mode\n        new.rawmode = self.rawmode\n        if self.palette is not None:\n            new.palette = self.palette[:]\n        new.dirty = self.dirty\n\n        return new\n\n    def getdata(self):\n        \"\"\"\n        Get palette contents in format suitable for the low-level\n        ``im.putpalette`` primitive.\n\n        .. warning:: This method is experimental.\n        \"\"\"\n        if self.rawmode:\n            return self.rawmode, self.palette\n        return self.mode, self.tobytes()\n\n    def tobytes(self):\n        \"\"\"Convert palette to bytes.\n\n        .. warning:: This method is experimental.\n        \"\"\"\n        if self.rawmode:\n            raise ValueError(\"palette contains raw palette data\")\n        if isinstance(self.palette, bytes):\n            return self.palette\n        arr = array.array(\"B\", self.palette)\n        return arr.tobytes()\n\n    # Declare tostring as an alias for tobytes\n    tostring = tobytes\n\n    def getcolor(self, color, image=None):\n        \"\"\"Given an rgb tuple, allocate palette entry.\n\n        .. warning:: This method is experimental.\n        \"\"\"\n        if self.rawmode:\n            raise ValueError(\"palette contains raw palette data\")\n        if isinstance(color, tuple):\n            if self.mode == \"RGB\":\n                if len(color) == 4 and color[3] == 255:\n                    color = color[:3]\n            elif self.mode == \"RGBA\":\n                if len(color) == 3:\n                    color += (255,)\n            try:\n                return self.colors[color]\n            except KeyError as e:\n                # allocate new color slot\n                if not isinstance(self.palette, bytearray):\n                    self._palette = bytearray(self.palette)\n                index = len(self.palette) // 3\n                special_colors = ()\n                if image:\n                    special_colors = (\n                        image.info.get(\"background\"),\n                        image.info.get(\"transparency\"),\n                    )\n                while index in special_colors:\n                    index += 1\n                if index >= 256:\n                    if image:\n                        # Search for an unused index\n                        for i, count in reversed(list(enumerate(image.histogram()))):\n                            if count == 0 and i not in special_colors:\n                                index = i\n                                break\n                    if index >= 256:\n                        raise ValueError(\"cannot allocate more than 256 colors\") from e\n                self.colors[color] = index\n                if index * 3 < len(self.palette):\n                    self._palette = (\n                        self.palette[: index * 3]\n                        + bytes(color)\n                        + self.palette[index * 3 + 3 :]\n                    )\n                else:\n                    self._palette += bytes(color)\n                self.dirty = 1\n                return index\n        else:\n            raise ValueError(f\"unknown color specifier: {repr(color)}\")\n\n    def save(self, fp):\n        \"\"\"Save palette to text file.\n\n        .. warning:: This method is experimental.\n        \"\"\"\n        if self.rawmode:\n            raise ValueError(\"palette contains raw palette data\")\n        if isinstance(fp, str):\n            fp = open(fp, \"w\")\n        fp.write(\"# Palette\\n\")\n        fp.write(f\"# Mode: {self.mode}\\n\")\n        for i in range(256):\n            fp.write(f\"{i}\")\n            for j in range(i * len(self.mode), (i + 1) * len(self.mode)):\n                try:\n                    fp.write(f\" {self.palette[j]}\")\n                except IndexError:\n                    fp.write(\" 0\")\n            fp.write(\"\\n\")\n        fp.close()\n\n\n# --------------------------------------------------------------------\n# Internal\n\n\ndef raw(rawmode, data):\n    palette = ImagePalette()\n    palette.rawmode = rawmode\n    palette.palette = data\n    palette.dirty = 1\n    return palette\n\n\n# --------------------------------------------------------------------\n# Factories\n\n\ndef make_linear_lut(black, white):\n    lut = []\n    if black == 0:\n        for i in range(256):\n            lut.append(white * i // 255)\n    else:\n        raise NotImplementedError  # FIXME\n    return lut\n\n\ndef make_gamma_lut(exp):\n    lut = []\n    for i in range(256):\n        lut.append(int(((i / 255.0) ** exp) * 255.0 + 0.5))\n    return lut\n\n\ndef negative(mode=\"RGB\"):\n    palette = list(range(256))\n    palette.reverse()\n    return ImagePalette(mode, palette * len(mode))\n\n\ndef random(mode=\"RGB\"):\n    from random import randint\n\n    palette = []\n    for i in range(256 * len(mode)):\n        palette.append(randint(0, 255))\n    return ImagePalette(mode, palette)\n\n\ndef sepia(white=\"#fff0c0\"):\n    r, g, b = ImageColor.getrgb(white)\n    r = make_linear_lut(0, r)\n    g = make_linear_lut(0, g)\n    b = make_linear_lut(0, b)\n    return ImagePalette(\"RGB\", r + g + b)\n\n\ndef wedge(mode=\"RGB\"):\n    return ImagePalette(mode, list(range(256)) * len(mode))\n\n\ndef load(filename):\n\n    # FIXME: supports GIMP gradients only\n\n    with open(filename, \"rb\") as fp:\n\n        for paletteHandler in [\n            GimpPaletteFile.GimpPaletteFile,\n            GimpGradientFile.GimpGradientFile,\n            PaletteFile.PaletteFile,\n        ]:\n            try:\n                fp.seek(0)\n                lut = paletteHandler(fp).getpalette()\n                if lut:\n                    break\n            except (SyntaxError, ValueError):\n                # import traceback\n                # traceback.print_exc()\n                pass\n        else:\n            raise OSError(\"cannot load palette\")\n\n    return lut  # data, rawmode\n",
            "header": {
                "file": {
                    "path": "src/PIL/ImagePalette.py"
                },
                "misc_line": null
            },
            "index_line": {
                "old_commit_hash": "214059f51",
                "new_commit_hash": "676e452bd",
                "mode": "100644"
            },
            "is_binary_file": false,
            "binary_line": null,
            "minus_file": {
                "path": "a/src/PIL/ImagePalette.py"
            },
            "plus_file": {
                "path": "b/src/PIL/ImagePalette.py"
            },
            "hunks": [
                {
                    "descriptor": {
                        "old_range": {
                            "start": 17,
                            "length": 6
                        },
                        "new_range": {
                            "start": 17,
                            "length": 7
                        },
                        "section": ""
                    },
                    "line_group": {
                        "all_lines": [
                            {
                                "content": "#",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "import array",
                                "type": "context"
                            },
                            {
                                "content": "import warnings",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "from . import GimpGradientFile, GimpPaletteFile, ImageColor, PaletteFile",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            }
                        ]
                    },
                    "modified_entities": [],
                    "added_entities": [
                        {
                            "file_name": "src/PIL/ImagePalette.py",
                            "type": "import",
                            "name": "warnings",
                            "content": "import warnings",
                            "ast_type_str": "Import",
                            "start_lineno": 20,
                            "end_lineno": 20,
                            "parent": null
                        }
                    ],
                    "deleted_entities": []
                },
                {
                    "descriptor": {
                        "old_range": {
                            "start": 40,
                            "length": 8
                        },
                        "new_range": {
                            "start": 41,
                            "length": 14
                        },
                        "section": "class ImagePalette:"
                    },
                    "line_group": {
                        "all_lines": [
                            {
                                "content": "        self.rawmode = None  # if set, palette contains raw data",
                                "type": "context"
                            },
                            {
                                "content": "        self.palette = palette or bytearray()",
                                "type": "context"
                            },
                            {
                                "content": "        self.dirty = None",
                                "type": "context"
                            },
                            {
                                "content": "        if size != 0 and size != len(self.palette):",
                                "type": "deleted"
                            },
                            {
                                "content": "            raise ValueError(\"wrong palette size\")",
                                "type": "deleted"
                            },
                            {
                                "content": "        if size != 0:",
                                "type": "added"
                            },
                            {
                                "content": "            warnings.warn(",
                                "type": "added"
                            },
                            {
                                "content": "                \"The size parameter is deprecated and will be removed in Pillow 10 \"",
                                "type": "added"
                            },
                            {
                                "content": "                \"(2023-01-02).\",",
                                "type": "added"
                            },
                            {
                                "content": "                DeprecationWarning,",
                                "type": "added"
                            },
                            {
                                "content": "            )",
                                "type": "added"
                            },
                            {
                                "content": "            if size != len(self.palette):",
                                "type": "added"
                            },
                            {
                                "content": "                raise ValueError(\"wrong palette size\")",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "    @property",
                                "type": "context"
                            },
                            {
                                "content": "    def palette(self):",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            }
                        ]
                    },
                    "modified_entities": [
                        {
                            "file_name": "src/PIL/ImagePalette.py",
                            "type": "method",
                            "name": "ImagePalette.__init__",
                            "content": "class ImagePalette:\n    \"\"\"\n    Color palette for palette mapped images\n\n    :param mode: The mode to use for the Palette. See:\n        :ref:`concept-modes`. Defaults to \"RGB\"\n    :param palette: An optional palette. If given, it must be a bytearray,\n        an array or a list of ints between 0-255. The list must be aligned\n        by channel (All R values must be contiguous in the list before G\n        and B values.) Defaults to 0 through 255 per channel.\n    :param size: An optional palette size. If given, an error is raised\n        if ``palette`` is not of equal length.\n    \"\"\"\n\n    def __init__(self, mode=\"RGB\", palette=None, size=0):\n        self.mode = mode\n        self.rawmode = None  # if set, palette contains raw data\n        self.palette = palette or bytearray()\n        self.dirty = None\n        if size != 0 and size != len(self.palette):\n            raise ValueError(\"wrong palette size\")\n\n    @property\n    def palette(self):\n        return self._palette\n\n    @palette.setter\n    def palette(self, palette):\n        self._palette = palette\n\n        mode_len = len(self.mode)\n        self.colors = {}\n        for i in range(0, len(self.palette), mode_len):\n            color = tuple(self.palette[i : i + mode_len])\n            if color in self.colors:\n                continue\n            self.colors[color] = i // mode_len\n\n    def copy(self):\n        new = ImagePalette()\n\n        new.mode = self.mode\n        new.rawmode = self.rawmode\n        if self.palette is not None:\n            new.palette = self.palette[:]\n        new.dirty = self.dirty\n\n        return new\n\n    def getdata(self):\n        \"\"\"\n        Get palette contents in format suitable for the low-level\n        ``im.putpalette`` primitive.\n\n        .. warning:: This method is experimental.\n        \"\"\"\n        if self.rawmode:\n            return self.rawmode, self.palette\n        return self.mode, self.tobytes()\n\n    def tobytes(self):\n        \"\"\"Convert palette to bytes.\n\n        .. warning:: This method is experimental.\n        \"\"\"\n        if self.rawmode:\n            raise ValueError(\"palette contains raw palette data\")\n        if isinstance(self.palette, bytes):\n            return self.palette\n        arr = array.array(\"B\", self.palette)\n        return arr.tobytes()\n\n    # Declare tostring as an alias for tobytes\n    tostring = tobytes\n\n    def getcolor(self, color, image=None):\n        \"\"\"Given an rgb tuple, allocate palette entry.\n\n        .. warning:: This method is experimental.\n        \"\"\"\n        if self.rawmode:\n            raise ValueError(\"palette contains raw palette data\")\n        if isinstance(color, tuple):\n            if self.mode == \"RGB\":\n                if len(color) == 4 and color[3] == 255:\n                    color = color[:3]\n            elif self.mode == \"RGBA\":\n                if len(color) == 3:\n                    color += (255,)\n            try:\n                return self.colors[color]\n            except KeyError as e:\n                # allocate new color slot\n                if not isinstance(self.palette, bytearray):\n                    self._palette = bytearray(self.palette)\n                index = len(self.palette) // 3\n                special_colors = ()\n                if image:\n                    special_colors = (\n                        image.info.get(\"background\"),\n                        image.info.get(\"transparency\"),\n                    )\n                while index in special_colors:\n                    index += 1\n                if index >= 256:\n                    if image:\n                        # Search for an unused index\n                        for i, count in reversed(list(enumerate(image.histogram()))):\n                            if count == 0 and i not in special_colors:\n                                index = i\n                                break\n                    if index >= 256:\n                        raise ValueError(\"cannot allocate more than 256 colors\") from e\n                self.colors[color] = index\n                if index * 3 < len(self.palette):\n                    self._palette = (\n                        self.palette[: index * 3]\n                        + bytes(color)\n                        + self.palette[index * 3 + 3 :]\n                    )\n                else:\n                    self._palette += bytes(color)\n                self.dirty = 1\n                return index\n        else:\n            raise ValueError(f\"unknown color specifier: {repr(color)}\")\n\n    def save(self, fp):\n        \"\"\"Save palette to text file.\n\n        .. warning:: This method is experimental.\n        \"\"\"\n        if self.rawmode:\n            raise ValueError(\"palette contains raw palette data\")\n        if isinstance(fp, str):\n            fp = open(fp, \"w\")\n        fp.write(\"# Palette\\n\")\n        fp.write(f\"# Mode: {self.mode}\\n\")\n        for i in range(256):\n            fp.write(f\"{i}\")\n            for j in range(i * len(self.mode), (i + 1) * len(self.mode)):\n                try:\n                    fp.write(f\" {self.palette[j]}\")\n                except IndexError:\n                    fp.write(\" 0\")\n            fp.write(\"\\n\")\n        fp.close()",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 38,
                            "end_lineno": 44,
                            "parent": {
                                "file_name": "src/PIL/ImagePalette.py",
                                "type": "class",
                                "name": "ImagePalette",
                                "content": "class ImagePalette:\n    \"\"\"\n    Color palette for palette mapped images\n\n    :param mode: The mode to use for the Palette. See:\n        :ref:`concept-modes`. Defaults to \"RGB\"\n    :param palette: An optional palette. If given, it must be a bytearray,\n        an array or a list of ints between 0-255. The list must be aligned\n        by channel (All R values must be contiguous in the list before G\n        and B values.) Defaults to 0 through 255 per channel.\n    :param size: An optional palette size. If given, an error is raised\n        if ``palette`` is not of equal length.\n    \"\"\"\n\n    def __init__(self, mode=\"RGB\", palette=None, size=0):\n        self.mode = mode\n        self.rawmode = None  # if set, palette contains raw data\n        self.palette = palette or bytearray()\n        self.dirty = None\n        if size != 0 and size != len(self.palette):\n            raise ValueError(\"wrong palette size\")\n\n    @property\n    def palette(self):\n        return self._palette\n\n    @palette.setter\n    def palette(self, palette):\n        self._palette = palette\n\n        mode_len = len(self.mode)\n        self.colors = {}\n        for i in range(0, len(self.palette), mode_len):\n            color = tuple(self.palette[i : i + mode_len])\n            if color in self.colors:\n                continue\n            self.colors[color] = i // mode_len\n\n    def copy(self):\n        new = ImagePalette()\n\n        new.mode = self.mode\n        new.rawmode = self.rawmode\n        if self.palette is not None:\n            new.palette = self.palette[:]\n        new.dirty = self.dirty\n\n        return new\n\n    def getdata(self):\n        \"\"\"\n        Get palette contents in format suitable for the low-level\n        ``im.putpalette`` primitive.\n\n        .. warning:: This method is experimental.\n        \"\"\"\n        if self.rawmode:\n            return self.rawmode, self.palette\n        return self.mode, self.tobytes()\n\n    def tobytes(self):\n        \"\"\"Convert palette to bytes.\n\n        .. warning:: This method is experimental.\n        \"\"\"\n        if self.rawmode:\n            raise ValueError(\"palette contains raw palette data\")\n        if isinstance(self.palette, bytes):\n            return self.palette\n        arr = array.array(\"B\", self.palette)\n        return arr.tobytes()\n\n    # Declare tostring as an alias for tobytes\n    tostring = tobytes\n\n    def getcolor(self, color, image=None):\n        \"\"\"Given an rgb tuple, allocate palette entry.\n\n        .. warning:: This method is experimental.\n        \"\"\"\n        if self.rawmode:\n            raise ValueError(\"palette contains raw palette data\")\n        if isinstance(color, tuple):\n            if self.mode == \"RGB\":\n                if len(color) == 4 and color[3] == 255:\n                    color = color[:3]\n            elif self.mode == \"RGBA\":\n                if len(color) == 3:\n                    color += (255,)\n            try:\n                return self.colors[color]\n            except KeyError as e:\n                # allocate new color slot\n                if not isinstance(self.palette, bytearray):\n                    self._palette = bytearray(self.palette)\n                index = len(self.palette) // 3\n                special_colors = ()\n                if image:\n                    special_colors = (\n                        image.info.get(\"background\"),\n                        image.info.get(\"transparency\"),\n                    )\n                while index in special_colors:\n                    index += 1\n                if index >= 256:\n                    if image:\n                        # Search for an unused index\n                        for i, count in reversed(list(enumerate(image.histogram()))):\n                            if count == 0 and i not in special_colors:\n                                index = i\n                                break\n                    if index >= 256:\n                        raise ValueError(\"cannot allocate more than 256 colors\") from e\n                self.colors[color] = index\n                if index * 3 < len(self.palette):\n                    self._palette = (\n                        self.palette[: index * 3]\n                        + bytes(color)\n                        + self.palette[index * 3 + 3 :]\n                    )\n                else:\n                    self._palette += bytes(color)\n                self.dirty = 1\n                return index\n        else:\n            raise ValueError(f\"unknown color specifier: {repr(color)}\")\n\n    def save(self, fp):\n        \"\"\"Save palette to text file.\n\n        .. warning:: This method is experimental.\n        \"\"\"\n        if self.rawmode:\n            raise ValueError(\"palette contains raw palette data\")\n        if isinstance(fp, str):\n            fp = open(fp, \"w\")\n        fp.write(\"# Palette\\n\")\n        fp.write(f\"# Mode: {self.mode}\\n\")\n        for i in range(256):\n            fp.write(f\"{i}\")\n            for j in range(i * len(self.mode), (i + 1) * len(self.mode)):\n                try:\n                    fp.write(f\" {self.palette[j]}\")\n                except IndexError:\n                    fp.write(\" 0\")\n            fp.write(\"\\n\")\n        fp.close()",
                                "ast_type_str": "ClassDef",
                                "start_lineno": 24,
                                "end_lineno": 170,
                                "parent": null
                            }
                        },
                        {
                            "file_name": "src/PIL/ImagePalette.py",
                            "type": "class",
                            "name": "ImagePalette",
                            "content": "class ImagePalette:\n    \"\"\"\n    Color palette for palette mapped images\n\n    :param mode: The mode to use for the Palette. See:\n        :ref:`concept-modes`. Defaults to \"RGB\"\n    :param palette: An optional palette. If given, it must be a bytearray,\n        an array or a list of ints between 0-255. The list must be aligned\n        by channel (All R values must be contiguous in the list before G\n        and B values.) Defaults to 0 through 255 per channel.\n    :param size: An optional palette size. If given, an error is raised\n        if ``palette`` is not of equal length.\n    \"\"\"\n\n    def __init__(self, mode=\"RGB\", palette=None, size=0):\n        self.mode = mode\n        self.rawmode = None  # if set, palette contains raw data\n        self.palette = palette or bytearray()\n        self.dirty = None\n        if size != 0 and size != len(self.palette):\n            raise ValueError(\"wrong palette size\")\n\n    @property\n    def palette(self):\n        return self._palette\n\n    @palette.setter\n    def palette(self, palette):\n        self._palette = palette\n\n        mode_len = len(self.mode)\n        self.colors = {}\n        for i in range(0, len(self.palette), mode_len):\n            color = tuple(self.palette[i : i + mode_len])\n            if color in self.colors:\n                continue\n            self.colors[color] = i // mode_len\n\n    def copy(self):\n        new = ImagePalette()\n\n        new.mode = self.mode\n        new.rawmode = self.rawmode\n        if self.palette is not None:\n            new.palette = self.palette[:]\n        new.dirty = self.dirty\n\n        return new\n\n    def getdata(self):\n        \"\"\"\n        Get palette contents in format suitable for the low-level\n        ``im.putpalette`` primitive.\n\n        .. warning:: This method is experimental.\n        \"\"\"\n        if self.rawmode:\n            return self.rawmode, self.palette\n        return self.mode, self.tobytes()\n\n    def tobytes(self):\n        \"\"\"Convert palette to bytes.\n\n        .. warning:: This method is experimental.\n        \"\"\"\n        if self.rawmode:\n            raise ValueError(\"palette contains raw palette data\")\n        if isinstance(self.palette, bytes):\n            return self.palette\n        arr = array.array(\"B\", self.palette)\n        return arr.tobytes()\n\n    # Declare tostring as an alias for tobytes\n    tostring = tobytes\n\n    def getcolor(self, color, image=None):\n        \"\"\"Given an rgb tuple, allocate palette entry.\n\n        .. warning:: This method is experimental.\n        \"\"\"\n        if self.rawmode:\n            raise ValueError(\"palette contains raw palette data\")\n        if isinstance(color, tuple):\n            if self.mode == \"RGB\":\n                if len(color) == 4 and color[3] == 255:\n                    color = color[:3]\n            elif self.mode == \"RGBA\":\n                if len(color) == 3:\n                    color += (255,)\n            try:\n                return self.colors[color]\n            except KeyError as e:\n                # allocate new color slot\n                if not isinstance(self.palette, bytearray):\n                    self._palette = bytearray(self.palette)\n                index = len(self.palette) // 3\n                special_colors = ()\n                if image:\n                    special_colors = (\n                        image.info.get(\"background\"),\n                        image.info.get(\"transparency\"),\n                    )\n                while index in special_colors:\n                    index += 1\n                if index >= 256:\n                    if image:\n                        # Search for an unused index\n                        for i, count in reversed(list(enumerate(image.histogram()))):\n                            if count == 0 and i not in special_colors:\n                                index = i\n                                break\n                    if index >= 256:\n                        raise ValueError(\"cannot allocate more than 256 colors\") from e\n                self.colors[color] = index\n                if index * 3 < len(self.palette):\n                    self._palette = (\n                        self.palette[: index * 3]\n                        + bytes(color)\n                        + self.palette[index * 3 + 3 :]\n                    )\n                else:\n                    self._palette += bytes(color)\n                self.dirty = 1\n                return index\n        else:\n            raise ValueError(f\"unknown color specifier: {repr(color)}\")\n\n    def save(self, fp):\n        \"\"\"Save palette to text file.\n\n        .. warning:: This method is experimental.\n        \"\"\"\n        if self.rawmode:\n            raise ValueError(\"palette contains raw palette data\")\n        if isinstance(fp, str):\n            fp = open(fp, \"w\")\n        fp.write(\"# Palette\\n\")\n        fp.write(f\"# Mode: {self.mode}\\n\")\n        for i in range(256):\n            fp.write(f\"{i}\")\n            for j in range(i * len(self.mode), (i + 1) * len(self.mode)):\n                try:\n                    fp.write(f\" {self.palette[j]}\")\n                except IndexError:\n                    fp.write(\" 0\")\n            fp.write(\"\\n\")\n        fp.close()",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 24,
                            "end_lineno": 170,
                            "parent": null
                        }
                    ],
                    "added_entities": [],
                    "deleted_entities": []
                }
            ]
        }
    ],
    "old_commit_hash": "71b7f3daf388e7657f58bc05d2105dce0cdf12f0^",
    "new_commit_hash": "71b7f3daf388e7657f58bc05d2105dce0cdf12f0",
    "commit_message": "Merge pull request #5641 from radarhere/palette_size\n\nDeprecate ImagePalette size parameter",
    "commit_date": "2021-07-29T23:42:25Z",
    "metadata": {}
}
{
    "repo_name": "pillow",
    "new_commit_hash": "71b7f3daf388e7657f58bc05d2105dce0cdf12f0",
    "test_file_codes": [
        "import pytest\n\nfrom PIL import Image, ImagePalette\n\nfrom .helper import assert_image_equal, assert_image_equal_tofile\n\n\ndef test_sanity():\n\n    palette = ImagePalette.ImagePalette(\"RGB\", list(range(256)) * 3)\n    assert len(palette.colors) == 256\n\n    with pytest.warns(DeprecationWarning):\n        with pytest.raises(ValueError):\n            ImagePalette.ImagePalette(\"RGB\", list(range(256)) * 3, 10)\n\n\ndef test_reload():\n    im = Image.open(\"Tests/images/hopper.gif\")\n    original = im.copy()\n    im.palette.dirty = 1\n    assert_image_equal(im.convert(\"RGB\"), original.convert(\"RGB\"))\n\n\ndef test_getcolor():\n\n    palette = ImagePalette.ImagePalette()\n    assert len(palette.palette) == 0\n    assert len(palette.colors) == 0\n\n    test_map = {}\n    for i in range(256):\n        test_map[palette.getcolor((i, i, i))] = i\n    assert len(test_map) == 256\n\n    # Colors can be converted between RGB and RGBA\n    rgba_palette = ImagePalette.ImagePalette(\"RGBA\")\n    assert rgba_palette.getcolor((0, 0, 0)) == rgba_palette.getcolor((0, 0, 0, 255))\n\n    assert palette.getcolor((0, 0, 0)) == palette.getcolor((0, 0, 0, 255))\n\n    # An error is raised when the palette is full\n    with pytest.raises(ValueError):\n        palette.getcolor((1, 2, 3))\n    # But not if the image is not using one of the palette entries\n    palette.getcolor((1, 2, 3), image=Image.new(\"P\", (1, 1)))\n\n    # Test unknown color specifier\n    with pytest.raises(ValueError):\n        palette.getcolor(\"unknown\")\n\n\n@pytest.mark.parametrize(\n    \"index, palette\",\n    [\n        # Test when the palette is not full\n        (0, ImagePalette.ImagePalette()),\n        # Test when the palette is full\n        (255, ImagePalette.ImagePalette(\"RGB\", list(range(256)) * 3)),\n    ],\n)\ndef test_getcolor_not_special(index, palette):\n    im = Image.new(\"P\", (1, 1))\n\n    # Do not use transparency index as a new color\n    im.info[\"transparency\"] = index\n    index1 = palette.getcolor((0, 0, 0), im)\n    assert index1 != index\n\n    # Do not use background index as a new color\n    im.info[\"background\"] = index1\n    index2 = palette.getcolor((0, 0, 1), im)\n    assert index2 not in (index, index1)\n\n\ndef test_file(tmp_path):\n\n    palette = ImagePalette.ImagePalette(\"RGB\", list(range(256)) * 3)\n\n    f = str(tmp_path / \"temp.lut\")\n\n    palette.save(f)\n\n    p = ImagePalette.load(f)\n\n    # load returns raw palette information\n    assert len(p[0]) == 768\n    assert p[1] == \"RGB\"\n\n    p = ImagePalette.raw(p[1], p[0])\n    assert isinstance(p, ImagePalette.ImagePalette)\n    assert p.palette == palette.tobytes()\n\n\ndef test_make_linear_lut():\n    # Arrange\n    black = 0\n    white = 255\n\n    # Act\n    lut = ImagePalette.make_linear_lut(black, white)\n\n    # Assert\n    assert isinstance(lut, list)\n    assert len(lut) == 256\n    # Check values\n    for i in range(0, len(lut)):\n        assert lut[i] == i\n\n\ndef test_make_linear_lut_not_yet_implemented():\n    # Update after FIXME\n    # Arrange\n    black = 1\n    white = 255\n\n    # Act\n    with pytest.raises(NotImplementedError):\n        ImagePalette.make_linear_lut(black, white)\n\n\ndef test_make_gamma_lut():\n    # Arrange\n    exp = 5\n\n    # Act\n    lut = ImagePalette.make_gamma_lut(exp)\n\n    # Assert\n    assert isinstance(lut, list)\n    assert len(lut) == 256\n    # Check a few values\n    assert lut[0] == 0\n    assert lut[63] == 0\n    assert lut[127] == 8\n    assert lut[191] == 60\n    assert lut[255] == 255\n\n\ndef test_rawmode_valueerrors(tmp_path):\n    # Arrange\n    palette = ImagePalette.raw(\"RGB\", list(range(256)) * 3)\n\n    # Act / Assert\n    with pytest.raises(ValueError):\n        palette.tobytes()\n    with pytest.raises(ValueError):\n        palette.getcolor((1, 2, 3))\n    f = str(tmp_path / \"temp.lut\")\n    with pytest.raises(ValueError):\n        palette.save(f)\n\n\ndef test_getdata():\n    # Arrange\n    data_in = list(range(256)) * 3\n    palette = ImagePalette.ImagePalette(\"RGB\", data_in)\n\n    # Act\n    mode, data_out = palette.getdata()\n\n    # Assert\n    assert mode == \"RGB\"\n\n\ndef test_rawmode_getdata():\n    # Arrange\n    data_in = list(range(256)) * 3\n    palette = ImagePalette.raw(\"RGB\", data_in)\n\n    # Act\n    rawmode, data_out = palette.getdata()\n\n    # Assert\n    assert rawmode == \"RGB\"\n    assert data_in == data_out\n\n\ndef test_2bit_palette(tmp_path):\n    # issue #2258, 2 bit palettes are corrupted.\n    outfile = str(tmp_path / \"temp.png\")\n\n    rgb = b\"\\x00\" * 2 + b\"\\x01\" * 2 + b\"\\x02\" * 2\n    img = Image.frombytes(\"P\", (6, 1), rgb)\n    img.putpalette(b\"\\xFF\\x00\\x00\\x00\\xFF\\x00\\x00\\x00\\xFF\")  # RGB\n    img.save(outfile, format=\"PNG\")\n\n    assert_image_equal_tofile(img, outfile)\n\n\ndef test_invalid_palette():\n    with pytest.raises(OSError):\n        ImagePalette.load(\"Tests/images/hopper.jpg\")\n"
    ],
    "test_file_names": [
        "test_1.py"
    ],
    "setup_res_code": 0,
    "setup_res_stdout": "Starting Pillow installation attempts...\nVerifying Pillow installation...\n✅ Pillow installation successful!\nSuccessfully installed Pillow\n",
    "setup_res_stderr": "Using CPython 3.9.21\nCreating virtual environment at: .venv\nActivate with: source .venv/bin/activate\nResolved 12 packages in 10ms\nInstalled 12 packages in 174ms\n + coverage==7.6.10\n + exceptiongroup==1.2.2\n + iniconfig==2.0.0\n + packaging==24.2\n + pluggy==1.5.0\n + pyqt5==5.15.11\n + pyqt5-qt5==5.15.16\n + pyqt5-sip==12.16.1\n + pytest==8.3.4\n + pytest-cov==6.0.0\n + setuptools==75.8.0\n + tomli==2.2.1\nResolved 1 package in 774ms\nPrepared 1 package in 32.53s\nInstalled 1 package in 1ms\n + pillow==8.4.0.dev0 (from file:///home/gcpuser/buckets/local_repoeval_bucket/repos/pillow_71b7f3daf388e7657f58bc05d2105dce0cdf12f0)\n",
    "new_commit_res_code": 0,
    "new_commit_res_stdout": "\u001b[1m============================= test session starts ==============================\u001b[0m\nplatform linux -- Python 3.9.21, pytest-8.3.4, pluggy-1.5.0\nrootdir: /home/gcpuser/buckets/local_repoeval_bucket/repos/pillow_71b7f3daf388e7657f58bc05d2105dce0cdf12f0\nconfigfile: setup.cfg\nplugins: cov-6.0.0\ncollected 14 items\n\nr2e_tests/test_1.py \u001b[32m.\u001b[0m\u001b[32m.\u001b[0m\u001b[32m.\u001b[0m\u001b[32m.\u001b[0m\u001b[32m.\u001b[0m\u001b[32m.\u001b[0m\u001b[32m.\u001b[0m\u001b[32m.\u001b[0m\u001b[32m.\u001b[0m\u001b[32m.\u001b[0m\u001b[32m.\u001b[0m\u001b[32m.\u001b[0m\u001b[32m.\u001b[0m\u001b[32m.\u001b[0m\u001b[32m                                       [100%]\u001b[0m\n\n==================================== PASSES ====================================\n\u001b[36m\u001b[1m=========================== short test summary info ============================\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mtest_sanity\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mtest_reload\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mtest_getcolor\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mtest_getcolor_not_special[0-palette0]\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mtest_getcolor_not_special[255-palette1]\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mtest_file\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mtest_make_linear_lut\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mtest_make_linear_lut_not_yet_implemented\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mtest_make_gamma_lut\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mtest_rawmode_valueerrors\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mtest_getdata\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mtest_rawmode_getdata\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mtest_2bit_palette\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mtest_invalid_palette\u001b[0m\n\u001b[32m============================== \u001b[32m\u001b[1m14 passed\u001b[0m\u001b[32m in 0.11s\u001b[0m\u001b[32m ==============================\u001b[0m\n",
    "new_commit_res_stderr": "",
    "old_commit_res_code": 1,
    "old_commit_res_stdout": "\u001b[1m============================= test session starts ==============================\u001b[0m\nplatform linux -- Python 3.9.21, pytest-8.3.4, pluggy-1.5.0\nrootdir: /home/gcpuser/buckets/local_repoeval_bucket/repos/pillow_71b7f3daf388e7657f58bc05d2105dce0cdf12f0\nconfigfile: setup.cfg\nplugins: cov-6.0.0\ncollected 14 items\n\nr2e_tests/test_1.py \u001b[31mF\u001b[0m\u001b[32m.\u001b[0m\u001b[32m.\u001b[0m\u001b[32m.\u001b[0m\u001b[32m.\u001b[0m\u001b[32m.\u001b[0m\u001b[32m.\u001b[0m\u001b[32m.\u001b[0m\u001b[32m.\u001b[0m\u001b[32m.\u001b[0m\u001b[32m.\u001b[0m\u001b[32m.\u001b[0m\u001b[32m.\u001b[0m\u001b[32m.\u001b[0m\u001b[31m                                       [100%]\u001b[0m\n\n=================================== FAILURES ===================================\n\u001b[31m\u001b[1m_________________________________ test_sanity __________________________________\u001b[0m\n\n    def test_sanity():\n    \n        palette = ImagePalette.ImagePalette(\"RGB\", list(range(256)) * 3)\n        assert len(palette.colors) == 256\n    \n        with pytest.warns(DeprecationWarning):\n            with pytest.raises(ValueError):\n>               ImagePalette.ImagePalette(\"RGB\", list(range(256)) * 3, 10)\n\u001b[1m\u001b[31mE               Failed: DID NOT WARN. No warnings of type (<class 'DeprecationWarning'>,) were emitted.\u001b[0m\n\u001b[1m\u001b[31mE                Emitted warnings: [].\u001b[0m\n\n\u001b[1m\u001b[31mr2e_tests/test_1.py\u001b[0m:15: Failed\n==================================== PASSES ====================================\n\u001b[36m\u001b[1m=========================== short test summary info ============================\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mtest_reload\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mtest_getcolor\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mtest_getcolor_not_special[0-palette0]\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mtest_getcolor_not_special[255-palette1]\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mtest_file\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mtest_make_linear_lut\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mtest_make_linear_lut_not_yet_implemented\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mtest_make_gamma_lut\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mtest_rawmode_valueerrors\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mtest_getdata\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mtest_rawmode_getdata\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mtest_2bit_palette\u001b[0m\n\u001b[32mPASSED\u001b[0m r2e_tests/test_1.py::\u001b[1mtest_invalid_palette\u001b[0m\n\u001b[31mFAILED\u001b[0m r2e_tests/test_1.py::\u001b[1mtest_sanity\u001b[0m - Failed: DID NOT WARN. No warnings of type (<class 'DeprecationWarning'>,) w...\n\u001b[31m========================= \u001b[31m\u001b[1m1 failed\u001b[0m, \u001b[32m13 passed\u001b[0m\u001b[31m in 0.09s\u001b[0m\u001b[31m =========================\u001b[0m\n",
    "old_commit_res_stderr": ""
}
Tests/test_imagepalette.py docs/deprecations.rst src/PIL/ImagePalette.py
We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
[ISSUE]
**Title:** Missing DeprecationWarning When Using `size` Parameter in ImagePalette

**Description:**
When initializing the `ImagePalette` class with the `size` parameter, no `DeprecationWarning` is emitted. This omission prevents users from being aware that the `size` parameter is deprecated and will be removed in future versions.

**Example Code:**
```python
from PIL import ImagePalette

# Initializing ImagePalette with the deprecated 'size' parameter
palette = ImagePalette.ImagePalette("RGB", list(range(256)) * 3, 10)
```

**Expected Behavior:**
A `DeprecationWarning` should be displayed, informing the user that the `size` parameter is deprecated and will be removed in Pillow 10 (scheduled for release on 2023-01-02).

**Actual Behavior:**
No warning is emitted, leaving users unaware of the deprecation, which may lead to issues when the parameter is eventually removed.

[/ISSUE]
--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.

--- BEGIN FILE ---
```
### src/PIL/ImagePalette.py
#
# The Python Imaging Library.
# $Id$
#
# image palette object
#
# History:
# 1996-03-11 fl   Rewritten.
# 1997-01-03 fl   Up and running.
# 1997-08-23 fl   Added load hack
# 2001-04-16 fl   Fixed randint shadow bug in random()
#
# Copyright (c) 1997-2001 by Secret Labs AB
# Copyright (c) 1996-1997 by Fredrik Lundh
#
# See the README file for information on usage and redistribution.
#

import array

from . import GimpGradientFile, GimpPaletteFile, ImageColor, PaletteFile


class ImagePalette:
    """
    Color palette for palette mapped images

    :param mode: The mode to use for the Palette. See:
        :ref:`concept-modes`. Defaults to "RGB"
    :param palette: An optional palette. If given, it must be a bytearray,
        an array or a list of ints between 0-255. The list must be aligned
        by channel (All R values must be contiguous in the list before G
        and B values.) Defaults to 0 through 255 per channel.
    :param size: An optional palette size. If given, an error is raised
        if ``palette`` is not of equal length.
    """

    def __init__(self, mode="RGB", palette=None, size=0):
        self.mode = mode
        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")

    @property
    def palette(self):
        return self._palette

    @palette.setter
    def palette(self, palette):
        self._palette = palette

        mode_len = len(self.mode)
        self.colors = {}
        for i in range(0, len(self.palette), mode_len):
            color = tuple(self.palette[i : i + mode_len])
            if color in self.colors:
                continue
            self.colors[color] = i // mode_len

    def copy(self):
        new = ImagePalette()

        new.mode = self.mode
        new.rawmode = self.rawmode
        if self.palette is not None:
            new.palette = self.palette[:]
        new.dirty = self.dirty

        return new

    def getdata(self):
        """
        Get palette contents in format suitable for the low-level
        ``im.putpalette`` primitive.

        .. warning:: This method is experimental.
        """
        if self.rawmode:
            return self.rawmode, self.palette
        return self.mode, self.tobytes()

    def tobytes(self):
        """Convert palette to bytes.

        .. warning:: This method is experimental.
        """
        if self.rawmode:
            raise ValueError("palette contains raw palette data")
        if isinstance(self.palette, bytes):
            return self.palette
        arr = array.array("B", self.palette)
        return arr.tobytes()

    # Declare tostring as an alias for tobytes
    tostring = tobytes

    def getcolor(self, color, image=None):
        """Given an rgb tuple, allocate palette entry.

        .. warning:: This method is experimental.
        """
        if self.rawmode:
            raise ValueError("palette contains raw palette data")
        if isinstance(color, tuple):
            if self.mode == "RGB":
                if len(color) == 4 and color[3] == 255:
                    color = color[:3]
            elif self.mode == "RGBA":
                if len(color) == 3:
                    color += (255,)
            try:
                return self.colors[color]
            except KeyError as e:
                # allocate new color slot
                if not isinstance(self.palette, bytearray):
                    self._palette = bytearray(self.palette)
                index = len(self.palette) // 3
                special_colors = ()
                if image:
                    special_colors = (
                        image.info.get("background"),
                        image.info.get("transparency"),
                    )
                while index in special_colors:
                    index += 1
                if index >= 256:
                    if image:
                        # Search for an unused index
                        for i, count in reversed(list(enumerate(image.histogram()))):
                            if count == 0 and i not in special_colors:
                                index = i
                                break
                    if index >= 256:
                        raise ValueError("cannot allocate more than 256 colors") from e
                self.colors[color] = index
                if index * 3 < len(self.palette):
                    self._palette = (
                        self.palette[: index * 3]
                        + bytes(color)
                        + self.palette[index * 3 + 3 :]
                    )
                else:
                    self._palette += bytes(color)
                self.dirty = 1
                return index
        else:
            raise ValueError(f"unknown color specifier: {repr(color)}")

    def save(self, fp):
        """Save palette to text file.

        .. warning:: This method is experimental.
        """
        if self.rawmode:
            raise ValueError("palette contains raw palette data")
        if isinstance(fp, str):
            fp = open(fp, "w")
        fp.write("# Palette\n")
        fp.write(f"# Mode: {self.mode}\n")
        for i in range(256):
            fp.write(f"{i}")
            for j in range(i * len(self.mode), (i + 1) * len(self.mode)):
                try:
                    fp.write(f" {self.palette[j]}")
                except IndexError:
                    fp.write(" 0")
            fp.write("\n")
        fp.close()


# --------------------------------------------------------------------
# Internal


def raw(rawmode, data):
    palette = ImagePalette()
    palette.rawmode = rawmode
    palette.palette = data
    palette.dirty = 1
    return palette


# --------------------------------------------------------------------
# Factories


def make_linear_lut(black, white):
    lut = []
    if black == 0:
        for i in range(256):
            lut.append(white * i // 255)
    else:
        raise NotImplementedError  # FIXME
    return lut


def make_gamma_lut(exp):
    lut = []
    for i in range(256):
        lut.append(int(((i / 255.0) ** exp) * 255.0 + 0.5))
    return lut


def negative(mode="RGB"):
    palette = list(range(256))
    palette.reverse()
    return ImagePalette(mode, palette * len(mode))


def random(mode="RGB"):
    from random import randint

    palette = []
    for i in range(256 * len(mode)):
        palette.append(randint(0, 255))
    return ImagePalette(mode, palette)


def sepia(white="#fff0c0"):
    r, g, b = ImageColor.getrgb(white)
    r = make_linear_lut(0, r)
    g = make_linear_lut(0, g)
    b = make_linear_lut(0, b)
    return ImagePalette("RGB", r + g + b)


def wedge(mode="RGB"):
    return ImagePalette(mode, list(range(256)) * len(mode))


def load(filename):

    # FIXME: supports GIMP gradients only

    with open(filename, "rb") as fp:

        for paletteHandler in [
            GimpPaletteFile.GimpPaletteFile,
            GimpGradientFile.GimpGradientFile,
            PaletteFile.PaletteFile,
        ]:
            try:
                fp.seek(0)
                lut = paletteHandler(fp).getpalette()
                if lut:
                    break
            except (SyntaxError, ValueError):
                # import traceback
                # traceback.print_exc()
                pass
        else:
            raise OSError("cannot load palette")

    return lut  # data, rawmode

```
--- END FILE ---

Please first localize the bug based on the issue statement, and then generate *SEARCH/REPLACE* edits to fix the issue.

Every *SEARCH/REPLACE* edit must use this format:
1. The file path
2. The start of search block: <<<<<<< SEARCH
3. A contiguous chunk of lines to search for in the existing source code
4. The dividing line: =======
5. The lines to replace into the source code
6. The end of the replace block: >>>>>>> REPLACE

Here is an example:

```python
### mathweb/flask/app.py
<<<<<<< SEARCH
from flask import Flask
=======
import math
from flask import Flask
>>>>>>> REPLACE
```
</solution>

Please note that the *SEARCH/REPLACE* edit REQUIRES PROPER INDENTATION. If you would like to add the line '        print(x)', you must fully write that out, with all those spaces before the code!
Wrap each *SEARCH/REPLACE* edit in a code block as shown in the example above. If you have multiple *SEARCH/REPLACE* edits, use a separate code block for each one.
[ISSUE]
**Title:** Missing DeprecationWarning When Using `size` Parameter in ImagePalette

**Description:**
When initializing the `ImagePalette` class with the `size` parameter, no `DeprecationWarning` is emitted. This omission prevents users from being aware that the `size` parameter is deprecated and will be removed in future versions.

**Example Code:**
```python
from PIL import ImagePalette

# Initializing ImagePalette with the deprecated 'size' parameter
palette = ImagePalette.ImagePalette("RGB", list(range(256)) * 3, 10)
```

**Expected Behavior:**
A `DeprecationWarning` should be displayed, informing the user that the `size` parameter is deprecated and will be removed in Pillow 10 (scheduled for release on 2023-01-02).

**Actual Behavior:**
No warning is emitted, leaving users unaware of the deprecation, which may lead to issues when the parameter is eventually removed.

[/ISSUE]
{
    "\u001b[1mtest_sanity\u001b[0m": "PASSED",
    "\u001b[1mtest_reload\u001b[0m": "PASSED",
    "\u001b[1mtest_getcolor\u001b[0m": "PASSED",
    "\u001b[1mtest_getcolor_not_special[0-palette0]\u001b[0m": "PASSED",
    "\u001b[1mtest_getcolor_not_special[255-palette1]\u001b[0m": "PASSED",
    "\u001b[1mtest_file\u001b[0m": "PASSED",
    "\u001b[1mtest_make_linear_lut\u001b[0m": "PASSED",
    "\u001b[1mtest_make_linear_lut_not_yet_implemented\u001b[0m": "PASSED",
    "\u001b[1mtest_make_gamma_lut\u001b[0m": "PASSED",
    "\u001b[1mtest_rawmode_valueerrors\u001b[0m": "PASSED",
    "\u001b[1mtest_getdata\u001b[0m": "PASSED",
    "\u001b[1mtest_rawmode_getdata\u001b[0m": "PASSED",
    "\u001b[1mtest_2bit_palette\u001b[0m": "PASSED",
    "\u001b[1mtest_invalid_palette\u001b[0m": "PASSED"
}
diff --git a/src/PIL/ImagePalette.py b/src/PIL/ImagePalette.py
index 214059f51..676e452bd 100644
--- 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 @@ class ImagePalette:
         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):
 

{"src/PIL/ImagePalette.py": "#\n# The Python Imaging Library.\n# $Id$\n#\n# image palette object\n#\n# History:\n# 1996-03-11 fl   Rewritten.\n# 1997-01-03 fl   Up and running.\n# 1997-08-23 fl   Added load hack\n# 2001-04-16 fl   Fixed randint shadow bug in random()\n#\n# Copyright (c) 1997-2001 by Secret Labs AB\n# Copyright (c) 1996-1997 by Fredrik Lundh\n#\n# See the README file for information on usage and redistribution.\n#\n\nimport array\n\nfrom . import GimpGradientFile, GimpPaletteFile, ImageColor, PaletteFile\n\n\nclass ImagePalette:\n    \"\"\"\n    Color palette for palette mapped images\n\n    :param mode: The mode to use for the Palette. See:\n        :ref:`concept-modes`. Defaults to \"RGB\"\n    :param palette: An optional palette. If given, it must be a bytearray,\n        an array or a list of ints between 0-255. The list must be aligned\n        by channel (All R values must be contiguous in the list before G\n        and B values.) Defaults to 0 through 255 per channel.\n    :param size: An optional palette size. If given, an error is raised\n        if ``palette`` is not of equal length.\n    \"\"\"\n\n    def __init__(self, mode=\"RGB\", palette=None, size=0):\n        self.mode = mode\n        self.rawmode = None  # if set, palette contains raw data\n        self.palette = palette or bytearray()\n        self.dirty = None\n        if size != 0 and size != len(self.palette):\n            raise ValueError(\"wrong palette size\")\n\n    @property\n    def palette(self):\n        return self._palette\n\n    @palette.setter\n    def palette(self, palette):\n        self._palette = palette\n\n        mode_len = len(self.mode)\n        self.colors = {}\n        for i in range(0, len(self.palette), mode_len):\n            color = tuple(self.palette[i : i + mode_len])\n            if color in self.colors:\n                continue\n            self.colors[color] = i // mode_len\n\n    def copy(self):\n        new = ImagePalette()\n\n        new.mode = self.mode\n        new.rawmode = self.rawmode\n        if self.palette is not None:\n            new.palette = self.palette[:]\n        new.dirty = self.dirty\n\n        return new\n\n    def getdata(self):\n        \"\"\"\n        Get palette contents in format suitable for the low-level\n        ``im.putpalette`` primitive.\n\n        .. warning:: This method is experimental.\n        \"\"\"\n        if self.rawmode:\n            return self.rawmode, self.palette\n        return self.mode, self.tobytes()\n\n    def tobytes(self):\n        \"\"\"Convert palette to bytes.\n\n        .. warning:: This method is experimental.\n        \"\"\"\n        if self.rawmode:\n            raise ValueError(\"palette contains raw palette data\")\n        if isinstance(self.palette, bytes):\n            return self.palette\n        arr = array.array(\"B\", self.palette)\n        return arr.tobytes()\n\n    # Declare tostring as an alias for tobytes\n    tostring = tobytes\n\n    def getcolor(self, color, image=None):\n        \"\"\"Given an rgb tuple, allocate palette entry.\n\n        .. warning:: This method is experimental.\n        \"\"\"\n        if self.rawmode:\n            raise ValueError(\"palette contains raw palette data\")\n        if isinstance(color, tuple):\n            if self.mode == \"RGB\":\n                if len(color) == 4 and color[3] == 255:\n                    color = color[:3]\n            elif self.mode == \"RGBA\":\n                if len(color) == 3:\n                    color += (255,)\n            try:\n                return self.colors[color]\n            except KeyError as e:\n                # allocate new color slot\n                if not isinstance(self.palette, bytearray):\n                    self._palette = bytearray(self.palette)\n                index = len(self.palette) // 3\n                special_colors = ()\n                if image:\n                    special_colors = (\n                        image.info.get(\"background\"),\n                        image.info.get(\"transparency\"),\n                    )\n                while index in special_colors:\n                    index += 1\n                if index >= 256:\n                    if image:\n                        # Search for an unused index\n                        for i, count in reversed(list(enumerate(image.histogram()))):\n                            if count == 0 and i not in special_colors:\n                                index = i\n                                break\n                    if index >= 256:\n                        raise ValueError(\"cannot allocate more than 256 colors\") from e\n                self.colors[color] = index\n                if index * 3 < len(self.palette):\n                    self._palette = (\n                        self.palette[: index * 3]\n                        + bytes(color)\n                        + self.palette[index * 3 + 3 :]\n                    )\n                else:\n                    self._palette += bytes(color)\n                self.dirty = 1\n                return index\n        else:\n            raise ValueError(f\"unknown color specifier: {repr(color)}\")\n\n    def save(self, fp):\n        \"\"\"Save palette to text file.\n\n        .. warning:: This method is experimental.\n        \"\"\"\n        if self.rawmode:\n            raise ValueError(\"palette contains raw palette data\")\n        if isinstance(fp, str):\n            fp = open(fp, \"w\")\n        fp.write(\"# Palette\\n\")\n        fp.write(f\"# Mode: {self.mode}\\n\")\n        for i in range(256):\n            fp.write(f\"{i}\")\n            for j in range(i * len(self.mode), (i + 1) * len(self.mode)):\n                try:\n                    fp.write(f\" {self.palette[j]}\")\n                except IndexError:\n                    fp.write(\" 0\")\n            fp.write(\"\\n\")\n        fp.close()\n\n\n# --------------------------------------------------------------------\n# Internal\n\n\ndef raw(rawmode, data):\n    palette = ImagePalette()\n    palette.rawmode = rawmode\n    palette.palette = data\n    palette.dirty = 1\n    return palette\n\n\n# --------------------------------------------------------------------\n# Factories\n\n\ndef make_linear_lut(black, white):\n    lut = []\n    if black == 0:\n        for i in range(256):\n            lut.append(white * i // 255)\n    else:\n        raise NotImplementedError  # FIXME\n    return lut\n\n\ndef make_gamma_lut(exp):\n    lut = []\n    for i in range(256):\n        lut.append(int(((i / 255.0) ** exp) * 255.0 + 0.5))\n    return lut\n\n\ndef negative(mode=\"RGB\"):\n    palette = list(range(256))\n    palette.reverse()\n    return ImagePalette(mode, palette * len(mode))\n\n\ndef random(mode=\"RGB\"):\n    from random import randint\n\n    palette = []\n    for i in range(256 * len(mode)):\n        palette.append(randint(0, 255))\n    return ImagePalette(mode, palette)\n\n\ndef sepia(white=\"#fff0c0\"):\n    r, g, b = ImageColor.getrgb(white)\n    r = make_linear_lut(0, r)\n    g = make_linear_lut(0, g)\n    b = make_linear_lut(0, b)\n    return ImagePalette(\"RGB\", r + g + b)\n\n\ndef wedge(mode=\"RGB\"):\n    return ImagePalette(mode, list(range(256)) * len(mode))\n\n\ndef load(filename):\n\n    # FIXME: supports GIMP gradients only\n\n    with open(filename, \"rb\") as fp:\n\n        for paletteHandler in [\n            GimpPaletteFile.GimpPaletteFile,\n            GimpGradientFile.GimpGradientFile,\n            PaletteFile.PaletteFile,\n        ]:\n            try:\n                fp.seek(0)\n                lut = paletteHandler(fp).getpalette()\n                if lut:\n                    break\n            except (SyntaxError, ValueError):\n                # import traceback\n                # traceback.print_exc()\n                pass\n        else:\n            raise OSError(\"cannot load palette\")\n\n    return lut  # data, rawmode\n"}
A user will ask you to solve a task. You should first draft your thinking process (inner monologue). Then, generate the solution.

Your response format must follow the template below:
<think>
Your thoughts or/and draft, like working through an exercise on scratch paper. Be as casual and as long as you want until you are confident to generate a correct solution.
</think>
<solution>
Final solution presented to the user.
</solution>
system
We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
[ISSUE]
**Title:** Missing DeprecationWarning When Using `size` Parameter in ImagePalette

**Description:**
When initializing the `ImagePalette` class with the `size` parameter, no `DeprecationWarning` is emitted. This omission prevents users from being aware that the `size` parameter is deprecated and will be removed in future versions.

**Example Code:**
```python
from PIL import ImagePalette

# Initializing ImagePalette with the deprecated 'size' parameter
palette = ImagePalette.ImagePalette("RGB", list(range(256)) * 3, 10)
```

**Expected Behavior:**
A `DeprecationWarning` should be displayed, informing the user that the `size` parameter is deprecated and will be removed in Pillow 10 (scheduled for release on 2023-01-02).

**Actual Behavior:**
No warning is emitted, leaving users unaware of the deprecation, which may lead to issues when the parameter is eventually removed.

[/ISSUE]
--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.

--- BEGIN FILE ---
```
### src/PIL/ImagePalette.py
#
# The Python Imaging Library.
# $Id$
#
# image palette object
#
# History:
# 1996-03-11 fl   Rewritten.
# 1997-01-03 fl   Up and running.
# 1997-08-23 fl   Added load hack
# 2001-04-16 fl   Fixed randint shadow bug in random()
#
# Copyright (c) 1997-2001 by Secret Labs AB
# Copyright (c) 1996-1997 by Fredrik Lundh
#
# See the README file for information on usage and redistribution.
#

import array

from . import GimpGradientFile, GimpPaletteFile, ImageColor, PaletteFile


class ImagePalette:
    """
    Color palette for palette mapped images

    :param mode: The mode to use for the Palette. See:
        :ref:`concept-modes`. Defaults to "RGB"
    :param palette: An optional palette. If given, it must be a bytearray,
        an array or a list of ints between 0-255. The list must be aligned
        by channel (All R values must be contiguous in the list before G
        and B values.) Defaults to 0 through 255 per channel.
    :param size: An optional palette size. If given, an error is raised
        if ``palette`` is not of equal length.
    """

    def __init__(self, mode="RGB", palette=None, size=0):
        self.mode = mode
        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")

    @property
    def palette(self):
        return self._palette

    @palette.setter
    def palette(self, palette):
        self._palette = palette

        mode_len = len(self.mode)
        self.colors = {}
        for i in range(0, len(self.palette), mode_len):
            color = tuple(self.palette[i : i + mode_len])
            if color in self.colors:
                continue
            self.colors[color] = i // mode_len

    def copy(self):
        new = ImagePalette()

        new.mode = self.mode
        new.rawmode = self.rawmode
        if self.palette is not None:
            new.palette = self.palette[:]
        new.dirty = self.dirty

        return new

    def getdata(self):
        """
        Get palette contents in format suitable for the low-level
        ``im.putpalette`` primitive.

        .. warning:: This method is experimental.
        """
        if self.rawmode:
            return self.rawmode, self.palette
        return self.mode, self.tobytes()

    def tobytes(self):
        """Convert palette to bytes.

        .. warning:: This method is experimental.
        """
        if self.rawmode:
            raise ValueError("palette contains raw palette data")
        if isinstance(self.palette, bytes):
            return self.palette
        arr = array.array("B", self.palette)
        return arr.tobytes()

    # Declare tostring as an alias for tobytes
    tostring = tobytes

    def getcolor(self, color, image=None):
        """Given an rgb tuple, allocate palette entry.

        .. warning:: This method is experimental.
        """
        if self.rawmode:
            raise ValueError("palette contains raw palette data")
        if isinstance(color, tuple):
            if self.mode == "RGB":
                if len(color) == 4 and color[3] == 255:
                    color = color[:3]
            elif self.mode == "RGBA":
                if len(color) == 3:
                    color += (255,)
            try:
                return self.colors[color]
            except KeyError as e:
                # allocate new color slot
                if not isinstance(self.palette, bytearray):
                    self._palette = bytearray(self.palette)
                index = len(self.palette) // 3
                special_colors = ()
                if image:
                    special_colors = (
                        image.info.get("background"),
                        image.info.get("transparency"),
                    )
                while index in special_colors:
                    index += 1
                if index >= 256:
                    if image:
                        # Search for an unused index
                        for i, count in reversed(list(enumerate(image.histogram()))):
                            if count == 0 and i not in special_colors:
                                index = i
                                break
                    if index >= 256:
                        raise ValueError("cannot allocate more than 256 colors") from e
                self.colors[color] = index
                if index * 3 < len(self.palette):
                    self._palette = (
                        self.palette[: index * 3]
                        + bytes(color)
                        + self.palette[index * 3 + 3 :]
                    )
                else:
                    self._palette += bytes(color)
                self.dirty = 1
                return index
        else:
            raise ValueError(f"unknown color specifier: {repr(color)}")

    def save(self, fp):
        """Save palette to text file.

        .. warning:: This method is experimental.
        """
        if self.rawmode:
            raise ValueError("palette contains raw palette data")
        if isinstance(fp, str):
            fp = open(fp, "w")
        fp.write("# Palette\n")
        fp.write(f"# Mode: {self.mode}\n")
        for i in range(256):
            fp.write(f"{i}")
            for j in range(i * len(self.mode), (i + 1) * len(self.mode)):
                try:
                    fp.write(f" {self.palette[j]}")
                except IndexError:
                    fp.write(" 0")
            fp.write("\n")
        fp.close()


# --------------------------------------------------------------------
# Internal


def raw(rawmode, data):
    palette = ImagePalette()
    palette.rawmode = rawmode
    palette.palette = data
    palette.dirty = 1
    return palette


# --------------------------------------------------------------------
# Factories


def make_linear_lut(black, white):
    lut = []
    if black == 0:
        for i in range(256):
            lut.append(white * i // 255)
    else:
        raise NotImplementedError  # FIXME
    return lut


def make_gamma_lut(exp):
    lut = []
    for i in range(256):
        lut.append(int(((i / 255.0) ** exp) * 255.0 + 0.5))
    return lut


def negative(mode="RGB"):
    palette = list(range(256))
    palette.reverse()
    return ImagePalette(mode, palette * len(mode))


def random(mode="RGB"):
    from random import randint

    palette = []
    for i in range(256 * len(mode)):
        palette.append(randint(0, 255))
    return ImagePalette(mode, palette)


def sepia(white="#fff0c0"):
    r, g, b = ImageColor.getrgb(white)
    r = make_linear_lut(0, r)
    g = make_linear_lut(0, g)
    b = make_linear_lut(0, b)
    return ImagePalette("RGB", r + g + b)


def wedge(mode="RGB"):
    return ImagePalette(mode, list(range(256)) * len(mode))


def load(filename):

    # FIXME: supports GIMP gradients only

    with open(filename, "rb") as fp:

        for paletteHandler in [
            GimpPaletteFile.GimpPaletteFile,
            GimpGradientFile.GimpGradientFile,
            PaletteFile.PaletteFile,
        ]:
            try:
                fp.seek(0)
                lut = paletteHandler(fp).getpalette()
                if lut:
                    break
            except (SyntaxError, ValueError):
                # import traceback
                # traceback.print_exc()
                pass
        else:
            raise OSError("cannot load palette")

    return lut  # data, rawmode

```
--- END FILE ---

Please first localize the bug based on the issue statement, and then generate *SEARCH/REPLACE* edits to fix the issue.

Every *SEARCH/REPLACE* edit must use this format:
1. The file path
2. The start of search block: <<<<<<< SEARCH
3. A contiguous chunk of lines to search for in the existing source code
4. The dividing line: =======
5. The lines to replace into the source code
6. The end of the replace block: >>>>>>> REPLACE

Here is an example:

```python
### mathweb/flask/app.py
<<<<<<< SEARCH
from flask import Flask
=======
import math
from flask import Flask
>>>>>>> REPLACE
```
</solution>

Please note that the *SEARCH/REPLACE* edit REQUIRES PROPER INDENTATION. If you would like to add the line '        print(x)', you must fully write that out, with all those spaces before the code!
Wrap each *SEARCH/REPLACE* edit in a code block as shown in the example above. If you have multiple *SEARCH/REPLACE* edits, use a separate code block for each one.
user