(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
is already known the extension will be added to the list of known extensions.
Valid extensions are empty or start with a ``'.'``.
+ Registered lower-case extensions are matched case-insensitively.
+
When *strict* is ``True`` (the default), the mapping will be added to the
official MIME types, otherwise to the non-standard ones.
extension is already known, the new type will replace the old one. When the type
is already known the extension will be added to the list of known extensions.
+ Registered lower-case extensions are matched case-insensitively.
+
When *strict* is ``True`` (the default), the mapping will be added to the
official MIME types, otherwise to the non-standard ones.
is already known the extension will be added
to the list of known extensions.
+ Registered lower-case extensions are matched
+ case-insensitively.
+
If strict is true, information will be added to
list of standard types, else to the list of non-standard
types.
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
is already known the extension will be added
to the list of known extensions.
+ Registered lower-case extensions are matched
+ case-insensitively.
+
If strict is true, information will be added to
list of standard types, else to the list of non-standard
types.
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))
--- /dev/null
+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.