{
    "file_diffs": [
        {
            "old_file_content": "from .helper import PillowTestCase\n\nfrom PIL import Image\n\n# sample ppm stream\ntest_file = \"Tests/images/hopper.ppm\"\n\n\nclass TestFilePpm(PillowTestCase):\n\n    def test_sanity(self):\n        im = Image.open(test_file)\n        im.load()\n        self.assertEqual(im.mode, \"RGB\")\n        self.assertEqual(im.size, (128, 128))\n        self.assertEqual(im.format, \"PPM\")\n\n    def test_16bit_pgm(self):\n        im = Image.open('Tests/images/16_bit_binary.pgm')\n        im.load()\n        self.assertEqual(im.mode, 'I')\n        self.assertEqual(im.size, (20, 100))\n\n        tgt = Image.open('Tests/images/16_bit_binary_pgm.png')\n        self.assert_image_equal(im, tgt)\n\n    def test_16bit_pgm_write(self):\n        im = Image.open('Tests/images/16_bit_binary.pgm')\n        im.load()\n\n        f = self.tempfile('temp.pgm')\n        im.save(f, 'PPM')\n\n        reloaded = Image.open(f)\n        self.assert_image_equal(im, reloaded)\n\n    def test_truncated_file(self):\n        path = self.tempfile('temp.pgm')\n        with open(path, 'w') as f:\n            f.write('P6')\n\n        self.assertRaises(ValueError, Image.open, path)\n\n    def test_neg_ppm(self):\n        # Storage.c accepted negative values for xsize, ysize.  the\n        # internal open_ppm function didn't check for sanity but it\n        # has been removed. The default opener doesn't accept negative\n        # sizes.\n\n        with self.assertRaises(IOError):\n            Image.open('Tests/images/negative_size.ppm')\n",
            "new_file_content": "from .helper import PillowTestCase\n\nfrom PIL import Image\n\n# sample ppm stream\ntest_file = \"Tests/images/hopper.ppm\"\n\n\nclass TestFilePpm(PillowTestCase):\n\n    def test_sanity(self):\n        im = Image.open(test_file)\n        im.load()\n        self.assertEqual(im.mode, \"RGB\")\n        self.assertEqual(im.size, (128, 128))\n        self.assertEqual(im.format, \"PPM\")\n        self.assertEqual(im.get_format_mimetype(), \"image/x-portable-pixmap\")\n\n    def test_16bit_pgm(self):\n        im = Image.open('Tests/images/16_bit_binary.pgm')\n        im.load()\n        self.assertEqual(im.mode, 'I')\n        self.assertEqual(im.size, (20, 100))\n        self.assertEqual(im.get_format_mimetype(), \"image/x-portable-graymap\")\n\n        tgt = Image.open('Tests/images/16_bit_binary_pgm.png')\n        self.assert_image_equal(im, tgt)\n\n    def test_16bit_pgm_write(self):\n        im = Image.open('Tests/images/16_bit_binary.pgm')\n        im.load()\n\n        f = self.tempfile('temp.pgm')\n        im.save(f, 'PPM')\n\n        reloaded = Image.open(f)\n        self.assert_image_equal(im, reloaded)\n\n    def test_truncated_file(self):\n        path = self.tempfile('temp.pgm')\n        with open(path, 'w') as f:\n            f.write('P6')\n\n        self.assertRaises(ValueError, Image.open, path)\n\n    def test_neg_ppm(self):\n        # Storage.c accepted negative values for xsize, ysize.  the\n        # internal open_ppm function didn't check for sanity but it\n        # has been removed. The default opener doesn't accept negative\n        # sizes.\n\n        with self.assertRaises(IOError):\n            Image.open('Tests/images/negative_size.ppm')\n\n    def test_mimetypes(self):\n        path = self.tempfile('temp.pgm')\n\n        with open(path, 'w') as f:\n            f.write(\"P4\\n128 128\\n255\")\n        im = Image.open(path)\n        self.assertEqual(im.get_format_mimetype(), \"image/x-portable-bitmap\")\n\n        with open(path, 'w') as f:\n            f.write(\"PyCMYK\\n128 128\\n255\")\n        im = Image.open(path)\n        self.assertEqual(im.get_format_mimetype(), \"image/x-portable-anymap\")\n",
            "header": {
                "file": {
                    "path": "Tests/test_file_ppm.py"
                },
                "misc_line": null
            },
            "index_line": {
                "old_commit_hash": "47f8b845e",
                "new_commit_hash": "dc239cc4c",
                "mode": "100644"
            },
            "is_binary_file": false,
            "binary_line": null,
            "minus_file": {
                "path": "a/Tests/test_file_ppm.py"
            },
            "plus_file": {
                "path": "b/Tests/test_file_ppm.py"
            },
            "hunks": [
                {
                    "descriptor": {
                        "old_range": {
                            "start": 14,
                            "length": 12
                        },
                        "new_range": {
                            "start": 14,
                            "length": 14
                        },
                        "section": "class TestFilePpm(PillowTestCase):"
                    },
                    "line_group": {
                        "all_lines": [
                            {
                                "content": "        self.assertEqual(im.mode, \"RGB\")",
                                "type": "context"
                            },
                            {
                                "content": "        self.assertEqual(im.size, (128, 128))",
                                "type": "context"
                            },
                            {
                                "content": "        self.assertEqual(im.format, \"PPM\")",
                                "type": "context"
                            },
                            {
                                "content": "        self.assertEqual(im.get_format_mimetype(), \"image/x-portable-pixmap\")",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "    def test_16bit_pgm(self):",
                                "type": "context"
                            },
                            {
                                "content": "        im = Image.open('Tests/images/16_bit_binary.pgm')",
                                "type": "context"
                            },
                            {
                                "content": "        im.load()",
                                "type": "context"
                            },
                            {
                                "content": "        self.assertEqual(im.mode, 'I')",
                                "type": "context"
                            },
                            {
                                "content": "        self.assertEqual(im.size, (20, 100))",
                                "type": "context"
                            },
                            {
                                "content": "        self.assertEqual(im.get_format_mimetype(), \"image/x-portable-graymap\")",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "        tgt = Image.open('Tests/images/16_bit_binary_pgm.png')",
                                "type": "context"
                            },
                            {
                                "content": "        self.assert_image_equal(im, tgt)",
                                "type": "context"
                            }
                        ]
                    },
                    "modified_entities": [
                        {
                            "file_name": "Tests/test_file_ppm.py",
                            "type": "method",
                            "name": "TestFilePpm.test_16bit_pgm",
                            "content": "class TestFilePpm(PillowTestCase):\n\n    def test_sanity(self):\n        im = Image.open(test_file)\n        im.load()\n        self.assertEqual(im.mode, \"RGB\")\n        self.assertEqual(im.size, (128, 128))\n        self.assertEqual(im.format, \"PPM\")\n        self.assertEqual(im.get_format_mimetype(), \"image/x-portable-pixmap\")\n\n    def test_16bit_pgm(self):\n        im = Image.open('Tests/images/16_bit_binary.pgm')\n        im.load()\n        self.assertEqual(im.mode, 'I')\n        self.assertEqual(im.size, (20, 100))\n        self.assertEqual(im.get_format_mimetype(), \"image/x-portable-graymap\")\n\n        tgt = Image.open('Tests/images/16_bit_binary_pgm.png')\n        self.assert_image_equal(im, tgt)\n\n    def test_16bit_pgm_write(self):\n        im = Image.open('Tests/images/16_bit_binary.pgm')\n        im.load()\n\n        f = self.tempfile('temp.pgm')\n        im.save(f, 'PPM')\n\n        reloaded = Image.open(f)\n        self.assert_image_equal(im, reloaded)\n\n    def test_truncated_file(self):\n        path = self.tempfile('temp.pgm')\n        with open(path, 'w') as f:\n            f.write('P6')\n\n        self.assertRaises(ValueError, Image.open, path)\n\n    def test_neg_ppm(self):\n        # Storage.c accepted negative values for xsize, ysize.  the\n        # internal open_ppm function didn't check for sanity but it\n        # has been removed. The default opener doesn't accept negative\n        # sizes.\n\n        with self.assertRaises(IOError):\n            Image.open('Tests/images/negative_size.ppm')\n\n    def test_mimetypes(self):\n        path = self.tempfile('temp.pgm')\n\n        with open(path, 'w') as f:\n            f.write(\"P4\\n128 128\\n255\")\n        im = Image.open(path)\n        self.assertEqual(im.get_format_mimetype(), \"image/x-portable-bitmap\")\n\n        with open(path, 'w') as f:\n            f.write(\"PyCMYK\\n128 128\\n255\")\n        im = Image.open(path)\n        self.assertEqual(im.get_format_mimetype(), \"image/x-portable-anymap\")",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 19,
                            "end_lineno": 27,
                            "parent": {
                                "file_name": "Tests/test_file_ppm.py",
                                "type": "class",
                                "name": "TestFilePpm",
                                "content": "class TestFilePpm(PillowTestCase):\n\n    def test_sanity(self):\n        im = Image.open(test_file)\n        im.load()\n        self.assertEqual(im.mode, \"RGB\")\n        self.assertEqual(im.size, (128, 128))\n        self.assertEqual(im.format, \"PPM\")\n        self.assertEqual(im.get_format_mimetype(), \"image/x-portable-pixmap\")\n\n    def test_16bit_pgm(self):\n        im = Image.open('Tests/images/16_bit_binary.pgm')\n        im.load()\n        self.assertEqual(im.mode, 'I')\n        self.assertEqual(im.size, (20, 100))\n        self.assertEqual(im.get_format_mimetype(), \"image/x-portable-graymap\")\n\n        tgt = Image.open('Tests/images/16_bit_binary_pgm.png')\n        self.assert_image_equal(im, tgt)\n\n    def test_16bit_pgm_write(self):\n        im = Image.open('Tests/images/16_bit_binary.pgm')\n        im.load()\n\n        f = self.tempfile('temp.pgm')\n        im.save(f, 'PPM')\n\n        reloaded = Image.open(f)\n        self.assert_image_equal(im, reloaded)\n\n    def test_truncated_file(self):\n        path = self.tempfile('temp.pgm')\n        with open(path, 'w') as f:\n            f.write('P6')\n\n        self.assertRaises(ValueError, Image.open, path)\n\n    def test_neg_ppm(self):\n        # Storage.c accepted negative values for xsize, ysize.  the\n        # internal open_ppm function didn't check for sanity but it\n        # has been removed. The default opener doesn't accept negative\n        # sizes.\n\n        with self.assertRaises(IOError):\n            Image.open('Tests/images/negative_size.ppm')\n\n    def test_mimetypes(self):\n        path = self.tempfile('temp.pgm')\n\n        with open(path, 'w') as f:\n            f.write(\"P4\\n128 128\\n255\")\n        im = Image.open(path)\n        self.assertEqual(im.get_format_mimetype(), \"image/x-portable-bitmap\")\n\n        with open(path, 'w') as f:\n            f.write(\"PyCMYK\\n128 128\\n255\")\n        im = Image.open(path)\n        self.assertEqual(im.get_format_mimetype(), \"image/x-portable-anymap\")",
                                "ast_type_str": "ClassDef",
                                "start_lineno": 9,
                                "end_lineno": 66,
                                "parent": null
                            }
                        },
                        {
                            "file_name": "Tests/test_file_ppm.py",
                            "type": "method",
                            "name": "TestFilePpm.test_sanity",
                            "content": "class TestFilePpm(PillowTestCase):\n\n    def test_sanity(self):\n        im = Image.open(test_file)\n        im.load()\n        self.assertEqual(im.mode, \"RGB\")\n        self.assertEqual(im.size, (128, 128))\n        self.assertEqual(im.format, \"PPM\")\n        self.assertEqual(im.get_format_mimetype(), \"image/x-portable-pixmap\")\n\n    def test_16bit_pgm(self):\n        im = Image.open('Tests/images/16_bit_binary.pgm')\n        im.load()\n        self.assertEqual(im.mode, 'I')\n        self.assertEqual(im.size, (20, 100))\n        self.assertEqual(im.get_format_mimetype(), \"image/x-portable-graymap\")\n\n        tgt = Image.open('Tests/images/16_bit_binary_pgm.png')\n        self.assert_image_equal(im, tgt)\n\n    def test_16bit_pgm_write(self):\n        im = Image.open('Tests/images/16_bit_binary.pgm')\n        im.load()\n\n        f = self.tempfile('temp.pgm')\n        im.save(f, 'PPM')\n\n        reloaded = Image.open(f)\n        self.assert_image_equal(im, reloaded)\n\n    def test_truncated_file(self):\n        path = self.tempfile('temp.pgm')\n        with open(path, 'w') as f:\n            f.write('P6')\n\n        self.assertRaises(ValueError, Image.open, path)\n\n    def test_neg_ppm(self):\n        # Storage.c accepted negative values for xsize, ysize.  the\n        # internal open_ppm function didn't check for sanity but it\n        # has been removed. The default opener doesn't accept negative\n        # sizes.\n\n        with self.assertRaises(IOError):\n            Image.open('Tests/images/negative_size.ppm')\n\n    def test_mimetypes(self):\n        path = self.tempfile('temp.pgm')\n\n        with open(path, 'w') as f:\n            f.write(\"P4\\n128 128\\n255\")\n        im = Image.open(path)\n        self.assertEqual(im.get_format_mimetype(), \"image/x-portable-bitmap\")\n\n        with open(path, 'w') as f:\n            f.write(\"PyCMYK\\n128 128\\n255\")\n        im = Image.open(path)\n        self.assertEqual(im.get_format_mimetype(), \"image/x-portable-anymap\")",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 11,
                            "end_lineno": 17,
                            "parent": {
                                "file_name": "Tests/test_file_ppm.py",
                                "type": "class",
                                "name": "TestFilePpm",
                                "content": "class TestFilePpm(PillowTestCase):\n\n    def test_sanity(self):\n        im = Image.open(test_file)\n        im.load()\n        self.assertEqual(im.mode, \"RGB\")\n        self.assertEqual(im.size, (128, 128))\n        self.assertEqual(im.format, \"PPM\")\n        self.assertEqual(im.get_format_mimetype(), \"image/x-portable-pixmap\")\n\n    def test_16bit_pgm(self):\n        im = Image.open('Tests/images/16_bit_binary.pgm')\n        im.load()\n        self.assertEqual(im.mode, 'I')\n        self.assertEqual(im.size, (20, 100))\n        self.assertEqual(im.get_format_mimetype(), \"image/x-portable-graymap\")\n\n        tgt = Image.open('Tests/images/16_bit_binary_pgm.png')\n        self.assert_image_equal(im, tgt)\n\n    def test_16bit_pgm_write(self):\n        im = Image.open('Tests/images/16_bit_binary.pgm')\n        im.load()\n\n        f = self.tempfile('temp.pgm')\n        im.save(f, 'PPM')\n\n        reloaded = Image.open(f)\n        self.assert_image_equal(im, reloaded)\n\n    def test_truncated_file(self):\n        path = self.tempfile('temp.pgm')\n        with open(path, 'w') as f:\n            f.write('P6')\n\n        self.assertRaises(ValueError, Image.open, path)\n\n    def test_neg_ppm(self):\n        # Storage.c accepted negative values for xsize, ysize.  the\n        # internal open_ppm function didn't check for sanity but it\n        # has been removed. The default opener doesn't accept negative\n        # sizes.\n\n        with self.assertRaises(IOError):\n            Image.open('Tests/images/negative_size.ppm')\n\n    def test_mimetypes(self):\n        path = self.tempfile('temp.pgm')\n\n        with open(path, 'w') as f:\n            f.write(\"P4\\n128 128\\n255\")\n        im = Image.open(path)\n        self.assertEqual(im.get_format_mimetype(), \"image/x-portable-bitmap\")\n\n        with open(path, 'w') as f:\n            f.write(\"PyCMYK\\n128 128\\n255\")\n        im = Image.open(path)\n        self.assertEqual(im.get_format_mimetype(), \"image/x-portable-anymap\")",
                                "ast_type_str": "ClassDef",
                                "start_lineno": 9,
                                "end_lineno": 66,
                                "parent": null
                            }
                        },
                        {
                            "file_name": "Tests/test_file_ppm.py",
                            "type": "class",
                            "name": "TestFilePpm",
                            "content": "class TestFilePpm(PillowTestCase):\n\n    def test_sanity(self):\n        im = Image.open(test_file)\n        im.load()\n        self.assertEqual(im.mode, \"RGB\")\n        self.assertEqual(im.size, (128, 128))\n        self.assertEqual(im.format, \"PPM\")\n        self.assertEqual(im.get_format_mimetype(), \"image/x-portable-pixmap\")\n\n    def test_16bit_pgm(self):\n        im = Image.open('Tests/images/16_bit_binary.pgm')\n        im.load()\n        self.assertEqual(im.mode, 'I')\n        self.assertEqual(im.size, (20, 100))\n        self.assertEqual(im.get_format_mimetype(), \"image/x-portable-graymap\")\n\n        tgt = Image.open('Tests/images/16_bit_binary_pgm.png')\n        self.assert_image_equal(im, tgt)\n\n    def test_16bit_pgm_write(self):\n        im = Image.open('Tests/images/16_bit_binary.pgm')\n        im.load()\n\n        f = self.tempfile('temp.pgm')\n        im.save(f, 'PPM')\n\n        reloaded = Image.open(f)\n        self.assert_image_equal(im, reloaded)\n\n    def test_truncated_file(self):\n        path = self.tempfile('temp.pgm')\n        with open(path, 'w') as f:\n            f.write('P6')\n\n        self.assertRaises(ValueError, Image.open, path)\n\n    def test_neg_ppm(self):\n        # Storage.c accepted negative values for xsize, ysize.  the\n        # internal open_ppm function didn't check for sanity but it\n        # has been removed. The default opener doesn't accept negative\n        # sizes.\n\n        with self.assertRaises(IOError):\n            Image.open('Tests/images/negative_size.ppm')\n\n    def test_mimetypes(self):\n        path = self.tempfile('temp.pgm')\n\n        with open(path, 'w') as f:\n            f.write(\"P4\\n128 128\\n255\")\n        im = Image.open(path)\n        self.assertEqual(im.get_format_mimetype(), \"image/x-portable-bitmap\")\n\n        with open(path, 'w') as f:\n            f.write(\"PyCMYK\\n128 128\\n255\")\n        im = Image.open(path)\n        self.assertEqual(im.get_format_mimetype(), \"image/x-portable-anymap\")",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 9,
                            "end_lineno": 66,
                            "parent": null
                        }
                    ],
                    "added_entities": [],
                    "deleted_entities": []
                },
                {
                    "descriptor": {
                        "old_range": {
                            "start": 49,
                            "length": 3
                        },
                        "new_range": {
                            "start": 51,
                            "length": 16
                        },
                        "section": "class TestFilePpm(PillowTestCase):"
                    },
                    "line_group": {
                        "all_lines": [
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "        with self.assertRaises(IOError):",
                                "type": "context"
                            },
                            {
                                "content": "            Image.open('Tests/images/negative_size.ppm')",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "added"
                            },
                            {
                                "content": "    def test_mimetypes(self):",
                                "type": "added"
                            },
                            {
                                "content": "        path = self.tempfile('temp.pgm')",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "added"
                            },
                            {
                                "content": "        with open(path, 'w') as f:",
                                "type": "added"
                            },
                            {
                                "content": "            f.write(\"P4\\n128 128\\n255\")",
                                "type": "added"
                            },
                            {
                                "content": "        im = Image.open(path)",
                                "type": "added"
                            },
                            {
                                "content": "        self.assertEqual(im.get_format_mimetype(), \"image/x-portable-bitmap\")",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "added"
                            },
                            {
                                "content": "        with open(path, 'w') as f:",
                                "type": "added"
                            },
                            {
                                "content": "            f.write(\"PyCMYK\\n128 128\\n255\")",
                                "type": "added"
                            },
                            {
                                "content": "        im = Image.open(path)",
                                "type": "added"
                            },
                            {
                                "content": "        self.assertEqual(im.get_format_mimetype(), \"image/x-portable-anymap\")",
                                "type": "added"
                            }
                        ]
                    },
                    "modified_entities": [
                        {
                            "file_name": "Tests/test_file_ppm.py",
                            "type": "class",
                            "name": "TestFilePpm",
                            "content": "class TestFilePpm(PillowTestCase):\n\n    def test_sanity(self):\n        im = Image.open(test_file)\n        im.load()\n        self.assertEqual(im.mode, \"RGB\")\n        self.assertEqual(im.size, (128, 128))\n        self.assertEqual(im.format, \"PPM\")\n        self.assertEqual(im.get_format_mimetype(), \"image/x-portable-pixmap\")\n\n    def test_16bit_pgm(self):\n        im = Image.open('Tests/images/16_bit_binary.pgm')\n        im.load()\n        self.assertEqual(im.mode, 'I')\n        self.assertEqual(im.size, (20, 100))\n        self.assertEqual(im.get_format_mimetype(), \"image/x-portable-graymap\")\n\n        tgt = Image.open('Tests/images/16_bit_binary_pgm.png')\n        self.assert_image_equal(im, tgt)\n\n    def test_16bit_pgm_write(self):\n        im = Image.open('Tests/images/16_bit_binary.pgm')\n        im.load()\n\n        f = self.tempfile('temp.pgm')\n        im.save(f, 'PPM')\n\n        reloaded = Image.open(f)\n        self.assert_image_equal(im, reloaded)\n\n    def test_truncated_file(self):\n        path = self.tempfile('temp.pgm')\n        with open(path, 'w') as f:\n            f.write('P6')\n\n        self.assertRaises(ValueError, Image.open, path)\n\n    def test_neg_ppm(self):\n        # Storage.c accepted negative values for xsize, ysize.  the\n        # internal open_ppm function didn't check for sanity but it\n        # has been removed. The default opener doesn't accept negative\n        # sizes.\n\n        with self.assertRaises(IOError):\n            Image.open('Tests/images/negative_size.ppm')\n\n    def test_mimetypes(self):\n        path = self.tempfile('temp.pgm')\n\n        with open(path, 'w') as f:\n            f.write(\"P4\\n128 128\\n255\")\n        im = Image.open(path)\n        self.assertEqual(im.get_format_mimetype(), \"image/x-portable-bitmap\")\n\n        with open(path, 'w') as f:\n            f.write(\"PyCMYK\\n128 128\\n255\")\n        im = Image.open(path)\n        self.assertEqual(im.get_format_mimetype(), \"image/x-portable-anymap\")",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 9,
                            "end_lineno": 66,
                            "parent": null
                        }
                    ],
                    "added_entities": [
                        {
                            "file_name": "Tests/test_file_ppm.py",
                            "type": "method",
                            "name": "TestFilePpm.test_mimetypes",
                            "content": "class TestFilePpm(PillowTestCase):\n\n    def test_sanity(self):\n        im = Image.open(test_file)\n        im.load()\n        self.assertEqual(im.mode, \"RGB\")\n        self.assertEqual(im.size, (128, 128))\n        self.assertEqual(im.format, \"PPM\")\n        self.assertEqual(im.get_format_mimetype(), \"image/x-portable-pixmap\")\n\n    def test_16bit_pgm(self):\n        im = Image.open('Tests/images/16_bit_binary.pgm')\n        im.load()\n        self.assertEqual(im.mode, 'I')\n        self.assertEqual(im.size, (20, 100))\n        self.assertEqual(im.get_format_mimetype(), \"image/x-portable-graymap\")\n\n        tgt = Image.open('Tests/images/16_bit_binary_pgm.png')\n        self.assert_image_equal(im, tgt)\n\n    def test_16bit_pgm_write(self):\n        im = Image.open('Tests/images/16_bit_binary.pgm')\n        im.load()\n\n        f = self.tempfile('temp.pgm')\n        im.save(f, 'PPM')\n\n        reloaded = Image.open(f)\n        self.assert_image_equal(im, reloaded)\n\n    def test_truncated_file(self):\n        path = self.tempfile('temp.pgm')\n        with open(path, 'w') as f:\n            f.write('P6')\n\n        self.assertRaises(ValueError, Image.open, path)\n\n    def test_neg_ppm(self):\n        # Storage.c accepted negative values for xsize, ysize.  the\n        # internal open_ppm function didn't check for sanity but it\n        # has been removed. The default opener doesn't accept negative\n        # sizes.\n\n        with self.assertRaises(IOError):\n            Image.open('Tests/images/negative_size.ppm')\n\n    def test_mimetypes(self):\n        path = self.tempfile('temp.pgm')\n\n        with open(path, 'w') as f:\n            f.write(\"P4\\n128 128\\n255\")\n        im = Image.open(path)\n        self.assertEqual(im.get_format_mimetype(), \"image/x-portable-bitmap\")\n\n        with open(path, 'w') as f:\n            f.write(\"PyCMYK\\n128 128\\n255\")\n        im = Image.open(path)\n        self.assertEqual(im.get_format_mimetype(), \"image/x-portable-anymap\")",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 55,
                            "end_lineno": 66,
                            "parent": {
                                "file_name": "Tests/test_file_ppm.py",
                                "type": "class",
                                "name": "TestFilePpm",
                                "content": "class TestFilePpm(PillowTestCase):\n\n    def test_sanity(self):\n        im = Image.open(test_file)\n        im.load()\n        self.assertEqual(im.mode, \"RGB\")\n        self.assertEqual(im.size, (128, 128))\n        self.assertEqual(im.format, \"PPM\")\n        self.assertEqual(im.get_format_mimetype(), \"image/x-portable-pixmap\")\n\n    def test_16bit_pgm(self):\n        im = Image.open('Tests/images/16_bit_binary.pgm')\n        im.load()\n        self.assertEqual(im.mode, 'I')\n        self.assertEqual(im.size, (20, 100))\n        self.assertEqual(im.get_format_mimetype(), \"image/x-portable-graymap\")\n\n        tgt = Image.open('Tests/images/16_bit_binary_pgm.png')\n        self.assert_image_equal(im, tgt)\n\n    def test_16bit_pgm_write(self):\n        im = Image.open('Tests/images/16_bit_binary.pgm')\n        im.load()\n\n        f = self.tempfile('temp.pgm')\n        im.save(f, 'PPM')\n\n        reloaded = Image.open(f)\n        self.assert_image_equal(im, reloaded)\n\n    def test_truncated_file(self):\n        path = self.tempfile('temp.pgm')\n        with open(path, 'w') as f:\n            f.write('P6')\n\n        self.assertRaises(ValueError, Image.open, path)\n\n    def test_neg_ppm(self):\n        # Storage.c accepted negative values for xsize, ysize.  the\n        # internal open_ppm function didn't check for sanity but it\n        # has been removed. The default opener doesn't accept negative\n        # sizes.\n\n        with self.assertRaises(IOError):\n            Image.open('Tests/images/negative_size.ppm')\n\n    def test_mimetypes(self):\n        path = self.tempfile('temp.pgm')\n\n        with open(path, 'w') as f:\n            f.write(\"P4\\n128 128\\n255\")\n        im = Image.open(path)\n        self.assertEqual(im.get_format_mimetype(), \"image/x-portable-bitmap\")\n\n        with open(path, 'w') as f:\n            f.write(\"PyCMYK\\n128 128\\n255\")\n        im = Image.open(path)\n        self.assertEqual(im.get_format_mimetype(), \"image/x-portable-anymap\")",
                                "ast_type_str": "ClassDef",
                                "start_lineno": 9,
                                "end_lineno": 66,
                                "parent": null
                            }
                        }
                    ],
                    "deleted_entities": []
                }
            ]
        },
        {
            "old_file_content": "#\n# The Python Imaging Library.\n# $Id$\n#\n# PPM support for PIL\n#\n# History:\n#       96-03-24 fl     Created\n#       98-03-06 fl     Write RGBA images (as RGB, that is)\n#\n# Copyright (c) Secret Labs AB 1997-98.\n# Copyright (c) Fredrik Lundh 1996.\n#\n# See the README file for information on usage and redistribution.\n#\n\n\nfrom . import Image, ImageFile\n\n# __version__ is deprecated and will be removed in a future version. Use\n# PIL.__version__ instead.\n__version__ = \"0.2\"\n\n#\n# --------------------------------------------------------------------\n\nb_whitespace = b'\\x20\\x09\\x0a\\x0b\\x0c\\x0d'\n\nMODES = {\n    # standard\n    b\"P4\": \"1\",\n    b\"P5\": \"L\",\n    b\"P6\": \"RGB\",\n    # extensions\n    b\"P0CMYK\": \"CMYK\",\n    # PIL extensions (for test purposes only)\n    b\"PyP\": \"P\",\n    b\"PyRGBA\": \"RGBA\",\n    b\"PyCMYK\": \"CMYK\"\n}\n\n\ndef _accept(prefix):\n    return prefix[0:1] == b\"P\" and prefix[1] in b\"0456y\"\n\n\n##\n# Image plugin for PBM, PGM, and PPM images.\n\nclass PpmImageFile(ImageFile.ImageFile):\n\n    format = \"PPM\"\n    format_description = \"Pbmplus image\"\n\n    def _token(self, s=b\"\"):\n        while True:  # read until next whitespace\n            c = self.fp.read(1)\n            if not c or c in b_whitespace:\n                break\n            if c > b'\\x79':\n                raise ValueError(\"Expected ASCII value, found binary\")\n            s = s + c\n            if (len(s) > 9):\n                raise ValueError(\"Expected int, got > 9 digits\")\n        return s\n\n    def _open(self):\n\n        # check magic\n        s = self.fp.read(1)\n        if s != b\"P\":\n            raise SyntaxError(\"not a PPM file\")\n        mode = MODES[self._token(s)]\n\n        if mode == \"1\":\n            self.mode = \"1\"\n            rawmode = \"1;I\"\n        else:\n            self.mode = rawmode = mode\n\n        for ix in range(3):\n            while True:\n                while True:\n                    s = self.fp.read(1)\n                    if s not in b_whitespace:\n                        break\n                    if s == b\"\":\n                        raise ValueError(\n                            \"File does not extend beyond magic number\")\n                if s != b\"#\":\n                    break\n                s = self.fp.readline()\n            s = int(self._token(s))\n            if ix == 0:\n                xsize = s\n            elif ix == 1:\n                ysize = s\n                if mode == \"1\":\n                    break\n            elif ix == 2:\n                # maxgrey\n                if s > 255:\n                    if not mode == 'L':\n                        raise ValueError(\"Too many colors for band: %s\" % s)\n                    if s < 2**16:\n                        self.mode = 'I'\n                        rawmode = 'I;16B'\n                    else:\n                        self.mode = 'I'\n                        rawmode = 'I;32B'\n\n        self._size = xsize, ysize\n        self.tile = [(\"raw\",\n                     (0, 0, xsize, ysize),\n                     self.fp.tell(),\n                     (rawmode, 0, 1))]\n\n\n#\n# --------------------------------------------------------------------\n\ndef _save(im, fp, filename):\n    if im.mode == \"1\":\n        rawmode, head = \"1;I\", b\"P4\"\n    elif im.mode == \"L\":\n        rawmode, head = \"L\", b\"P5\"\n    elif im.mode == \"I\":\n        if im.getextrema()[1] < 2**16:\n            rawmode, head = \"I;16B\", b\"P5\"\n        else:\n            rawmode, head = \"I;32B\", b\"P5\"\n    elif im.mode == \"RGB\":\n        rawmode, head = \"RGB\", b\"P6\"\n    elif im.mode == \"RGBA\":\n        rawmode, head = \"RGB\", b\"P6\"\n    else:\n        raise IOError(\"cannot write mode %s as PPM\" % im.mode)\n    fp.write(head + (\"\\n%d %d\\n\" % im.size).encode('ascii'))\n    if head == b\"P6\":\n        fp.write(b\"255\\n\")\n    if head == b\"P5\":\n        if rawmode == \"L\":\n            fp.write(b\"255\\n\")\n        elif rawmode == \"I;16B\":\n            fp.write(b\"65535\\n\")\n        elif rawmode == \"I;32B\":\n            fp.write(b\"2147483648\\n\")\n    ImageFile._save(im, fp, [(\"raw\", (0, 0)+im.size, 0, (rawmode, 0, 1))])\n\n    # ALTERNATIVE: save via builtin debug function\n    # im._dump(filename)\n\n#\n# --------------------------------------------------------------------\n\n\nImage.register_open(PpmImageFile.format, PpmImageFile, _accept)\nImage.register_save(PpmImageFile.format, _save)\n\nImage.register_extensions(PpmImageFile.format, [\".pbm\", \".pgm\", \".ppm\"])\n",
            "new_file_content": "#\n# The Python Imaging Library.\n# $Id$\n#\n# PPM support for PIL\n#\n# History:\n#       96-03-24 fl     Created\n#       98-03-06 fl     Write RGBA images (as RGB, that is)\n#\n# Copyright (c) Secret Labs AB 1997-98.\n# Copyright (c) Fredrik Lundh 1996.\n#\n# See the README file for information on usage and redistribution.\n#\n\n\nfrom . import Image, ImageFile\n\n# __version__ is deprecated and will be removed in a future version. Use\n# PIL.__version__ instead.\n__version__ = \"0.2\"\n\n#\n# --------------------------------------------------------------------\n\nb_whitespace = b'\\x20\\x09\\x0a\\x0b\\x0c\\x0d'\n\nMODES = {\n    # standard\n    b\"P4\": \"1\",\n    b\"P5\": \"L\",\n    b\"P6\": \"RGB\",\n    # extensions\n    b\"P0CMYK\": \"CMYK\",\n    # PIL extensions (for test purposes only)\n    b\"PyP\": \"P\",\n    b\"PyRGBA\": \"RGBA\",\n    b\"PyCMYK\": \"CMYK\"\n}\n\n\ndef _accept(prefix):\n    return prefix[0:1] == b\"P\" and prefix[1] in b\"0456y\"\n\n\n##\n# Image plugin for PBM, PGM, and PPM images.\n\nclass PpmImageFile(ImageFile.ImageFile):\n\n    format = \"PPM\"\n    format_description = \"Pbmplus image\"\n\n    def _token(self, s=b\"\"):\n        while True:  # read until next whitespace\n            c = self.fp.read(1)\n            if not c or c in b_whitespace:\n                break\n            if c > b'\\x79':\n                raise ValueError(\"Expected ASCII value, found binary\")\n            s = s + c\n            if (len(s) > 9):\n                raise ValueError(\"Expected int, got > 9 digits\")\n        return s\n\n    def _open(self):\n\n        # check magic\n        s = self.fp.read(1)\n        if s != b\"P\":\n            raise SyntaxError(\"not a PPM file\")\n        magic_number = self._token(s)\n        mode = MODES[magic_number]\n\n        self.custom_mimetype = {\n            b\"P4\": \"image/x-portable-bitmap\",\n            b\"P5\": \"image/x-portable-graymap\",\n            b\"P6\": \"image/x-portable-pixmap\",\n        }.get(magic_number)\n\n        if mode == \"1\":\n            self.mode = \"1\"\n            rawmode = \"1;I\"\n        else:\n            self.mode = rawmode = mode\n\n        for ix in range(3):\n            while True:\n                while True:\n                    s = self.fp.read(1)\n                    if s not in b_whitespace:\n                        break\n                    if s == b\"\":\n                        raise ValueError(\n                            \"File does not extend beyond magic number\")\n                if s != b\"#\":\n                    break\n                s = self.fp.readline()\n            s = int(self._token(s))\n            if ix == 0:\n                xsize = s\n            elif ix == 1:\n                ysize = s\n                if mode == \"1\":\n                    break\n            elif ix == 2:\n                # maxgrey\n                if s > 255:\n                    if not mode == 'L':\n                        raise ValueError(\"Too many colors for band: %s\" % s)\n                    if s < 2**16:\n                        self.mode = 'I'\n                        rawmode = 'I;16B'\n                    else:\n                        self.mode = 'I'\n                        rawmode = 'I;32B'\n\n        self._size = xsize, ysize\n        self.tile = [(\"raw\",\n                     (0, 0, xsize, ysize),\n                     self.fp.tell(),\n                     (rawmode, 0, 1))]\n\n\n#\n# --------------------------------------------------------------------\n\ndef _save(im, fp, filename):\n    if im.mode == \"1\":\n        rawmode, head = \"1;I\", b\"P4\"\n    elif im.mode == \"L\":\n        rawmode, head = \"L\", b\"P5\"\n    elif im.mode == \"I\":\n        if im.getextrema()[1] < 2**16:\n            rawmode, head = \"I;16B\", b\"P5\"\n        else:\n            rawmode, head = \"I;32B\", b\"P5\"\n    elif im.mode == \"RGB\":\n        rawmode, head = \"RGB\", b\"P6\"\n    elif im.mode == \"RGBA\":\n        rawmode, head = \"RGB\", b\"P6\"\n    else:\n        raise IOError(\"cannot write mode %s as PPM\" % im.mode)\n    fp.write(head + (\"\\n%d %d\\n\" % im.size).encode('ascii'))\n    if head == b\"P6\":\n        fp.write(b\"255\\n\")\n    if head == b\"P5\":\n        if rawmode == \"L\":\n            fp.write(b\"255\\n\")\n        elif rawmode == \"I;16B\":\n            fp.write(b\"65535\\n\")\n        elif rawmode == \"I;32B\":\n            fp.write(b\"2147483648\\n\")\n    ImageFile._save(im, fp, [(\"raw\", (0, 0)+im.size, 0, (rawmode, 0, 1))])\n\n    # ALTERNATIVE: save via builtin debug function\n    # im._dump(filename)\n\n#\n# --------------------------------------------------------------------\n\n\nImage.register_open(PpmImageFile.format, PpmImageFile, _accept)\nImage.register_save(PpmImageFile.format, _save)\n\nImage.register_extensions(PpmImageFile.format, [\".pbm\", \".pgm\", \".ppm\"])\n\nImage.register_mime(PpmImageFile.format, \"image/x-portable-anymap\")\n",
            "header": {
                "file": {
                    "path": "src/PIL/PpmImagePlugin.py"
                },
                "misc_line": null
            },
            "index_line": {
                "old_commit_hash": "750454dc5",
                "new_commit_hash": "e3e411cad",
                "mode": "100644"
            },
            "is_binary_file": false,
            "binary_line": null,
            "minus_file": {
                "path": "a/src/PIL/PpmImagePlugin.py"
            },
            "plus_file": {
                "path": "b/src/PIL/PpmImagePlugin.py"
            },
            "hunks": [
                {
                    "descriptor": {
                        "old_range": {
                            "start": 70,
                            "length": 7
                        },
                        "new_range": {
                            "start": 70,
                            "length": 14
                        },
                        "section": "class PpmImageFile(ImageFile.ImageFile):"
                    },
                    "line_group": {
                        "all_lines": [
                            {
                                "content": "        s = self.fp.read(1)",
                                "type": "context"
                            },
                            {
                                "content": "        if s != b\"P\":",
                                "type": "context"
                            },
                            {
                                "content": "            raise SyntaxError(\"not a PPM file\")",
                                "type": "context"
                            },
                            {
                                "content": "        mode = MODES[self._token(s)]",
                                "type": "deleted"
                            },
                            {
                                "content": "        magic_number = self._token(s)",
                                "type": "added"
                            },
                            {
                                "content": "        mode = MODES[magic_number]",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "added"
                            },
                            {
                                "content": "        self.custom_mimetype = {",
                                "type": "added"
                            },
                            {
                                "content": "            b\"P4\": \"image/x-portable-bitmap\",",
                                "type": "added"
                            },
                            {
                                "content": "            b\"P5\": \"image/x-portable-graymap\",",
                                "type": "added"
                            },
                            {
                                "content": "            b\"P6\": \"image/x-portable-pixmap\",",
                                "type": "added"
                            },
                            {
                                "content": "        }.get(magic_number)",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "        if mode == \"1\":",
                                "type": "context"
                            },
                            {
                                "content": "            self.mode = \"1\"",
                                "type": "context"
                            }
                        ]
                    },
                    "modified_entities": [
                        {
                            "file_name": "src/PIL/PpmImagePlugin.py",
                            "type": "method",
                            "name": "PpmImageFile._open",
                            "content": "class PpmImageFile(ImageFile.ImageFile):\n\n    format = \"PPM\"\n    format_description = \"Pbmplus image\"\n\n    def _token(self, s=b\"\"):\n        while True:  # read until next whitespace\n            c = self.fp.read(1)\n            if not c or c in b_whitespace:\n                break\n            if c > b'\\x79':\n                raise ValueError(\"Expected ASCII value, found binary\")\n            s = s + c\n            if (len(s) > 9):\n                raise ValueError(\"Expected int, got > 9 digits\")\n        return s\n\n    def _open(self):\n\n        # check magic\n        s = self.fp.read(1)\n        if s != b\"P\":\n            raise SyntaxError(\"not a PPM file\")\n        mode = MODES[self._token(s)]\n\n        if mode == \"1\":\n            self.mode = \"1\"\n            rawmode = \"1;I\"\n        else:\n            self.mode = rawmode = mode\n\n        for ix in range(3):\n            while True:\n                while True:\n                    s = self.fp.read(1)\n                    if s not in b_whitespace:\n                        break\n                    if s == b\"\":\n                        raise ValueError(\n                            \"File does not extend beyond magic number\")\n                if s != b\"#\":\n                    break\n                s = self.fp.readline()\n            s = int(self._token(s))\n            if ix == 0:\n                xsize = s\n            elif ix == 1:\n                ysize = s\n                if mode == \"1\":\n                    break\n            elif ix == 2:\n                # maxgrey\n                if s > 255:\n                    if not mode == 'L':\n                        raise ValueError(\"Too many colors for band: %s\" % s)\n                    if s < 2**16:\n                        self.mode = 'I'\n                        rawmode = 'I;16B'\n                    else:\n                        self.mode = 'I'\n                        rawmode = 'I;32B'\n\n        self._size = xsize, ysize\n        self.tile = [(\"raw\",\n                     (0, 0, xsize, ysize),\n                     self.fp.tell(),\n                     (rawmode, 0, 1))]",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 67,
                            "end_lineno": 116,
                            "parent": {
                                "file_name": "src/PIL/PpmImagePlugin.py",
                                "type": "class",
                                "name": "PpmImageFile",
                                "content": "class PpmImageFile(ImageFile.ImageFile):\n\n    format = \"PPM\"\n    format_description = \"Pbmplus image\"\n\n    def _token(self, s=b\"\"):\n        while True:  # read until next whitespace\n            c = self.fp.read(1)\n            if not c or c in b_whitespace:\n                break\n            if c > b'\\x79':\n                raise ValueError(\"Expected ASCII value, found binary\")\n            s = s + c\n            if (len(s) > 9):\n                raise ValueError(\"Expected int, got > 9 digits\")\n        return s\n\n    def _open(self):\n\n        # check magic\n        s = self.fp.read(1)\n        if s != b\"P\":\n            raise SyntaxError(\"not a PPM file\")\n        mode = MODES[self._token(s)]\n\n        if mode == \"1\":\n            self.mode = \"1\"\n            rawmode = \"1;I\"\n        else:\n            self.mode = rawmode = mode\n\n        for ix in range(3):\n            while True:\n                while True:\n                    s = self.fp.read(1)\n                    if s not in b_whitespace:\n                        break\n                    if s == b\"\":\n                        raise ValueError(\n                            \"File does not extend beyond magic number\")\n                if s != b\"#\":\n                    break\n                s = self.fp.readline()\n            s = int(self._token(s))\n            if ix == 0:\n                xsize = s\n            elif ix == 1:\n                ysize = s\n                if mode == \"1\":\n                    break\n            elif ix == 2:\n                # maxgrey\n                if s > 255:\n                    if not mode == 'L':\n                        raise ValueError(\"Too many colors for band: %s\" % s)\n                    if s < 2**16:\n                        self.mode = 'I'\n                        rawmode = 'I;16B'\n                    else:\n                        self.mode = 'I'\n                        rawmode = 'I;32B'\n\n        self._size = xsize, ysize\n        self.tile = [(\"raw\",\n                     (0, 0, xsize, ysize),\n                     self.fp.tell(),\n                     (rawmode, 0, 1))]",
                                "ast_type_str": "ClassDef",
                                "start_lineno": 50,
                                "end_lineno": 116,
                                "parent": null
                            }
                        },
                        {
                            "file_name": "src/PIL/PpmImagePlugin.py",
                            "type": "class",
                            "name": "PpmImageFile",
                            "content": "class PpmImageFile(ImageFile.ImageFile):\n\n    format = \"PPM\"\n    format_description = \"Pbmplus image\"\n\n    def _token(self, s=b\"\"):\n        while True:  # read until next whitespace\n            c = self.fp.read(1)\n            if not c or c in b_whitespace:\n                break\n            if c > b'\\x79':\n                raise ValueError(\"Expected ASCII value, found binary\")\n            s = s + c\n            if (len(s) > 9):\n                raise ValueError(\"Expected int, got > 9 digits\")\n        return s\n\n    def _open(self):\n\n        # check magic\n        s = self.fp.read(1)\n        if s != b\"P\":\n            raise SyntaxError(\"not a PPM file\")\n        mode = MODES[self._token(s)]\n\n        if mode == \"1\":\n            self.mode = \"1\"\n            rawmode = \"1;I\"\n        else:\n            self.mode = rawmode = mode\n\n        for ix in range(3):\n            while True:\n                while True:\n                    s = self.fp.read(1)\n                    if s not in b_whitespace:\n                        break\n                    if s == b\"\":\n                        raise ValueError(\n                            \"File does not extend beyond magic number\")\n                if s != b\"#\":\n                    break\n                s = self.fp.readline()\n            s = int(self._token(s))\n            if ix == 0:\n                xsize = s\n            elif ix == 1:\n                ysize = s\n                if mode == \"1\":\n                    break\n            elif ix == 2:\n                # maxgrey\n                if s > 255:\n                    if not mode == 'L':\n                        raise ValueError(\"Too many colors for band: %s\" % s)\n                    if s < 2**16:\n                        self.mode = 'I'\n                        rawmode = 'I;16B'\n                    else:\n                        self.mode = 'I'\n                        rawmode = 'I;32B'\n\n        self._size = xsize, ysize\n        self.tile = [(\"raw\",\n                     (0, 0, xsize, ysize),\n                     self.fp.tell(),\n                     (rawmode, 0, 1))]",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 50,
                            "end_lineno": 116,
                            "parent": null
                        }
                    ],
                    "added_entities": [],
                    "deleted_entities": []
                },
                {
                    "descriptor": {
                        "old_range": {
                            "start": 158,
                            "length": 3
                        },
                        "new_range": {
                            "start": 165,
                            "length": 5
                        },
                        "section": "Image.register_open(PpmImageFile.format, PpmImageFile, _accept)"
                    },
                    "line_group": {
                        "all_lines": [
                            {
                                "content": "Image.register_save(PpmImageFile.format, _save)",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "Image.register_extensions(PpmImageFile.format, [\".pbm\", \".pgm\", \".ppm\"])",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "added"
                            },
                            {
                                "content": "Image.register_mime(PpmImageFile.format, \"image/x-portable-anymap\")",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "context"
                            }
                        ]
                    },
                    "modified_entities": [],
                    "added_entities": [
                        {
                            "file_name": "src/PIL/PpmImagePlugin.py",
                            "type": "statement",
                            "name": "",
                            "content": "Image.register_mime(PpmImageFile.format, \"image/x-portable-anymap\")",
                            "ast_type_str": "Expr",
                            "start_lineno": 169,
                            "end_lineno": 169,
                            "parent": null
                        }
                    ],
                    "deleted_entities": []
                }
            ]
        }
    ],
    "old_commit_hash": "975fccafc7ed857d33102e4b632efbb43f4988fb^",
    "new_commit_hash": "975fccafc7ed857d33102e4b632efbb43f4988fb",
    "commit_message": "Merge pull request #3688 from radarhere/mime\n\nAdd PPM mime types",
    "commit_date": "2019-03-05T19:04:11+02:00",
    "metadata": {}
}
{
    "repo_name": "pillow",
    "new_commit_hash": "975fccafc7ed857d33102e4b632efbb43f4988fb",
    "test_file_codes": [
        "from .helper import PillowTestCase\n\nfrom PIL import Image\n\n# sample ppm stream\ntest_file = \"Tests/images/hopper.ppm\"\n\n\nclass TestFilePpm(PillowTestCase):\n\n    def test_sanity(self):\n        im = Image.open(test_file)\n        im.load()\n        self.assertEqual(im.mode, \"RGB\")\n        self.assertEqual(im.size, (128, 128))\n        self.assertEqual(im.format, \"PPM\")\n        self.assertEqual(im.get_format_mimetype(), \"image/x-portable-pixmap\")\n\n    def test_16bit_pgm(self):\n        im = Image.open('Tests/images/16_bit_binary.pgm')\n        im.load()\n        self.assertEqual(im.mode, 'I')\n        self.assertEqual(im.size, (20, 100))\n        self.assertEqual(im.get_format_mimetype(), \"image/x-portable-graymap\")\n\n        tgt = Image.open('Tests/images/16_bit_binary_pgm.png')\n        self.assert_image_equal(im, tgt)\n\n    def test_16bit_pgm_write(self):\n        im = Image.open('Tests/images/16_bit_binary.pgm')\n        im.load()\n\n        f = self.tempfile('temp.pgm')\n        im.save(f, 'PPM')\n\n        reloaded = Image.open(f)\n        self.assert_image_equal(im, reloaded)\n\n    def test_truncated_file(self):\n        path = self.tempfile('temp.pgm')\n        with open(path, 'w') as f:\n            f.write('P6')\n\n        self.assertRaises(ValueError, Image.open, path)\n\n    def test_neg_ppm(self):\n        # Storage.c accepted negative values for xsize, ysize.  the\n        # internal open_ppm function didn't check for sanity but it\n        # has been removed. The default opener doesn't accept negative\n        # sizes.\n\n        with self.assertRaises(IOError):\n            Image.open('Tests/images/negative_size.ppm')\n\n    def test_mimetypes(self):\n        path = self.tempfile('temp.pgm')\n\n        with open(path, 'w') as f:\n            f.write(\"P4\\n128 128\\n255\")\n        im = Image.open(path)\n        self.assertEqual(im.get_format_mimetype(), \"image/x-portable-bitmap\")\n\n        with open(path, 'w') as f:\n            f.write(\"PyCMYK\\n128 128\\n255\")\n        im = Image.open(path)\n        self.assertEqual(im.get_format_mimetype(), \"image/x-portable-anymap\")\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 317ms\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 907ms\nPrepared 1 package in 32.29s\nInstalled 1 package in 1ms\n + pillow==6.0.0.dev0 (from file:///home/gcpuser/buckets/local_repoeval_bucket/repos/pillow_975fccafc7ed857d33102e4b632efbb43f4988fb)\n",
    "new_commit_res_code": 0,
    "new_commit_res_stdout": "============================= test session starts ==============================\nplatform linux -- Python 3.9.21, pytest-8.3.4, pluggy-1.5.0\nrootdir: /home/gcpuser/buckets/local_repoeval_bucket/repos/pillow_975fccafc7ed857d33102e4b632efbb43f4988fb\nplugins: cov-6.0.0\ncollected 6 items\n\nr2e_tests/test_1.py ......                                               [100%]\n\n==================================== PASSES ====================================\n=========================== short test summary info ============================\nPASSED r2e_tests/test_1.py::TestFilePpm::test_16bit_pgm\nPASSED r2e_tests/test_1.py::TestFilePpm::test_16bit_pgm_write\nPASSED r2e_tests/test_1.py::TestFilePpm::test_mimetypes\nPASSED r2e_tests/test_1.py::TestFilePpm::test_neg_ppm\nPASSED r2e_tests/test_1.py::TestFilePpm::test_sanity\nPASSED r2e_tests/test_1.py::TestFilePpm::test_truncated_file\n============================== 6 passed in 0.42s ===============================\n",
    "new_commit_res_stderr": "",
    "old_commit_res_code": 1,
    "old_commit_res_stdout": "============================= test session starts ==============================\nplatform linux -- Python 3.9.21, pytest-8.3.4, pluggy-1.5.0\nrootdir: /home/gcpuser/buckets/local_repoeval_bucket/repos/pillow_975fccafc7ed857d33102e4b632efbb43f4988fb\nplugins: cov-6.0.0\ncollected 6 items\n\nr2e_tests/test_1.py F.F.F.                                               [100%]\n\n=================================== FAILURES ===================================\n__________________________ TestFilePpm.test_16bit_pgm __________________________\n\nself = <r2e_tests.test_1.TestFilePpm testMethod=test_16bit_pgm>\n\n    def test_16bit_pgm(self):\n        im = Image.open('Tests/images/16_bit_binary.pgm')\n        im.load()\n        self.assertEqual(im.mode, 'I')\n        self.assertEqual(im.size, (20, 100))\n>       self.assertEqual(im.get_format_mimetype(), \"image/x-portable-graymap\")\nE       AssertionError: None != 'image/x-portable-graymap'\n\nr2e_tests/test_1.py:24: AssertionError\n__________________________ TestFilePpm.test_mimetypes __________________________\n\nself = <r2e_tests.test_1.TestFilePpm testMethod=test_mimetypes>\n\n    def test_mimetypes(self):\n        path = self.tempfile('temp.pgm')\n    \n        with open(path, 'w') as f:\n            f.write(\"P4\\n128 128\\n255\")\n        im = Image.open(path)\n>       self.assertEqual(im.get_format_mimetype(), \"image/x-portable-bitmap\")\nE       AssertionError: None != 'image/x-portable-bitmap'\n\nr2e_tests/test_1.py:61: AssertionError\n___________________________ TestFilePpm.test_sanity ____________________________\n\nself = <r2e_tests.test_1.TestFilePpm testMethod=test_sanity>\n\n    def test_sanity(self):\n        im = Image.open(test_file)\n        im.load()\n        self.assertEqual(im.mode, \"RGB\")\n        self.assertEqual(im.size, (128, 128))\n        self.assertEqual(im.format, \"PPM\")\n>       self.assertEqual(im.get_format_mimetype(), \"image/x-portable-pixmap\")\nE       AssertionError: None != 'image/x-portable-pixmap'\n\nr2e_tests/test_1.py:17: AssertionError\n==================================== PASSES ====================================\n=========================== short test summary info ============================\nPASSED r2e_tests/test_1.py::TestFilePpm::test_16bit_pgm_write\nPASSED r2e_tests/test_1.py::TestFilePpm::test_neg_ppm\nPASSED r2e_tests/test_1.py::TestFilePpm::test_truncated_file\nFAILED r2e_tests/test_1.py::TestFilePpm::test_16bit_pgm - AssertionError: Non...\nFAILED r2e_tests/test_1.py::TestFilePpm::test_mimetypes - AssertionError: Non...\nFAILED r2e_tests/test_1.py::TestFilePpm::test_sanity - AssertionError: None !...\n========================= 3 failed, 3 passed in 0.16s ==========================\n",
    "old_commit_res_stderr": ""
}
Tests/test_file_ppm.py src/PIL/PpmImagePlugin.py
We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
[ISSUE]
**Title:** PPM Images Return `None` for MIME Type Using `get_format_mimetype()`

**Description:**
When attempting to retrieve the MIME type of PPM (Portable Pixmap) images using the `get_format_mimetype()` method, the method returns `None` instead of the expected MIME type. This issue affects processes that rely on MIME types for handling image formats correctly.

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

im = Image.open('example.ppm')
im.load()
mime_type = im.get_format_mimetype()
print(mime_type)  # Expected: 'image/x-portable-pixmap', Got: None
```

**Expected Behavior:**
The `get_format_mimetype()` method should return the appropriate MIME type for PPM images, such as `'image/x-portable-pixmap'`. This allows systems and applications to correctly identify and handle PPM image files based on their MIME types.

**Actual Behavior:**
For PPM images, the `get_format_mimetype()` method returns `None`, preventing proper identification and handling of the image format. This can lead to issues in workflows that depend on MIME types for processing images.

[/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/PpmImagePlugin.py
#
# The Python Imaging Library.
# $Id$
#
# PPM support for PIL
#
# History:
#       96-03-24 fl     Created
#       98-03-06 fl     Write RGBA images (as RGB, that is)
#
# Copyright (c) Secret Labs AB 1997-98.
# Copyright (c) Fredrik Lundh 1996.
#
# See the README file for information on usage and redistribution.
#


from . import Image, ImageFile

# __version__ is deprecated and will be removed in a future version. Use
# PIL.__version__ instead.
__version__ = "0.2"

#
# --------------------------------------------------------------------

b_whitespace = b'\x20\x09\x0a\x0b\x0c\x0d'

MODES = {
    # standard
    b"P4": "1",
    b"P5": "L",
    b"P6": "RGB",
    # extensions
    b"P0CMYK": "CMYK",
    # PIL extensions (for test purposes only)
    b"PyP": "P",
    b"PyRGBA": "RGBA",
    b"PyCMYK": "CMYK"
}


def _accept(prefix):
    return prefix[0:1] == b"P" and prefix[1] in b"0456y"


##
# Image plugin for PBM, PGM, and PPM images.

class PpmImageFile(ImageFile.ImageFile):

    format = "PPM"
    format_description = "Pbmplus image"

    def _token(self, s=b""):
        while True:  # read until next whitespace
            c = self.fp.read(1)
            if not c or c in b_whitespace:
                break
            if c > b'\x79':
                raise ValueError("Expected ASCII value, found binary")
            s = s + c
            if (len(s) > 9):
                raise ValueError("Expected int, got > 9 digits")
        return s

    def _open(self):

        # check magic
        s = self.fp.read(1)
        if s != b"P":
            raise SyntaxError("not a PPM file")
        mode = MODES[self._token(s)]

        if mode == "1":
            self.mode = "1"
            rawmode = "1;I"
        else:
            self.mode = rawmode = mode

        for ix in range(3):
            while True:
                while True:
                    s = self.fp.read(1)
                    if s not in b_whitespace:
                        break
                    if s == b"":
                        raise ValueError(
                            "File does not extend beyond magic number")
                if s != b"#":
                    break
                s = self.fp.readline()
            s = int(self._token(s))
            if ix == 0:
                xsize = s
            elif ix == 1:
                ysize = s
                if mode == "1":
                    break
            elif ix == 2:
                # maxgrey
                if s > 255:
                    if not mode == 'L':
                        raise ValueError("Too many colors for band: %s" % s)
                    if s < 2**16:
                        self.mode = 'I'
                        rawmode = 'I;16B'
                    else:
                        self.mode = 'I'
                        rawmode = 'I;32B'

        self._size = xsize, ysize
        self.tile = [("raw",
                     (0, 0, xsize, ysize),
                     self.fp.tell(),
                     (rawmode, 0, 1))]


#
# --------------------------------------------------------------------

def _save(im, fp, filename):
    if im.mode == "1":
        rawmode, head = "1;I", b"P4"
    elif im.mode == "L":
        rawmode, head = "L", b"P5"
    elif im.mode == "I":
        if im.getextrema()[1] < 2**16:
            rawmode, head = "I;16B", b"P5"
        else:
            rawmode, head = "I;32B", b"P5"
    elif im.mode == "RGB":
        rawmode, head = "RGB", b"P6"
    elif im.mode == "RGBA":
        rawmode, head = "RGB", b"P6"
    else:
        raise IOError("cannot write mode %s as PPM" % im.mode)
    fp.write(head + ("\n%d %d\n" % im.size).encode('ascii'))
    if head == b"P6":
        fp.write(b"255\n")
    if head == b"P5":
        if rawmode == "L":
            fp.write(b"255\n")
        elif rawmode == "I;16B":
            fp.write(b"65535\n")
        elif rawmode == "I;32B":
            fp.write(b"2147483648\n")
    ImageFile._save(im, fp, [("raw", (0, 0)+im.size, 0, (rawmode, 0, 1))])

    # ALTERNATIVE: save via builtin debug function
    # im._dump(filename)

#
# --------------------------------------------------------------------


Image.register_open(PpmImageFile.format, PpmImageFile, _accept)
Image.register_save(PpmImageFile.format, _save)

Image.register_extensions(PpmImageFile.format, [".pbm", ".pgm", ".ppm"])

```
--- 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:** PPM Images Return `None` for MIME Type Using `get_format_mimetype()`

**Description:**
When attempting to retrieve the MIME type of PPM (Portable Pixmap) images using the `get_format_mimetype()` method, the method returns `None` instead of the expected MIME type. This issue affects processes that rely on MIME types for handling image formats correctly.

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

im = Image.open('example.ppm')
im.load()
mime_type = im.get_format_mimetype()
print(mime_type)  # Expected: 'image/x-portable-pixmap', Got: None
```

**Expected Behavior:**
The `get_format_mimetype()` method should return the appropriate MIME type for PPM images, such as `'image/x-portable-pixmap'`. This allows systems and applications to correctly identify and handle PPM image files based on their MIME types.

**Actual Behavior:**
For PPM images, the `get_format_mimetype()` method returns `None`, preventing proper identification and handling of the image format. This can lead to issues in workflows that depend on MIME types for processing images.

[/ISSUE]
{
    "TestFilePpm.test_16bit_pgm": "PASSED",
    "TestFilePpm.test_16bit_pgm_write": "PASSED",
    "TestFilePpm.test_mimetypes": "PASSED",
    "TestFilePpm.test_neg_ppm": "PASSED",
    "TestFilePpm.test_sanity": "PASSED",
    "TestFilePpm.test_truncated_file": "PASSED"
}
diff --git a/src/PIL/PpmImagePlugin.py b/src/PIL/PpmImagePlugin.py
index 750454dc5..e3e411cad 100644
--- a/src/PIL/PpmImagePlugin.py
+++ b/src/PIL/PpmImagePlugin.py
@@ -70,7 +70,14 @@ class PpmImageFile(ImageFile.ImageFile):
         s = self.fp.read(1)
         if s != b"P":
             raise SyntaxError("not a PPM file")
-        mode = MODES[self._token(s)]
+        magic_number = self._token(s)
+        mode = MODES[magic_number]
+
+        self.custom_mimetype = {
+            b"P4": "image/x-portable-bitmap",
+            b"P5": "image/x-portable-graymap",
+            b"P6": "image/x-portable-pixmap",
+        }.get(magic_number)
 
         if mode == "1":
             self.mode = "1"
@@ -158,3 +165,5 @@ Image.register_open(PpmImageFile.format, PpmImageFile, _accept)
 Image.register_save(PpmImageFile.format, _save)
 
 Image.register_extensions(PpmImageFile.format, [".pbm", ".pgm", ".ppm"])
+
+Image.register_mime(PpmImageFile.format, "image/x-portable-anymap")
 

{"src/PIL/PpmImagePlugin.py": "#\n# The Python Imaging Library.\n# $Id$\n#\n# PPM support for PIL\n#\n# History:\n#       96-03-24 fl     Created\n#       98-03-06 fl     Write RGBA images (as RGB, that is)\n#\n# Copyright (c) Secret Labs AB 1997-98.\n# Copyright (c) Fredrik Lundh 1996.\n#\n# See the README file for information on usage and redistribution.\n#\n\n\nfrom . import Image, ImageFile\n\n# __version__ is deprecated and will be removed in a future version. Use\n# PIL.__version__ instead.\n__version__ = \"0.2\"\n\n#\n# --------------------------------------------------------------------\n\nb_whitespace = b'\\x20\\x09\\x0a\\x0b\\x0c\\x0d'\n\nMODES = {\n    # standard\n    b\"P4\": \"1\",\n    b\"P5\": \"L\",\n    b\"P6\": \"RGB\",\n    # extensions\n    b\"P0CMYK\": \"CMYK\",\n    # PIL extensions (for test purposes only)\n    b\"PyP\": \"P\",\n    b\"PyRGBA\": \"RGBA\",\n    b\"PyCMYK\": \"CMYK\"\n}\n\n\ndef _accept(prefix):\n    return prefix[0:1] == b\"P\" and prefix[1] in b\"0456y\"\n\n\n##\n# Image plugin for PBM, PGM, and PPM images.\n\nclass PpmImageFile(ImageFile.ImageFile):\n\n    format = \"PPM\"\n    format_description = \"Pbmplus image\"\n\n    def _token(self, s=b\"\"):\n        while True:  # read until next whitespace\n            c = self.fp.read(1)\n            if not c or c in b_whitespace:\n                break\n            if c > b'\\x79':\n                raise ValueError(\"Expected ASCII value, found binary\")\n            s = s + c\n            if (len(s) > 9):\n                raise ValueError(\"Expected int, got > 9 digits\")\n        return s\n\n    def _open(self):\n\n        # check magic\n        s = self.fp.read(1)\n        if s != b\"P\":\n            raise SyntaxError(\"not a PPM file\")\n        mode = MODES[self._token(s)]\n\n        if mode == \"1\":\n            self.mode = \"1\"\n            rawmode = \"1;I\"\n        else:\n            self.mode = rawmode = mode\n\n        for ix in range(3):\n            while True:\n                while True:\n                    s = self.fp.read(1)\n                    if s not in b_whitespace:\n                        break\n                    if s == b\"\":\n                        raise ValueError(\n                            \"File does not extend beyond magic number\")\n                if s != b\"#\":\n                    break\n                s = self.fp.readline()\n            s = int(self._token(s))\n            if ix == 0:\n                xsize = s\n            elif ix == 1:\n                ysize = s\n                if mode == \"1\":\n                    break\n            elif ix == 2:\n                # maxgrey\n                if s > 255:\n                    if not mode == 'L':\n                        raise ValueError(\"Too many colors for band: %s\" % s)\n                    if s < 2**16:\n                        self.mode = 'I'\n                        rawmode = 'I;16B'\n                    else:\n                        self.mode = 'I'\n                        rawmode = 'I;32B'\n\n        self._size = xsize, ysize\n        self.tile = [(\"raw\",\n                     (0, 0, xsize, ysize),\n                     self.fp.tell(),\n                     (rawmode, 0, 1))]\n\n\n#\n# --------------------------------------------------------------------\n\ndef _save(im, fp, filename):\n    if im.mode == \"1\":\n        rawmode, head = \"1;I\", b\"P4\"\n    elif im.mode == \"L\":\n        rawmode, head = \"L\", b\"P5\"\n    elif im.mode == \"I\":\n        if im.getextrema()[1] < 2**16:\n            rawmode, head = \"I;16B\", b\"P5\"\n        else:\n            rawmode, head = \"I;32B\", b\"P5\"\n    elif im.mode == \"RGB\":\n        rawmode, head = \"RGB\", b\"P6\"\n    elif im.mode == \"RGBA\":\n        rawmode, head = \"RGB\", b\"P6\"\n    else:\n        raise IOError(\"cannot write mode %s as PPM\" % im.mode)\n    fp.write(head + (\"\\n%d %d\\n\" % im.size).encode('ascii'))\n    if head == b\"P6\":\n        fp.write(b\"255\\n\")\n    if head == b\"P5\":\n        if rawmode == \"L\":\n            fp.write(b\"255\\n\")\n        elif rawmode == \"I;16B\":\n            fp.write(b\"65535\\n\")\n        elif rawmode == \"I;32B\":\n            fp.write(b\"2147483648\\n\")\n    ImageFile._save(im, fp, [(\"raw\", (0, 0)+im.size, 0, (rawmode, 0, 1))])\n\n    # ALTERNATIVE: save via builtin debug function\n    # im._dump(filename)\n\n#\n# --------------------------------------------------------------------\n\n\nImage.register_open(PpmImageFile.format, PpmImageFile, _accept)\nImage.register_save(PpmImageFile.format, _save)\n\nImage.register_extensions(PpmImageFile.format, [\".pbm\", \".pgm\", \".ppm\"])\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:** PPM Images Return `None` for MIME Type Using `get_format_mimetype()`

**Description:**
When attempting to retrieve the MIME type of PPM (Portable Pixmap) images using the `get_format_mimetype()` method, the method returns `None` instead of the expected MIME type. This issue affects processes that rely on MIME types for handling image formats correctly.

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

im = Image.open('example.ppm')
im.load()
mime_type = im.get_format_mimetype()
print(mime_type)  # Expected: 'image/x-portable-pixmap', Got: None
```

**Expected Behavior:**
The `get_format_mimetype()` method should return the appropriate MIME type for PPM images, such as `'image/x-portable-pixmap'`. This allows systems and applications to correctly identify and handle PPM image files based on their MIME types.

**Actual Behavior:**
For PPM images, the `get_format_mimetype()` method returns `None`, preventing proper identification and handling of the image format. This can lead to issues in workflows that depend on MIME types for processing images.

[/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/PpmImagePlugin.py
#
# The Python Imaging Library.
# $Id$
#
# PPM support for PIL
#
# History:
#       96-03-24 fl     Created
#       98-03-06 fl     Write RGBA images (as RGB, that is)
#
# Copyright (c) Secret Labs AB 1997-98.
# Copyright (c) Fredrik Lundh 1996.
#
# See the README file for information on usage and redistribution.
#


from . import Image, ImageFile

# __version__ is deprecated and will be removed in a future version. Use
# PIL.__version__ instead.
__version__ = "0.2"

#
# --------------------------------------------------------------------

b_whitespace = b'\x20\x09\x0a\x0b\x0c\x0d'

MODES = {
    # standard
    b"P4": "1",
    b"P5": "L",
    b"P6": "RGB",
    # extensions
    b"P0CMYK": "CMYK",
    # PIL extensions (for test purposes only)
    b"PyP": "P",
    b"PyRGBA": "RGBA",
    b"PyCMYK": "CMYK"
}


def _accept(prefix):
    return prefix[0:1] == b"P" and prefix[1] in b"0456y"


##
# Image plugin for PBM, PGM, and PPM images.

class PpmImageFile(ImageFile.ImageFile):

    format = "PPM"
    format_description = "Pbmplus image"

    def _token(self, s=b""):
        while True:  # read until next whitespace
            c = self.fp.read(1)
            if not c or c in b_whitespace:
                break
            if c > b'\x79':
                raise ValueError("Expected ASCII value, found binary")
            s = s + c
            if (len(s) > 9):
                raise ValueError("Expected int, got > 9 digits")
        return s

    def _open(self):

        # check magic
        s = self.fp.read(1)
        if s != b"P":
            raise SyntaxError("not a PPM file")
        mode = MODES[self._token(s)]

        if mode == "1":
            self.mode = "1"
            rawmode = "1;I"
        else:
            self.mode = rawmode = mode

        for ix in range(3):
            while True:
                while True:
                    s = self.fp.read(1)
                    if s not in b_whitespace:
                        break
                    if s == b"":
                        raise ValueError(
                            "File does not extend beyond magic number")
                if s != b"#":
                    break
                s = self.fp.readline()
            s = int(self._token(s))
            if ix == 0:
                xsize = s
            elif ix == 1:
                ysize = s
                if mode == "1":
                    break
            elif ix == 2:
                # maxgrey
                if s > 255:
                    if not mode == 'L':
                        raise ValueError("Too many colors for band: %s" % s)
                    if s < 2**16:
                        self.mode = 'I'
                        rawmode = 'I;16B'
                    else:
                        self.mode = 'I'
                        rawmode = 'I;32B'

        self._size = xsize, ysize
        self.tile = [("raw",
                     (0, 0, xsize, ysize),
                     self.fp.tell(),
                     (rawmode, 0, 1))]


#
# --------------------------------------------------------------------

def _save(im, fp, filename):
    if im.mode == "1":
        rawmode, head = "1;I", b"P4"
    elif im.mode == "L":
        rawmode, head = "L", b"P5"
    elif im.mode == "I":
        if im.getextrema()[1] < 2**16:
            rawmode, head = "I;16B", b"P5"
        else:
            rawmode, head = "I;32B", b"P5"
    elif im.mode == "RGB":
        rawmode, head = "RGB", b"P6"
    elif im.mode == "RGBA":
        rawmode, head = "RGB", b"P6"
    else:
        raise IOError("cannot write mode %s as PPM" % im.mode)
    fp.write(head + ("\n%d %d\n" % im.size).encode('ascii'))
    if head == b"P6":
        fp.write(b"255\n")
    if head == b"P5":
        if rawmode == "L":
            fp.write(b"255\n")
        elif rawmode == "I;16B":
            fp.write(b"65535\n")
        elif rawmode == "I;32B":
            fp.write(b"2147483648\n")
    ImageFile._save(im, fp, [("raw", (0, 0)+im.size, 0, (rawmode, 0, 1))])

    # ALTERNATIVE: save via builtin debug function
    # im._dump(filename)

#
# --------------------------------------------------------------------


Image.register_open(PpmImageFile.format, PpmImageFile, _accept)
Image.register_save(PpmImageFile.format, _save)

Image.register_extensions(PpmImageFile.format, [".pbm", ".pgm", ".ppm"])

```
--- 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