diff --git a/Lib/mimetypes.py b/Lib/mimetypes.py index a834826114614d..cf54984f9bbf68 100644 --- a/Lib/mimetypes.py +++ b/Lib/mimetypes.py @@ -187,15 +187,19 @@ def _guess_file_type(self, path, strict, splitext): base, ext = splitext(base) else: encoding = None - ext = ext.lower() + ext_lower = ext.lower() types_map = self.types_map[True] if ext in types_map: return types_map[ext], encoding + if ext_lower in types_map: + return types_map[ext_lower], encoding elif strict: return None, encoding types_map = self.types_map[False] if ext in types_map: return types_map[ext], encoding + if ext_lower in types_map: + return types_map[ext_lower], encoding else: return None, encoding diff --git a/Lib/test/test_mimetypes.py b/Lib/test/test_mimetypes.py index 2d618081521e10..7296f9ba0e1959 100644 --- a/Lib/test/test_mimetypes.py +++ b/Lib/test/test_mimetypes.py @@ -49,6 +49,18 @@ def test_case_sensitivity(self): eq(self.db.guess_file_type("foobar.tar.z"), (None, None)) eq(self.db.guess_type("scheme:foobar.tar.z"), (None, None)) + def test_added_types_case_sensitive_preferred(self): + self.db.add_type("text/x-r-script", ".R") + self.db.add_type("text/x-test-lowercase-r", ".r") + self.assertEqual( + self.db.guess_file_type("example.R"), + ("text/x-r-script", None), + ) + self.assertEqual( + self.db.guess_file_type("example.r"), + ("text/x-test-lowercase-r", None), + ) + def test_default_data(self): eq = self.assertEqual eq(self.db.guess_file_type("foo.html"), ("text/html", None)) diff --git a/Misc/NEWS.d/next/Library/2026-04-20-01-24-22.gh-issue-92455.vXhmad.rst b/Misc/NEWS.d/next/Library/2026-04-20-01-24-22.gh-issue-92455.vXhmad.rst new file mode 100644 index 00000000000000..7d251cae688ae8 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-04-20-01-24-22.gh-issue-92455.vXhmad.rst @@ -0,0 +1,3 @@ +Fix :mod:`mimetypes` to prefer case-sensitive matches for MIME type suffixes +registered with :func:`mimetypes.add_type` before falling back to +case-insensitive matches. Contributed by Xiao Yuan.