{
    "file_diffs": [
        {
            "old_file_content": "import io\n\nimport pytest\nfrom PIL import features\n\nfrom .helper import skip_unless_feature\n\ntry:\n    from PIL import _webp\nexcept ImportError:\n    pass\n\n\ndef test_check():\n    # Check the correctness of the convenience function\n    for module in features.modules:\n        assert features.check_module(module) == features.check(module)\n    for codec in features.codecs:\n        assert features.check_codec(codec) == features.check(codec)\n    for feature in features.features:\n        assert features.check_feature(feature) == features.check(feature)\n\n\n@skip_unless_feature(\"webp\")\ndef test_webp_transparency():\n    assert features.check(\"transp_webp\") != _webp.WebPDecoderBuggyAlpha()\n    assert features.check(\"transp_webp\") == _webp.HAVE_TRANSPARENCY\n\n\n@skip_unless_feature(\"webp\")\ndef test_webp_mux():\n    assert features.check(\"webp_mux\") == _webp.HAVE_WEBPMUX\n\n\n@skip_unless_feature(\"webp\")\ndef test_webp_anim():\n    assert features.check(\"webp_anim\") == _webp.HAVE_WEBPANIM\n\n\ndef test_check_modules():\n    for feature in features.modules:\n        assert features.check_module(feature) in [True, False]\n    for feature in features.codecs:\n        assert features.check_codec(feature) in [True, False]\n\n\ndef test_supported_modules():\n    assert isinstance(features.get_supported_modules(), list)\n    assert isinstance(features.get_supported_codecs(), list)\n    assert isinstance(features.get_supported_features(), list)\n    assert isinstance(features.get_supported(), list)\n\n\ndef test_unsupported_codec():\n    # Arrange\n    codec = \"unsupported_codec\"\n    # Act / Assert\n    with pytest.raises(ValueError):\n        features.check_codec(codec)\n\n\ndef test_unsupported_module():\n    # Arrange\n    module = \"unsupported_module\"\n    # Act / Assert\n    with pytest.raises(ValueError):\n        features.check_module(module)\n\n\ndef test_pilinfo():\n    buf = io.StringIO()\n    features.pilinfo(buf)\n    out = buf.getvalue()\n    lines = out.splitlines()\n    assert lines[0] == \"-\" * 68\n    assert lines[1].startswith(\"Pillow \")\n    assert lines[2].startswith(\"Python \")\n    lines = lines[3:]\n    while lines[0].startswith(\"    \"):\n        lines = lines[1:]\n    assert lines[0] == \"-\" * 68\n    assert lines[1].startswith(\"Python modules loaded from \")\n    assert lines[2].startswith(\"Binary modules loaded from \")\n    assert lines[3] == \"-\" * 68\n    jpeg = (\n        \"\\n\"\n        + \"-\" * 68\n        + \"\\n\"\n        + \"JPEG image/jpeg\\n\"\n        + \"Extensions: .jfif, .jpe, .jpeg, .jpg\\n\"\n        + \"Features: open, save\\n\"\n        + \"-\" * 68\n        + \"\\n\"\n    )\n    assert jpeg in out\n",
            "new_file_content": "import io\n\nimport pytest\nfrom PIL import features\n\nfrom .helper import skip_unless_feature\n\ntry:\n    from PIL import _webp\nexcept ImportError:\n    pass\n\n\ndef test_check():\n    # Check the correctness of the convenience function\n    for module in features.modules:\n        assert features.check_module(module) == features.check(module)\n    for codec in features.codecs:\n        assert features.check_codec(codec) == features.check(codec)\n    for feature in features.features:\n        assert features.check_feature(feature) == features.check(feature)\n\n\n@skip_unless_feature(\"webp\")\ndef test_webp_transparency():\n    assert features.check(\"transp_webp\") != _webp.WebPDecoderBuggyAlpha()\n    assert features.check(\"transp_webp\") == _webp.HAVE_TRANSPARENCY\n\n\n@skip_unless_feature(\"webp\")\ndef test_webp_mux():\n    assert features.check(\"webp_mux\") == _webp.HAVE_WEBPMUX\n\n\n@skip_unless_feature(\"webp\")\ndef test_webp_anim():\n    assert features.check(\"webp_anim\") == _webp.HAVE_WEBPANIM\n\n\ndef test_check_modules():\n    for feature in features.modules:\n        assert features.check_module(feature) in [True, False]\n    for feature in features.codecs:\n        assert features.check_codec(feature) in [True, False]\n\n\ndef test_check_warns_on_nonexistent():\n    with pytest.warns(UserWarning) as cm:\n        has_feature = features.check(\"typo\")\n    assert has_feature is False\n    assert str(cm[-1].message) == \"Unknown feature 'typo'.\"\n\n\ndef test_supported_modules():\n    assert isinstance(features.get_supported_modules(), list)\n    assert isinstance(features.get_supported_codecs(), list)\n    assert isinstance(features.get_supported_features(), list)\n    assert isinstance(features.get_supported(), list)\n\n\ndef test_unsupported_codec():\n    # Arrange\n    codec = \"unsupported_codec\"\n    # Act / Assert\n    with pytest.raises(ValueError):\n        features.check_codec(codec)\n\n\ndef test_unsupported_module():\n    # Arrange\n    module = \"unsupported_module\"\n    # Act / Assert\n    with pytest.raises(ValueError):\n        features.check_module(module)\n\n\ndef test_pilinfo():\n    buf = io.StringIO()\n    features.pilinfo(buf)\n    out = buf.getvalue()\n    lines = out.splitlines()\n    assert lines[0] == \"-\" * 68\n    assert lines[1].startswith(\"Pillow \")\n    assert lines[2].startswith(\"Python \")\n    lines = lines[3:]\n    while lines[0].startswith(\"    \"):\n        lines = lines[1:]\n    assert lines[0] == \"-\" * 68\n    assert lines[1].startswith(\"Python modules loaded from \")\n    assert lines[2].startswith(\"Binary modules loaded from \")\n    assert lines[3] == \"-\" * 68\n    jpeg = (\n        \"\\n\"\n        + \"-\" * 68\n        + \"\\n\"\n        + \"JPEG image/jpeg\\n\"\n        + \"Extensions: .jfif, .jpe, .jpeg, .jpg\\n\"\n        + \"Features: open, save\\n\"\n        + \"-\" * 68\n        + \"\\n\"\n    )\n    assert jpeg in out\n",
            "header": {
                "file": {
                    "path": "Tests/test_features.py"
                },
                "misc_line": null
            },
            "index_line": {
                "old_commit_hash": "10799df33",
                "new_commit_hash": "7cfa08071",
                "mode": "100644"
            },
            "is_binary_file": false,
            "binary_line": null,
            "minus_file": {
                "path": "a/Tests/test_features.py"
            },
            "plus_file": {
                "path": "b/Tests/test_features.py"
            },
            "hunks": [
                {
                    "descriptor": {
                        "old_range": {
                            "start": 44,
                            "length": 6
                        },
                        "new_range": {
                            "start": 44,
                            "length": 13
                        },
                        "section": "def test_check_modules():"
                    },
                    "line_group": {
                        "all_lines": [
                            {
                                "content": "        assert features.check_codec(feature) in [True, False]",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "def test_check_warns_on_nonexistent():",
                                "type": "added"
                            },
                            {
                                "content": "    with pytest.warns(UserWarning) as cm:",
                                "type": "added"
                            },
                            {
                                "content": "        has_feature = features.check(\"typo\")",
                                "type": "added"
                            },
                            {
                                "content": "    assert has_feature is False",
                                "type": "added"
                            },
                            {
                                "content": "    assert str(cm[-1].message) == \"Unknown feature 'typo'.\"",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "added"
                            },
                            {
                                "content": "def test_supported_modules():",
                                "type": "context"
                            },
                            {
                                "content": "    assert isinstance(features.get_supported_modules(), list)",
                                "type": "context"
                            },
                            {
                                "content": "    assert isinstance(features.get_supported_codecs(), list)",
                                "type": "context"
                            }
                        ]
                    },
                    "modified_entities": [],
                    "added_entities": [
                        {
                            "file_name": "Tests/test_features.py",
                            "type": "function",
                            "name": "test_check_warns_on_nonexistent",
                            "content": "def test_check_warns_on_nonexistent():\n    with pytest.warns(UserWarning) as cm:\n        has_feature = features.check(\"typo\")\n    assert has_feature is False\n    assert str(cm[-1].message) == \"Unknown feature 'typo'.\"",
                            "ast_type_str": "FunctionDef",
                            "start_lineno": 47,
                            "end_lineno": 51,
                            "parent": null
                        }
                    ],
                    "deleted_entities": []
                }
            ]
        },
        {
            "old_file_content": "import collections\nimport os\nimport sys\n\nimport PIL\n\nfrom . import Image\n\nmodules = {\n    \"pil\": \"PIL._imaging\",\n    \"tkinter\": \"PIL._tkinter_finder\",\n    \"freetype2\": \"PIL._imagingft\",\n    \"littlecms2\": \"PIL._imagingcms\",\n    \"webp\": \"PIL._webp\",\n}\n\n\ndef check_module(feature):\n    if not (feature in modules):\n        raise ValueError(\"Unknown module %s\" % feature)\n\n    module = modules[feature]\n\n    try:\n        __import__(module)\n        return True\n    except ImportError:\n        return False\n\n\ndef get_supported_modules():\n    return [f for f in modules if check_module(f)]\n\n\ncodecs = {\"jpg\": \"jpeg\", \"jpg_2000\": \"jpeg2k\", \"zlib\": \"zip\", \"libtiff\": \"libtiff\"}\n\n\ndef check_codec(feature):\n    if feature not in codecs:\n        raise ValueError(\"Unknown codec %s\" % feature)\n\n    codec = codecs[feature]\n\n    return codec + \"_encoder\" in dir(Image.core)\n\n\ndef get_supported_codecs():\n    return [f for f in codecs if check_codec(f)]\n\n\nfeatures = {\n    \"webp_anim\": (\"PIL._webp\", \"HAVE_WEBPANIM\"),\n    \"webp_mux\": (\"PIL._webp\", \"HAVE_WEBPMUX\"),\n    \"transp_webp\": (\"PIL._webp\", \"HAVE_TRANSPARENCY\"),\n    \"raqm\": (\"PIL._imagingft\", \"HAVE_RAQM\"),\n    \"libjpeg_turbo\": (\"PIL._imaging\", \"HAVE_LIBJPEGTURBO\"),\n    \"libimagequant\": (\"PIL._imaging\", \"HAVE_LIBIMAGEQUANT\"),\n}\n\n\ndef check_feature(feature):\n    if feature not in features:\n        raise ValueError(\"Unknown feature %s\" % feature)\n\n    module, flag = features[feature]\n\n    try:\n        imported_module = __import__(module, fromlist=[\"PIL\"])\n        return getattr(imported_module, flag)\n    except ImportError:\n        return None\n\n\ndef get_supported_features():\n    return [f for f in features if check_feature(f)]\n\n\ndef check(feature):\n    return (\n        feature in modules\n        and check_module(feature)\n        or feature in codecs\n        and check_codec(feature)\n        or feature in features\n        and check_feature(feature)\n    )\n\n\ndef get_supported():\n    ret = get_supported_modules()\n    ret.extend(get_supported_features())\n    ret.extend(get_supported_codecs())\n    return ret\n\n\ndef pilinfo(out=None, supported_formats=True):\n    if out is None:\n        out = sys.stdout\n\n    Image.init()\n\n    print(\"-\" * 68, file=out)\n    print(\"Pillow {}\".format(PIL.__version__), file=out)\n    py_version = sys.version.splitlines()\n    print(\"Python {}\".format(py_version[0].strip()), file=out)\n    for py_version in py_version[1:]:\n        print(\"       {}\".format(py_version.strip()), file=out)\n    print(\"-\" * 68, file=out)\n    print(\n        \"Python modules loaded from {}\".format(os.path.dirname(Image.__file__)),\n        file=out,\n    )\n    print(\n        \"Binary modules loaded from {}\".format(os.path.dirname(Image.core.__file__)),\n        file=out,\n    )\n    print(\"-\" * 68, file=out)\n\n    for name, feature in [\n        (\"pil\", \"PIL CORE\"),\n        (\"tkinter\", \"TKINTER\"),\n        (\"freetype2\", \"FREETYPE2\"),\n        (\"littlecms2\", \"LITTLECMS2\"),\n        (\"webp\", \"WEBP\"),\n        (\"transp_webp\", \"WEBP Transparency\"),\n        (\"webp_mux\", \"WEBPMUX\"),\n        (\"webp_anim\", \"WEBP Animation\"),\n        (\"jpg\", \"JPEG\"),\n        (\"jpg_2000\", \"OPENJPEG (JPEG2000)\"),\n        (\"zlib\", \"ZLIB (PNG/ZIP)\"),\n        (\"libtiff\", \"LIBTIFF\"),\n        (\"raqm\", \"RAQM (Bidirectional Text)\"),\n        (\"libimagequant\", \"LIBIMAGEQUANT (Quantization method)\"),\n    ]:\n        if check(name):\n            print(\"---\", feature, \"support ok\", file=out)\n        else:\n            print(\"***\", feature, \"support not installed\", file=out)\n    print(\"-\" * 68, file=out)\n\n    if supported_formats:\n        extensions = collections.defaultdict(list)\n        for ext, i in Image.EXTENSION.items():\n            extensions[i].append(ext)\n\n        for i in sorted(Image.ID):\n            line = \"{}\".format(i)\n            if i in Image.MIME:\n                line = \"{} {}\".format(line, Image.MIME[i])\n            print(line, file=out)\n\n            if i in extensions:\n                print(\n                    \"Extensions: {}\".format(\", \".join(sorted(extensions[i]))), file=out\n                )\n\n            features = []\n            if i in Image.OPEN:\n                features.append(\"open\")\n            if i in Image.SAVE:\n                features.append(\"save\")\n            if i in Image.SAVE_ALL:\n                features.append(\"save_all\")\n            if i in Image.DECODERS:\n                features.append(\"decode\")\n            if i in Image.ENCODERS:\n                features.append(\"encode\")\n\n            print(\"Features: {}\".format(\", \".join(features)), file=out)\n            print(\"-\" * 68, file=out)\n",
            "new_file_content": "import collections\nimport os\nimport sys\nimport warnings\n\nimport PIL\n\nfrom . import Image\n\nmodules = {\n    \"pil\": \"PIL._imaging\",\n    \"tkinter\": \"PIL._tkinter_finder\",\n    \"freetype2\": \"PIL._imagingft\",\n    \"littlecms2\": \"PIL._imagingcms\",\n    \"webp\": \"PIL._webp\",\n}\n\n\ndef check_module(feature):\n    if not (feature in modules):\n        raise ValueError(\"Unknown module %s\" % feature)\n\n    module = modules[feature]\n\n    try:\n        __import__(module)\n        return True\n    except ImportError:\n        return False\n\n\ndef get_supported_modules():\n    return [f for f in modules if check_module(f)]\n\n\ncodecs = {\"jpg\": \"jpeg\", \"jpg_2000\": \"jpeg2k\", \"zlib\": \"zip\", \"libtiff\": \"libtiff\"}\n\n\ndef check_codec(feature):\n    if feature not in codecs:\n        raise ValueError(\"Unknown codec %s\" % feature)\n\n    codec = codecs[feature]\n\n    return codec + \"_encoder\" in dir(Image.core)\n\n\ndef get_supported_codecs():\n    return [f for f in codecs if check_codec(f)]\n\n\nfeatures = {\n    \"webp_anim\": (\"PIL._webp\", \"HAVE_WEBPANIM\"),\n    \"webp_mux\": (\"PIL._webp\", \"HAVE_WEBPMUX\"),\n    \"transp_webp\": (\"PIL._webp\", \"HAVE_TRANSPARENCY\"),\n    \"raqm\": (\"PIL._imagingft\", \"HAVE_RAQM\"),\n    \"libjpeg_turbo\": (\"PIL._imaging\", \"HAVE_LIBJPEGTURBO\"),\n    \"libimagequant\": (\"PIL._imaging\", \"HAVE_LIBIMAGEQUANT\"),\n}\n\n\ndef check_feature(feature):\n    if feature not in features:\n        raise ValueError(\"Unknown feature %s\" % feature)\n\n    module, flag = features[feature]\n\n    try:\n        imported_module = __import__(module, fromlist=[\"PIL\"])\n        return getattr(imported_module, flag)\n    except ImportError:\n        return None\n\n\ndef get_supported_features():\n    return [f for f in features if check_feature(f)]\n\n\ndef check(feature):\n    if feature in modules:\n        return check_module(feature)\n    if feature in codecs:\n        return check_codec(feature)\n    if feature in features:\n        return check_feature(feature)\n    warnings.warn(\"Unknown feature '%s'.\" % feature, stacklevel=2)\n    return False\n\n\ndef get_supported():\n    ret = get_supported_modules()\n    ret.extend(get_supported_features())\n    ret.extend(get_supported_codecs())\n    return ret\n\n\ndef pilinfo(out=None, supported_formats=True):\n    if out is None:\n        out = sys.stdout\n\n    Image.init()\n\n    print(\"-\" * 68, file=out)\n    print(\"Pillow {}\".format(PIL.__version__), file=out)\n    py_version = sys.version.splitlines()\n    print(\"Python {}\".format(py_version[0].strip()), file=out)\n    for py_version in py_version[1:]:\n        print(\"       {}\".format(py_version.strip()), file=out)\n    print(\"-\" * 68, file=out)\n    print(\n        \"Python modules loaded from {}\".format(os.path.dirname(Image.__file__)),\n        file=out,\n    )\n    print(\n        \"Binary modules loaded from {}\".format(os.path.dirname(Image.core.__file__)),\n        file=out,\n    )\n    print(\"-\" * 68, file=out)\n\n    for name, feature in [\n        (\"pil\", \"PIL CORE\"),\n        (\"tkinter\", \"TKINTER\"),\n        (\"freetype2\", \"FREETYPE2\"),\n        (\"littlecms2\", \"LITTLECMS2\"),\n        (\"webp\", \"WEBP\"),\n        (\"transp_webp\", \"WEBP Transparency\"),\n        (\"webp_mux\", \"WEBPMUX\"),\n        (\"webp_anim\", \"WEBP Animation\"),\n        (\"jpg\", \"JPEG\"),\n        (\"jpg_2000\", \"OPENJPEG (JPEG2000)\"),\n        (\"zlib\", \"ZLIB (PNG/ZIP)\"),\n        (\"libtiff\", \"LIBTIFF\"),\n        (\"raqm\", \"RAQM (Bidirectional Text)\"),\n        (\"libimagequant\", \"LIBIMAGEQUANT (Quantization method)\"),\n    ]:\n        if check(name):\n            print(\"---\", feature, \"support ok\", file=out)\n        else:\n            print(\"***\", feature, \"support not installed\", file=out)\n    print(\"-\" * 68, file=out)\n\n    if supported_formats:\n        extensions = collections.defaultdict(list)\n        for ext, i in Image.EXTENSION.items():\n            extensions[i].append(ext)\n\n        for i in sorted(Image.ID):\n            line = \"{}\".format(i)\n            if i in Image.MIME:\n                line = \"{} {}\".format(line, Image.MIME[i])\n            print(line, file=out)\n\n            if i in extensions:\n                print(\n                    \"Extensions: {}\".format(\", \".join(sorted(extensions[i]))), file=out\n                )\n\n            features = []\n            if i in Image.OPEN:\n                features.append(\"open\")\n            if i in Image.SAVE:\n                features.append(\"save\")\n            if i in Image.SAVE_ALL:\n                features.append(\"save_all\")\n            if i in Image.DECODERS:\n                features.append(\"decode\")\n            if i in Image.ENCODERS:\n                features.append(\"encode\")\n\n            print(\"Features: {}\".format(\", \".join(features)), file=out)\n            print(\"-\" * 68, file=out)\n",
            "header": {
                "file": {
                    "path": "src/PIL/features.py"
                },
                "misc_line": null
            },
            "index_line": {
                "old_commit_hash": "5822febab",
                "new_commit_hash": "0a1d5d611",
                "mode": "100644"
            },
            "is_binary_file": false,
            "binary_line": null,
            "minus_file": {
                "path": "a/src/PIL/features.py"
            },
            "plus_file": {
                "path": "b/src/PIL/features.py"
            },
            "hunks": [
                {
                    "descriptor": {
                        "old_range": {
                            "start": 1,
                            "length": 6
                        },
                        "new_range": {
                            "start": 1,
                            "length": 7
                        },
                        "section": ""
                    },
                    "line_group": {
                        "all_lines": [
                            {
                                "content": "import collections",
                                "type": "context"
                            },
                            {
                                "content": "import os",
                                "type": "context"
                            },
                            {
                                "content": "import sys",
                                "type": "context"
                            },
                            {
                                "content": "import warnings",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "import PIL",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            }
                        ]
                    },
                    "modified_entities": [],
                    "added_entities": [
                        {
                            "file_name": "src/PIL/features.py",
                            "type": "import",
                            "name": "warnings",
                            "content": "import warnings",
                            "ast_type_str": "Import",
                            "start_lineno": 4,
                            "end_lineno": 4,
                            "parent": null
                        }
                    ],
                    "deleted_entities": []
                },
                {
                    "descriptor": {
                        "old_range": {
                            "start": 76,
                            "length": 14
                        },
                        "new_range": {
                            "start": 77,
                            "length": 14
                        },
                        "section": "def get_supported_features():"
                    },
                    "line_group": {
                        "all_lines": [
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "def check(feature):",
                                "type": "context"
                            },
                            {
                                "content": "    return (",
                                "type": "deleted"
                            },
                            {
                                "content": "        feature in modules",
                                "type": "deleted"
                            },
                            {
                                "content": "        and check_module(feature)",
                                "type": "deleted"
                            },
                            {
                                "content": "        or feature in codecs",
                                "type": "deleted"
                            },
                            {
                                "content": "        and check_codec(feature)",
                                "type": "deleted"
                            },
                            {
                                "content": "        or feature in features",
                                "type": "deleted"
                            },
                            {
                                "content": "        and check_feature(feature)",
                                "type": "deleted"
                            },
                            {
                                "content": "    )",
                                "type": "deleted"
                            },
                            {
                                "content": "    if feature in modules:",
                                "type": "added"
                            },
                            {
                                "content": "        return check_module(feature)",
                                "type": "added"
                            },
                            {
                                "content": "    if feature in codecs:",
                                "type": "added"
                            },
                            {
                                "content": "        return check_codec(feature)",
                                "type": "added"
                            },
                            {
                                "content": "    if feature in features:",
                                "type": "added"
                            },
                            {
                                "content": "        return check_feature(feature)",
                                "type": "added"
                            },
                            {
                                "content": "    warnings.warn(\"Unknown feature '%s'.\" % feature, stacklevel=2)",
                                "type": "added"
                            },
                            {
                                "content": "    return False",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "def get_supported():",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            }
                        ]
                    },
                    "modified_entities": [
                        {
                            "file_name": "src/PIL/features.py",
                            "type": "function",
                            "name": "check",
                            "content": "def check(feature):\n    return (\n        feature in modules\n        and check_module(feature)\n        or feature in codecs\n        and check_codec(feature)\n        or feature in features\n        and check_feature(feature)\n    )",
                            "ast_type_str": "FunctionDef",
                            "start_lineno": 78,
                            "end_lineno": 86,
                            "parent": null
                        }
                    ],
                    "added_entities": [],
                    "deleted_entities": []
                }
            ]
        }
    ],
    "old_commit_hash": "974233be45a801f6bf4719aa37cc7e7b603c1630^",
    "new_commit_hash": "974233be45a801f6bf4719aa37cc7e7b603c1630",
    "commit_message": "Merge pull request #4438 from jdufresne/warning\n\nWarn on typos passed to features.check()",
    "commit_date": "2020-03-02T21:26:17+02:00",
    "metadata": {}
}
{
    "repo_name": "pillow",
    "new_commit_hash": "974233be45a801f6bf4719aa37cc7e7b603c1630",
    "test_file_codes": [
        "import io\n\nimport pytest\nfrom PIL import features\n\nfrom .helper import skip_unless_feature\n\ntry:\n    from PIL import _webp\nexcept ImportError:\n    pass\n\n\ndef test_check():\n    # Check the correctness of the convenience function\n    for module in features.modules:\n        assert features.check_module(module) == features.check(module)\n    for codec in features.codecs:\n        assert features.check_codec(codec) == features.check(codec)\n    for feature in features.features:\n        assert features.check_feature(feature) == features.check(feature)\n\n\n@skip_unless_feature(\"webp\")\ndef test_webp_transparency():\n    assert features.check(\"transp_webp\") != _webp.WebPDecoderBuggyAlpha()\n    assert features.check(\"transp_webp\") == _webp.HAVE_TRANSPARENCY\n\n\n@skip_unless_feature(\"webp\")\ndef test_webp_mux():\n    assert features.check(\"webp_mux\") == _webp.HAVE_WEBPMUX\n\n\n@skip_unless_feature(\"webp\")\ndef test_webp_anim():\n    assert features.check(\"webp_anim\") == _webp.HAVE_WEBPANIM\n\n\ndef test_check_modules():\n    for feature in features.modules:\n        assert features.check_module(feature) in [True, False]\n    for feature in features.codecs:\n        assert features.check_codec(feature) in [True, False]\n\n\ndef test_check_warns_on_nonexistent():\n    with pytest.warns(UserWarning) as cm:\n        has_feature = features.check(\"typo\")\n    assert has_feature is False\n    assert str(cm[-1].message) == \"Unknown feature 'typo'.\"\n\n\ndef test_supported_modules():\n    assert isinstance(features.get_supported_modules(), list)\n    assert isinstance(features.get_supported_codecs(), list)\n    assert isinstance(features.get_supported_features(), list)\n    assert isinstance(features.get_supported(), list)\n\n\ndef test_unsupported_codec():\n    # Arrange\n    codec = \"unsupported_codec\"\n    # Act / Assert\n    with pytest.raises(ValueError):\n        features.check_codec(codec)\n\n\ndef test_unsupported_module():\n    # Arrange\n    module = \"unsupported_module\"\n    # Act / Assert\n    with pytest.raises(ValueError):\n        features.check_module(module)\n\n\ndef test_pilinfo():\n    buf = io.StringIO()\n    features.pilinfo(buf)\n    out = buf.getvalue()\n    lines = out.splitlines()\n    assert lines[0] == \"-\" * 68\n    assert lines[1].startswith(\"Pillow \")\n    assert lines[2].startswith(\"Python \")\n    lines = lines[3:]\n    while lines[0].startswith(\"    \"):\n        lines = lines[1:]\n    assert lines[0] == \"-\" * 68\n    assert lines[1].startswith(\"Python modules loaded from \")\n    assert lines[2].startswith(\"Binary modules loaded from \")\n    assert lines[3] == \"-\" * 68\n    jpeg = (\n        \"\\n\"\n        + \"-\" * 68\n        + \"\\n\"\n        + \"JPEG image/jpeg\\n\"\n        + \"Extensions: .jfif, .jpe, .jpeg, .jpg\\n\"\n        + \"Features: open, save\\n\"\n        + \"-\" * 68\n        + \"\\n\"\n    )\n    assert jpeg in out\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 11ms\nInstalled 12 packages in 193ms\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 890ms\nPrepared 1 package in 33.00s\nInstalled 1 package in 1ms\n + pillow==7.1.0.dev0 (from file:///home/gcpuser/buckets/local_repoeval_bucket/repos/pillow_974233be45a801f6bf4719aa37cc7e7b603c1630)\n",
    "new_commit_res_code": 1,
    "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_974233be45a801f6bf4719aa37cc7e7b603c1630\nconfigfile: setup.cfg\nplugins: cov-6.0.0\ncollected 10 items\n\nr2e_tests/test_1.py F...F.F..F                                           [100%]\n\n=================================== FAILURES ===================================\n__________________________________ test_check __________________________________\n\n    def test_check():\n        # Check the correctness of the convenience function\n        for module in features.modules:\n>           assert features.check_module(module) == features.check(module)\n\nr2e_tests/test_1.py:17: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \nsrc/PIL/features.py:26: in check_module\n    __import__(module)\n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\n    \"\"\" Find compiled module linking to Tcl / Tk libraries\n    \"\"\"\n    import sys\n    from tkinter import _tkinter as tk\n    \n    if hasattr(sys, \"pypy_find_executable\"):\n        # Tested with packages at https://bitbucket.org/pypy/pypy/downloads.\n        # PyPies 1.6, 2.0 do not have tkinter built in.  PyPy3-2.3.1 gives an\n        # OSError trying to import tkinter. Otherwise:\n        try:  # PyPy 5.1, 4.0.0, 2.6.1, 2.6.0\n            TKINTER_LIB = tk.tklib_cffi.__file__\n        except AttributeError:\n            # PyPy3 2.4, 2.1-beta1; PyPy 2.5.1, 2.5.0, 2.4.0, 2.3, 2.2, 2.1\n            TKINTER_LIB = tk.tkffi.verifier.modulefilename\n    else:\n>       TKINTER_LIB = tk.__file__\nE       AttributeError: module '_tkinter' has no attribute '__file__'\n\nsrc/PIL/_tkinter_finder.py:16: AttributeError\n______________________________ test_check_modules ______________________________\n\n    def test_check_modules():\n        for feature in features.modules:\n>           assert features.check_module(feature) in [True, False]\n\nr2e_tests/test_1.py:42: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \nsrc/PIL/features.py:26: in check_module\n    __import__(module)\n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\n    \"\"\" Find compiled module linking to Tcl / Tk libraries\n    \"\"\"\n    import sys\n    from tkinter import _tkinter as tk\n    \n    if hasattr(sys, \"pypy_find_executable\"):\n        # Tested with packages at https://bitbucket.org/pypy/pypy/downloads.\n        # PyPies 1.6, 2.0 do not have tkinter built in.  PyPy3-2.3.1 gives an\n        # OSError trying to import tkinter. Otherwise:\n        try:  # PyPy 5.1, 4.0.0, 2.6.1, 2.6.0\n            TKINTER_LIB = tk.tklib_cffi.__file__\n        except AttributeError:\n            # PyPy3 2.4, 2.1-beta1; PyPy 2.5.1, 2.5.0, 2.4.0, 2.3, 2.2, 2.1\n            TKINTER_LIB = tk.tkffi.verifier.modulefilename\n    else:\n>       TKINTER_LIB = tk.__file__\nE       AttributeError: module '_tkinter' has no attribute '__file__'\n\nsrc/PIL/_tkinter_finder.py:16: AttributeError\n____________________________ test_supported_modules ____________________________\n\n    def test_supported_modules():\n>       assert isinstance(features.get_supported_modules(), list)\n\nr2e_tests/test_1.py:55: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \nsrc/PIL/features.py:33: in get_supported_modules\n    return [f for f in modules if check_module(f)]\nsrc/PIL/features.py:33: in <listcomp>\n    return [f for f in modules if check_module(f)]\nsrc/PIL/features.py:26: in check_module\n    __import__(module)\n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\n    \"\"\" Find compiled module linking to Tcl / Tk libraries\n    \"\"\"\n    import sys\n    from tkinter import _tkinter as tk\n    \n    if hasattr(sys, \"pypy_find_executable\"):\n        # Tested with packages at https://bitbucket.org/pypy/pypy/downloads.\n        # PyPies 1.6, 2.0 do not have tkinter built in.  PyPy3-2.3.1 gives an\n        # OSError trying to import tkinter. Otherwise:\n        try:  # PyPy 5.1, 4.0.0, 2.6.1, 2.6.0\n            TKINTER_LIB = tk.tklib_cffi.__file__\n        except AttributeError:\n            # PyPy3 2.4, 2.1-beta1; PyPy 2.5.1, 2.5.0, 2.4.0, 2.3, 2.2, 2.1\n            TKINTER_LIB = tk.tkffi.verifier.modulefilename\n    else:\n>       TKINTER_LIB = tk.__file__\nE       AttributeError: module '_tkinter' has no attribute '__file__'\n\nsrc/PIL/_tkinter_finder.py:16: AttributeError\n_________________________________ test_pilinfo _________________________________\n\n    def test_pilinfo():\n        buf = io.StringIO()\n>       features.pilinfo(buf)\n\nr2e_tests/test_1.py:79: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \nsrc/PIL/features.py:136: in pilinfo\n    if check(name):\nsrc/PIL/features.py:81: in check\n    return check_module(feature)\nsrc/PIL/features.py:26: in check_module\n    __import__(module)\n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\n    \"\"\" Find compiled module linking to Tcl / Tk libraries\n    \"\"\"\n    import sys\n    from tkinter import _tkinter as tk\n    \n    if hasattr(sys, \"pypy_find_executable\"):\n        # Tested with packages at https://bitbucket.org/pypy/pypy/downloads.\n        # PyPies 1.6, 2.0 do not have tkinter built in.  PyPy3-2.3.1 gives an\n        # OSError trying to import tkinter. Otherwise:\n        try:  # PyPy 5.1, 4.0.0, 2.6.1, 2.6.0\n            TKINTER_LIB = tk.tklib_cffi.__file__\n        except AttributeError:\n            # PyPy3 2.4, 2.1-beta1; PyPy 2.5.1, 2.5.0, 2.4.0, 2.3, 2.2, 2.1\n            TKINTER_LIB = tk.tkffi.verifier.modulefilename\n    else:\n>       TKINTER_LIB = tk.__file__\nE       AttributeError: module '_tkinter' has no attribute '__file__'\n\nsrc/PIL/_tkinter_finder.py:16: AttributeError\n==================================== PASSES ====================================\n=========================== short test summary info ============================\nPASSED r2e_tests/test_1.py::test_webp_transparency\nPASSED r2e_tests/test_1.py::test_webp_mux\nPASSED r2e_tests/test_1.py::test_webp_anim\nPASSED r2e_tests/test_1.py::test_check_warns_on_nonexistent\nPASSED r2e_tests/test_1.py::test_unsupported_codec\nPASSED r2e_tests/test_1.py::test_unsupported_module\nFAILED r2e_tests/test_1.py::test_check - AttributeError: module '_tkinter' ha...\nFAILED r2e_tests/test_1.py::test_check_modules - AttributeError: module '_tki...\nFAILED r2e_tests/test_1.py::test_supported_modules - AttributeError: module '...\nFAILED r2e_tests/test_1.py::test_pilinfo - AttributeError: module '_tkinter' ...\n========================= 4 failed, 6 passed in 0.23s ==========================\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_974233be45a801f6bf4719aa37cc7e7b603c1630\nconfigfile: setup.cfg\nplugins: cov-6.0.0\ncollected 10 items\n\nr2e_tests/test_1.py F...FFF..F                                           [100%]\n\n=================================== FAILURES ===================================\n__________________________________ test_check __________________________________\n\n    def test_check():\n        # Check the correctness of the convenience function\n        for module in features.modules:\n>           assert features.check_module(module) == features.check(module)\n\nr2e_tests/test_1.py:17: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \nsrc/PIL/features.py:25: in check_module\n    __import__(module)\n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\n    \"\"\" Find compiled module linking to Tcl / Tk libraries\n    \"\"\"\n    import sys\n    from tkinter import _tkinter as tk\n    \n    if hasattr(sys, \"pypy_find_executable\"):\n        # Tested with packages at https://bitbucket.org/pypy/pypy/downloads.\n        # PyPies 1.6, 2.0 do not have tkinter built in.  PyPy3-2.3.1 gives an\n        # OSError trying to import tkinter. Otherwise:\n        try:  # PyPy 5.1, 4.0.0, 2.6.1, 2.6.0\n            TKINTER_LIB = tk.tklib_cffi.__file__\n        except AttributeError:\n            # PyPy3 2.4, 2.1-beta1; PyPy 2.5.1, 2.5.0, 2.4.0, 2.3, 2.2, 2.1\n            TKINTER_LIB = tk.tkffi.verifier.modulefilename\n    else:\n>       TKINTER_LIB = tk.__file__\nE       AttributeError: module '_tkinter' has no attribute '__file__'\n\nsrc/PIL/_tkinter_finder.py:16: AttributeError\n______________________________ test_check_modules ______________________________\n\n    def test_check_modules():\n        for feature in features.modules:\n>           assert features.check_module(feature) in [True, False]\n\nr2e_tests/test_1.py:42: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \nsrc/PIL/features.py:25: in check_module\n    __import__(module)\n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\n    \"\"\" Find compiled module linking to Tcl / Tk libraries\n    \"\"\"\n    import sys\n    from tkinter import _tkinter as tk\n    \n    if hasattr(sys, \"pypy_find_executable\"):\n        # Tested with packages at https://bitbucket.org/pypy/pypy/downloads.\n        # PyPies 1.6, 2.0 do not have tkinter built in.  PyPy3-2.3.1 gives an\n        # OSError trying to import tkinter. Otherwise:\n        try:  # PyPy 5.1, 4.0.0, 2.6.1, 2.6.0\n            TKINTER_LIB = tk.tklib_cffi.__file__\n        except AttributeError:\n            # PyPy3 2.4, 2.1-beta1; PyPy 2.5.1, 2.5.0, 2.4.0, 2.3, 2.2, 2.1\n            TKINTER_LIB = tk.tkffi.verifier.modulefilename\n    else:\n>       TKINTER_LIB = tk.__file__\nE       AttributeError: module '_tkinter' has no attribute '__file__'\n\nsrc/PIL/_tkinter_finder.py:16: AttributeError\n_______________________ test_check_warns_on_nonexistent ________________________\n\n    def test_check_warns_on_nonexistent():\n        with pytest.warns(UserWarning) as cm:\n>           has_feature = features.check(\"typo\")\nE           Failed: DID NOT WARN. No warnings of type (<class 'UserWarning'>,) were emitted.\nE            Emitted warnings: [].\n\nr2e_tests/test_1.py:49: Failed\n____________________________ test_supported_modules ____________________________\n\n    def test_supported_modules():\n>       assert isinstance(features.get_supported_modules(), list)\n\nr2e_tests/test_1.py:55: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \nsrc/PIL/features.py:32: in get_supported_modules\n    return [f for f in modules if check_module(f)]\nsrc/PIL/features.py:32: in <listcomp>\n    return [f for f in modules if check_module(f)]\nsrc/PIL/features.py:25: in check_module\n    __import__(module)\n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\n    \"\"\" Find compiled module linking to Tcl / Tk libraries\n    \"\"\"\n    import sys\n    from tkinter import _tkinter as tk\n    \n    if hasattr(sys, \"pypy_find_executable\"):\n        # Tested with packages at https://bitbucket.org/pypy/pypy/downloads.\n        # PyPies 1.6, 2.0 do not have tkinter built in.  PyPy3-2.3.1 gives an\n        # OSError trying to import tkinter. Otherwise:\n        try:  # PyPy 5.1, 4.0.0, 2.6.1, 2.6.0\n            TKINTER_LIB = tk.tklib_cffi.__file__\n        except AttributeError:\n            # PyPy3 2.4, 2.1-beta1; PyPy 2.5.1, 2.5.0, 2.4.0, 2.3, 2.2, 2.1\n            TKINTER_LIB = tk.tkffi.verifier.modulefilename\n    else:\n>       TKINTER_LIB = tk.__file__\nE       AttributeError: module '_tkinter' has no attribute '__file__'\n\nsrc/PIL/_tkinter_finder.py:16: AttributeError\n_________________________________ test_pilinfo _________________________________\n\n    def test_pilinfo():\n        buf = io.StringIO()\n>       features.pilinfo(buf)\n\nr2e_tests/test_1.py:79: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \nsrc/PIL/features.py:135: in pilinfo\n    if check(name):\nsrc/PIL/features.py:81: in check\n    and check_module(feature)\nsrc/PIL/features.py:25: in check_module\n    __import__(module)\n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\n    \"\"\" Find compiled module linking to Tcl / Tk libraries\n    \"\"\"\n    import sys\n    from tkinter import _tkinter as tk\n    \n    if hasattr(sys, \"pypy_find_executable\"):\n        # Tested with packages at https://bitbucket.org/pypy/pypy/downloads.\n        # PyPies 1.6, 2.0 do not have tkinter built in.  PyPy3-2.3.1 gives an\n        # OSError trying to import tkinter. Otherwise:\n        try:  # PyPy 5.1, 4.0.0, 2.6.1, 2.6.0\n            TKINTER_LIB = tk.tklib_cffi.__file__\n        except AttributeError:\n            # PyPy3 2.4, 2.1-beta1; PyPy 2.5.1, 2.5.0, 2.4.0, 2.3, 2.2, 2.1\n            TKINTER_LIB = tk.tkffi.verifier.modulefilename\n    else:\n>       TKINTER_LIB = tk.__file__\nE       AttributeError: module '_tkinter' has no attribute '__file__'\n\nsrc/PIL/_tkinter_finder.py:16: AttributeError\n==================================== PASSES ====================================\n=========================== short test summary info ============================\nPASSED r2e_tests/test_1.py::test_webp_transparency\nPASSED r2e_tests/test_1.py::test_webp_mux\nPASSED r2e_tests/test_1.py::test_webp_anim\nPASSED r2e_tests/test_1.py::test_unsupported_codec\nPASSED r2e_tests/test_1.py::test_unsupported_module\nFAILED r2e_tests/test_1.py::test_check - AttributeError: module '_tkinter' ha...\nFAILED r2e_tests/test_1.py::test_check_modules - AttributeError: module '_tki...\nFAILED r2e_tests/test_1.py::test_check_warns_on_nonexistent - Failed: DID NOT...\nFAILED r2e_tests/test_1.py::test_supported_modules - AttributeError: module '...\nFAILED r2e_tests/test_1.py::test_pilinfo - AttributeError: module '_tkinter' ...\n========================= 5 failed, 5 passed in 0.19s ==========================\n",
    "old_commit_res_stderr": ""
}
Tests/test_features.py src/PIL/features.py
We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
[ISSUE]

**Title:** `features.check()` Does Not Warn on Unknown Feature Names

**Description:**
When an incorrect feature name is passed to `features.check()`, no warning is emitted. This lack of feedback can make it difficult to identify typos or unsupported features, leading to silent failures or unexpected behavior in the application.

**Example Code:**
```python
import PIL.features

# Passing a typo in the feature name
has_feature = PIL.features.check("typo")
print(has_feature)
```

**Expected Behavior:**
A warning should be displayed indicating that `"typo"` is an unknown feature. Additionally, `has_feature` should return `False` to signify that the feature is not supported.

**Actual Behavior:**
No warning is emitted when an unknown feature name is passed. While `has_feature` correctly returns `False`, the absence of a warning can obscure the fact that the feature name may be misspelled or unsupported.

[/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/features.py
import collections
import os
import sys

import PIL

from . import Image

modules = {
    "pil": "PIL._imaging",
    "tkinter": "PIL._tkinter_finder",
    "freetype2": "PIL._imagingft",
    "littlecms2": "PIL._imagingcms",
    "webp": "PIL._webp",
}


def check_module(feature):
    if not (feature in modules):
        raise ValueError("Unknown module %s" % feature)

    module = modules[feature]

    try:
        __import__(module)
        return True
    except ImportError:
        return False


def get_supported_modules():
    return [f for f in modules if check_module(f)]


codecs = {"jpg": "jpeg", "jpg_2000": "jpeg2k", "zlib": "zip", "libtiff": "libtiff"}


def check_codec(feature):
    if feature not in codecs:
        raise ValueError("Unknown codec %s" % feature)

    codec = codecs[feature]

    return codec + "_encoder" in dir(Image.core)


def get_supported_codecs():
    return [f for f in codecs if check_codec(f)]


features = {
    "webp_anim": ("PIL._webp", "HAVE_WEBPANIM"),
    "webp_mux": ("PIL._webp", "HAVE_WEBPMUX"),
    "transp_webp": ("PIL._webp", "HAVE_TRANSPARENCY"),
    "raqm": ("PIL._imagingft", "HAVE_RAQM"),
    "libjpeg_turbo": ("PIL._imaging", "HAVE_LIBJPEGTURBO"),
    "libimagequant": ("PIL._imaging", "HAVE_LIBIMAGEQUANT"),
}


def check_feature(feature):
    if feature not in features:
        raise ValueError("Unknown feature %s" % feature)

    module, flag = features[feature]

    try:
        imported_module = __import__(module, fromlist=["PIL"])
        return getattr(imported_module, flag)
    except ImportError:
        return None


def get_supported_features():
    return [f for f in features if check_feature(f)]


def check(feature):
    return (
        feature in modules
        and check_module(feature)
        or feature in codecs
        and check_codec(feature)
        or feature in features
        and check_feature(feature)
    )


def get_supported():
    ret = get_supported_modules()
    ret.extend(get_supported_features())
    ret.extend(get_supported_codecs())
    return ret


def pilinfo(out=None, supported_formats=True):
    if out is None:
        out = sys.stdout

    Image.init()

    print("-" * 68, file=out)
    print("Pillow {}".format(PIL.__version__), file=out)
    py_version = sys.version.splitlines()
    print("Python {}".format(py_version[0].strip()), file=out)
    for py_version in py_version[1:]:
        print("       {}".format(py_version.strip()), file=out)
    print("-" * 68, file=out)
    print(
        "Python modules loaded from {}".format(os.path.dirname(Image.__file__)),
        file=out,
    )
    print(
        "Binary modules loaded from {}".format(os.path.dirname(Image.core.__file__)),
        file=out,
    )
    print("-" * 68, file=out)

    for name, feature in [
        ("pil", "PIL CORE"),
        ("tkinter", "TKINTER"),
        ("freetype2", "FREETYPE2"),
        ("littlecms2", "LITTLECMS2"),
        ("webp", "WEBP"),
        ("transp_webp", "WEBP Transparency"),
        ("webp_mux", "WEBPMUX"),
        ("webp_anim", "WEBP Animation"),
        ("jpg", "JPEG"),
        ("jpg_2000", "OPENJPEG (JPEG2000)"),
        ("zlib", "ZLIB (PNG/ZIP)"),
        ("libtiff", "LIBTIFF"),
        ("raqm", "RAQM (Bidirectional Text)"),
        ("libimagequant", "LIBIMAGEQUANT (Quantization method)"),
    ]:
        if check(name):
            print("---", feature, "support ok", file=out)
        else:
            print("***", feature, "support not installed", file=out)
    print("-" * 68, file=out)

    if supported_formats:
        extensions = collections.defaultdict(list)
        for ext, i in Image.EXTENSION.items():
            extensions[i].append(ext)

        for i in sorted(Image.ID):
            line = "{}".format(i)
            if i in Image.MIME:
                line = "{} {}".format(line, Image.MIME[i])
            print(line, file=out)

            if i in extensions:
                print(
                    "Extensions: {}".format(", ".join(sorted(extensions[i]))), file=out
                )

            features = []
            if i in Image.OPEN:
                features.append("open")
            if i in Image.SAVE:
                features.append("save")
            if i in Image.SAVE_ALL:
                features.append("save_all")
            if i in Image.DECODERS:
                features.append("decode")
            if i in Image.ENCODERS:
                features.append("encode")

            print("Features: {}".format(", ".join(features)), file=out)
            print("-" * 68, file=out)

```
--- 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:** `features.check()` Does Not Warn on Unknown Feature Names

**Description:**
When an incorrect feature name is passed to `features.check()`, no warning is emitted. This lack of feedback can make it difficult to identify typos or unsupported features, leading to silent failures or unexpected behavior in the application.

**Example Code:**
```python
import PIL.features

# Passing a typo in the feature name
has_feature = PIL.features.check("typo")
print(has_feature)
```

**Expected Behavior:**
A warning should be displayed indicating that `"typo"` is an unknown feature. Additionally, `has_feature` should return `False` to signify that the feature is not supported.

**Actual Behavior:**
No warning is emitted when an unknown feature name is passed. While `has_feature` correctly returns `False`, the absence of a warning can obscure the fact that the feature name may be misspelled or unsupported.

[/ISSUE]
{
    "test_webp_transparency": "PASSED",
    "test_webp_mux": "PASSED",
    "test_webp_anim": "PASSED",
    "test_check_warns_on_nonexistent": "PASSED",
    "test_unsupported_codec": "PASSED",
    "test_unsupported_module": "PASSED",
    "test_check": "FAILED",
    "test_check_modules": "FAILED",
    "test_supported_modules": "FAILED",
    "test_pilinfo": "FAILED"
}
diff --git a/src/PIL/features.py b/src/PIL/features.py
index 5822febab..0a1d5d611 100644
--- a/src/PIL/features.py
+++ b/src/PIL/features.py
@@ -1,6 +1,7 @@
 import collections
 import os
 import sys
+import warnings
 
 import PIL
 
@@ -76,14 +77,14 @@ def get_supported_features():
 
 
 def check(feature):
-    return (
-        feature in modules
-        and check_module(feature)
-        or feature in codecs
-        and check_codec(feature)
-        or feature in features
-        and check_feature(feature)
-    )
+    if feature in modules:
+        return check_module(feature)
+    if feature in codecs:
+        return check_codec(feature)
+    if feature in features:
+        return check_feature(feature)
+    warnings.warn("Unknown feature '%s'." % feature, stacklevel=2)
+    return False
 
 
 def get_supported():
 

{"src/PIL/features.py": "import collections\nimport os\nimport sys\n\nimport PIL\n\nfrom . import Image\n\nmodules = {\n    \"pil\": \"PIL._imaging\",\n    \"tkinter\": \"PIL._tkinter_finder\",\n    \"freetype2\": \"PIL._imagingft\",\n    \"littlecms2\": \"PIL._imagingcms\",\n    \"webp\": \"PIL._webp\",\n}\n\n\ndef check_module(feature):\n    if not (feature in modules):\n        raise ValueError(\"Unknown module %s\" % feature)\n\n    module = modules[feature]\n\n    try:\n        __import__(module)\n        return True\n    except ImportError:\n        return False\n\n\ndef get_supported_modules():\n    return [f for f in modules if check_module(f)]\n\n\ncodecs = {\"jpg\": \"jpeg\", \"jpg_2000\": \"jpeg2k\", \"zlib\": \"zip\", \"libtiff\": \"libtiff\"}\n\n\ndef check_codec(feature):\n    if feature not in codecs:\n        raise ValueError(\"Unknown codec %s\" % feature)\n\n    codec = codecs[feature]\n\n    return codec + \"_encoder\" in dir(Image.core)\n\n\ndef get_supported_codecs():\n    return [f for f in codecs if check_codec(f)]\n\n\nfeatures = {\n    \"webp_anim\": (\"PIL._webp\", \"HAVE_WEBPANIM\"),\n    \"webp_mux\": (\"PIL._webp\", \"HAVE_WEBPMUX\"),\n    \"transp_webp\": (\"PIL._webp\", \"HAVE_TRANSPARENCY\"),\n    \"raqm\": (\"PIL._imagingft\", \"HAVE_RAQM\"),\n    \"libjpeg_turbo\": (\"PIL._imaging\", \"HAVE_LIBJPEGTURBO\"),\n    \"libimagequant\": (\"PIL._imaging\", \"HAVE_LIBIMAGEQUANT\"),\n}\n\n\ndef check_feature(feature):\n    if feature not in features:\n        raise ValueError(\"Unknown feature %s\" % feature)\n\n    module, flag = features[feature]\n\n    try:\n        imported_module = __import__(module, fromlist=[\"PIL\"])\n        return getattr(imported_module, flag)\n    except ImportError:\n        return None\n\n\ndef get_supported_features():\n    return [f for f in features if check_feature(f)]\n\n\ndef check(feature):\n    return (\n        feature in modules\n        and check_module(feature)\n        or feature in codecs\n        and check_codec(feature)\n        or feature in features\n        and check_feature(feature)\n    )\n\n\ndef get_supported():\n    ret = get_supported_modules()\n    ret.extend(get_supported_features())\n    ret.extend(get_supported_codecs())\n    return ret\n\n\ndef pilinfo(out=None, supported_formats=True):\n    if out is None:\n        out = sys.stdout\n\n    Image.init()\n\n    print(\"-\" * 68, file=out)\n    print(\"Pillow {}\".format(PIL.__version__), file=out)\n    py_version = sys.version.splitlines()\n    print(\"Python {}\".format(py_version[0].strip()), file=out)\n    for py_version in py_version[1:]:\n        print(\"       {}\".format(py_version.strip()), file=out)\n    print(\"-\" * 68, file=out)\n    print(\n        \"Python modules loaded from {}\".format(os.path.dirname(Image.__file__)),\n        file=out,\n    )\n    print(\n        \"Binary modules loaded from {}\".format(os.path.dirname(Image.core.__file__)),\n        file=out,\n    )\n    print(\"-\" * 68, file=out)\n\n    for name, feature in [\n        (\"pil\", \"PIL CORE\"),\n        (\"tkinter\", \"TKINTER\"),\n        (\"freetype2\", \"FREETYPE2\"),\n        (\"littlecms2\", \"LITTLECMS2\"),\n        (\"webp\", \"WEBP\"),\n        (\"transp_webp\", \"WEBP Transparency\"),\n        (\"webp_mux\", \"WEBPMUX\"),\n        (\"webp_anim\", \"WEBP Animation\"),\n        (\"jpg\", \"JPEG\"),\n        (\"jpg_2000\", \"OPENJPEG (JPEG2000)\"),\n        (\"zlib\", \"ZLIB (PNG/ZIP)\"),\n        (\"libtiff\", \"LIBTIFF\"),\n        (\"raqm\", \"RAQM (Bidirectional Text)\"),\n        (\"libimagequant\", \"LIBIMAGEQUANT (Quantization method)\"),\n    ]:\n        if check(name):\n            print(\"---\", feature, \"support ok\", file=out)\n        else:\n            print(\"***\", feature, \"support not installed\", file=out)\n    print(\"-\" * 68, file=out)\n\n    if supported_formats:\n        extensions = collections.defaultdict(list)\n        for ext, i in Image.EXTENSION.items():\n            extensions[i].append(ext)\n\n        for i in sorted(Image.ID):\n            line = \"{}\".format(i)\n            if i in Image.MIME:\n                line = \"{} {}\".format(line, Image.MIME[i])\n            print(line, file=out)\n\n            if i in extensions:\n                print(\n                    \"Extensions: {}\".format(\", \".join(sorted(extensions[i]))), file=out\n                )\n\n            features = []\n            if i in Image.OPEN:\n                features.append(\"open\")\n            if i in Image.SAVE:\n                features.append(\"save\")\n            if i in Image.SAVE_ALL:\n                features.append(\"save_all\")\n            if i in Image.DECODERS:\n                features.append(\"decode\")\n            if i in Image.ENCODERS:\n                features.append(\"encode\")\n\n            print(\"Features: {}\".format(\", \".join(features)), file=out)\n            print(\"-\" * 68, file=out)\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:** `features.check()` Does Not Warn on Unknown Feature Names

**Description:**
When an incorrect feature name is passed to `features.check()`, no warning is emitted. This lack of feedback can make it difficult to identify typos or unsupported features, leading to silent failures or unexpected behavior in the application.

**Example Code:**
```python
import PIL.features

# Passing a typo in the feature name
has_feature = PIL.features.check("typo")
print(has_feature)
```

**Expected Behavior:**
A warning should be displayed indicating that `"typo"` is an unknown feature. Additionally, `has_feature` should return `False` to signify that the feature is not supported.

**Actual Behavior:**
No warning is emitted when an unknown feature name is passed. While `has_feature` correctly returns `False`, the absence of a warning can obscure the fact that the feature name may be misspelled or unsupported.

[/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/features.py
import collections
import os
import sys

import PIL

from . import Image

modules = {
    "pil": "PIL._imaging",
    "tkinter": "PIL._tkinter_finder",
    "freetype2": "PIL._imagingft",
    "littlecms2": "PIL._imagingcms",
    "webp": "PIL._webp",
}


def check_module(feature):
    if not (feature in modules):
        raise ValueError("Unknown module %s" % feature)

    module = modules[feature]

    try:
        __import__(module)
        return True
    except ImportError:
        return False


def get_supported_modules():
    return [f for f in modules if check_module(f)]


codecs = {"jpg": "jpeg", "jpg_2000": "jpeg2k", "zlib": "zip", "libtiff": "libtiff"}


def check_codec(feature):
    if feature not in codecs:
        raise ValueError("Unknown codec %s" % feature)

    codec = codecs[feature]

    return codec + "_encoder" in dir(Image.core)


def get_supported_codecs():
    return [f for f in codecs if check_codec(f)]


features = {
    "webp_anim": ("PIL._webp", "HAVE_WEBPANIM"),
    "webp_mux": ("PIL._webp", "HAVE_WEBPMUX"),
    "transp_webp": ("PIL._webp", "HAVE_TRANSPARENCY"),
    "raqm": ("PIL._imagingft", "HAVE_RAQM"),
    "libjpeg_turbo": ("PIL._imaging", "HAVE_LIBJPEGTURBO"),
    "libimagequant": ("PIL._imaging", "HAVE_LIBIMAGEQUANT"),
}


def check_feature(feature):
    if feature not in features:
        raise ValueError("Unknown feature %s" % feature)

    module, flag = features[feature]

    try:
        imported_module = __import__(module, fromlist=["PIL"])
        return getattr(imported_module, flag)
    except ImportError:
        return None


def get_supported_features():
    return [f for f in features if check_feature(f)]


def check(feature):
    return (
        feature in modules
        and check_module(feature)
        or feature in codecs
        and check_codec(feature)
        or feature in features
        and check_feature(feature)
    )


def get_supported():
    ret = get_supported_modules()
    ret.extend(get_supported_features())
    ret.extend(get_supported_codecs())
    return ret


def pilinfo(out=None, supported_formats=True):
    if out is None:
        out = sys.stdout

    Image.init()

    print("-" * 68, file=out)
    print("Pillow {}".format(PIL.__version__), file=out)
    py_version = sys.version.splitlines()
    print("Python {}".format(py_version[0].strip()), file=out)
    for py_version in py_version[1:]:
        print("       {}".format(py_version.strip()), file=out)
    print("-" * 68, file=out)
    print(
        "Python modules loaded from {}".format(os.path.dirname(Image.__file__)),
        file=out,
    )
    print(
        "Binary modules loaded from {}".format(os.path.dirname(Image.core.__file__)),
        file=out,
    )
    print("-" * 68, file=out)

    for name, feature in [
        ("pil", "PIL CORE"),
        ("tkinter", "TKINTER"),
        ("freetype2", "FREETYPE2"),
        ("littlecms2", "LITTLECMS2"),
        ("webp", "WEBP"),
        ("transp_webp", "WEBP Transparency"),
        ("webp_mux", "WEBPMUX"),
        ("webp_anim", "WEBP Animation"),
        ("jpg", "JPEG"),
        ("jpg_2000", "OPENJPEG (JPEG2000)"),
        ("zlib", "ZLIB (PNG/ZIP)"),
        ("libtiff", "LIBTIFF"),
        ("raqm", "RAQM (Bidirectional Text)"),
        ("libimagequant", "LIBIMAGEQUANT (Quantization method)"),
    ]:
        if check(name):
            print("---", feature, "support ok", file=out)
        else:
            print("***", feature, "support not installed", file=out)
    print("-" * 68, file=out)

    if supported_formats:
        extensions = collections.defaultdict(list)
        for ext, i in Image.EXTENSION.items():
            extensions[i].append(ext)

        for i in sorted(Image.ID):
            line = "{}".format(i)
            if i in Image.MIME:
                line = "{} {}".format(line, Image.MIME[i])
            print(line, file=out)

            if i in extensions:
                print(
                    "Extensions: {}".format(", ".join(sorted(extensions[i]))), file=out
                )

            features = []
            if i in Image.OPEN:
                features.append("open")
            if i in Image.SAVE:
                features.append("save")
            if i in Image.SAVE_ALL:
                features.append("save_all")
            if i in Image.DECODERS:
                features.append("decode")
            if i in Image.ENCODERS:
                features.append("encode")

            print("Features: {}".format(", ".join(features)), file=out)
            print("-" * 68, file=out)

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