Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Doc/library/mimetypes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@ the information :func:`init` sets up.
(e.g. :program:`compress` or :program:`gzip`). The encoding is suitable for use
as a :mailheader:`Content-Encoding` header, **not** as a
:mailheader:`Content-Transfer-Encoding` header. The mappings are table driven.
Encoding suffixes are case sensitive; type suffixes are first tried case
sensitively, then case insensitively.
Encoding suffixes are case sensitive. Suffix mappings and type suffixes are
first tried case sensitively, then case insensitively.

The optional *strict* argument is a flag specifying whether the list of known MIME types
is limited to only the official types `registered with IANA
Expand Down
16 changes: 13 additions & 3 deletions Lib/mimetypes.py
Original file line number Diff line number Diff line change
Expand Up @@ -172,23 +172,33 @@ def guess_file_type(self, path, *, strict=True):

def _guess_file_type(self, path, strict, splitext):
base, ext = splitext(path)
while (ext_lower := ext.lower()) in self.suffix_map:
base, ext = splitext(base + self.suffix_map[ext_lower])
while True:
if ext in self.suffix_map:
suffix = self.suffix_map[ext]
elif (ext_lower := ext.lower()) in self.suffix_map:
suffix = self.suffix_map[ext_lower]
else:
break
base, ext = splitext(base + suffix)
# encodings_map is case sensitive
if ext in self.encodings_map:
encoding = self.encodings_map[ext]
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

Expand Down
44 changes: 44 additions & 0 deletions Lib/test/test_mimetypes.py
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,50 @@ 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_suffix_map_case_sensitive_preferred(self):
self.db.suffix_map[".TEST-SUFFIX"] = ".tar.gz"
self.db.suffix_map[".test-suffix"] = ".tar.xz"
self.assertEqual(
self.db.guess_file_type("example.TEST-SUFFIX"),
("application/x-tar", "gzip"),
)
self.assertEqual(
self.db.guess_file_type("example.test-suffix"),
("application/x-tar", "xz"),
)

def test_added_types_case_sensitive_preferred(self):
self.db.add_type("text/x-test-uppercase-r", ".R")
self.db.add_type("text/x-test-lowercase-r", ".r")
self.assertEqual(
self.db.guess_file_type("example.R"),
("text/x-test-uppercase-r", None),
)
self.assertEqual(
self.db.guess_file_type("example.r"),
("text/x-test-lowercase-r", None),
)
self.db.add_type("text/x-test-uppercase-non-strict",
".NON-STRICT-EXT", strict=False)
self.db.add_type("text/x-test-lowercase-non-strict",
".non-strict-ext", strict=False)
self.assertEqual(
self.db.guess_file_type("example.NON-STRICT-EXT"),
(None, None),
)
self.assertEqual(
self.db.guess_file_type("example.non-strict-ext"),
(None, None),
)
self.assertEqual(
self.db.guess_file_type("example.NON-STRICT-EXT", strict=False),
("text/x-test-uppercase-non-strict", None),
)
self.assertEqual(
self.db.guess_file_type("example.non-strict-ext", strict=False),
("text/x-test-lowercase-non-strict", None),
)

def test_default_data(self):
eq = self.assertEqual
eq(self.db.guess_file_type("foo.html"), ("text/html", None))
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Fix :mod:`mimetypes` to prefer case-sensitive matches for suffix mappings and
MIME type suffixes before falling back to case-insensitive matches.
Contributed by Xiao Yuan.
Loading