Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
24 changes: 23 additions & 1 deletion Lib/mimetypes.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
suffix_map -- dictionary mapping suffixes to suffixes
encodings_map -- dictionary mapping suffixes to encodings
types_map -- dictionary mapping suffixes to types
duplicate_types_map -- dictionary mapping suffixes to types for suffixes that map to multiple types

Functions:

Expand Down Expand Up @@ -42,7 +43,8 @@
"knownfiles", "inited", "MimeTypes",
"guess_type", "guess_file_type", "guess_all_extensions", "guess_extension",
"add_type", "init", "read_mime_types",
"suffix_map", "encodings_map", "types_map", "common_types"
"suffix_map", "encodings_map", "types_map", "common_types",
"duplicate_ext_types",
]

knownfiles = [
Expand Down Expand Up @@ -80,6 +82,11 @@ def __init__(self, filenames=(), strict=True):
self.add_type(type, ext, True)
for (ext, type) in _common_types_default.items():
self.add_type(type, ext, False)
for (ext, type) in _duplicate_ext_types_default.items():
exts = self.types_map_inv[strict].setdefault(type, [])
if ext not in exts:
exts.append(ext)

for name in filenames:
self.read(name, strict)

Expand Down Expand Up @@ -425,6 +432,7 @@ def _default_mime_types():
global suffix_map, _suffix_map_default
global encodings_map, _encodings_map_default
global types_map, _types_map_default
global duplicate_ext_types, _duplicate_ext_types_default
global common_types, _common_types_default

suffix_map = _suffix_map_default = {
Expand Down Expand Up @@ -608,6 +616,20 @@ def _default_mime_types():
'.movie' : 'video/x-sgi-movie',
}

# Some extensions in the default list are linked to multiple mimetypes.
# If you need to add a type that duplicates an extension in the default
# map, add it here.

# Please sort these too.
# Make sure the entry with the preferred file extension for a particular mime type
# appears before any others of the same mimetype.
duplicate_ext_types = _duplicate_ext_types_default = {
'.3gp' : 'video/3gpp',
'.3gpp' : 'video/3gpp',
'.3g2' : 'video/3gpp2',
'.3gpp2' : 'video/3gpp2',
}

# These are non-standard types, commonly found in the wild. They will
# only match if strict=0 flag is given to the API methods.

Expand Down
13 changes: 13 additions & 0 deletions Lib/test/test_mimetypes.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,13 @@ def test_read_mime_types(self):
mock_open.assert_called_with(filename, encoding='utf-8')
eq(mime_dict[".Français"], "application/no-mans-land")

def test_duplicate_ext_types(self):
# assert that each extension in the duplicate map is also in the default map
# for a different type
for ext, type in mimetypes.duplicate_ext_types.items():
self.assertIn(ext, mimetypes._types_map_default)
self.assertNotEqual(type, mimetypes._types_map_default[ext])

def test_non_standard_types(self):
eq = self.assertEqual
# First try strict
Expand Down Expand Up @@ -231,6 +238,8 @@ def check_extensions():
self.assertEqual(mimetypes.guess_extension('application/x-texinfo'), '.texi')
self.assertEqual(mimetypes.guess_extension('application/x-troff'), '.roff')
self.assertEqual(mimetypes.guess_extension('application/xml'), '.xsl')
self.assertEqual(mimetypes.guess_extension('audio/3gpp'), '.3gp')
self.assertEqual(mimetypes.guess_extension('audio/3gpp2'), '.3g2')
self.assertEqual(mimetypes.guess_extension('audio/mpeg'), '.mp3')
self.assertEqual(mimetypes.guess_extension('image/avif'), '.avif')
self.assertEqual(mimetypes.guess_extension('image/webp'), '.webp')
Expand All @@ -241,6 +250,8 @@ def check_extensions():
self.assertEqual(mimetypes.guess_extension('text/plain'), '.txt')
self.assertEqual(mimetypes.guess_extension('text/rtf'), '.rtf')
self.assertEqual(mimetypes.guess_extension('text/x-rst'), '.rst')
self.assertEqual(mimetypes.guess_extension('video/3gpp'), '.3gp')
self.assertEqual(mimetypes.guess_extension('video/3gpp2'), '.3g2')
self.assertEqual(mimetypes.guess_extension('video/mpeg'), '.mpeg')
self.assertEqual(mimetypes.guess_extension('video/quicktime'), '.mov')

Expand All @@ -255,6 +266,7 @@ def test_init_stability(self):
encodings_map = mimetypes.encodings_map
types_map = mimetypes.types_map
common_types = mimetypes.common_types
duplicate_ext_types = mimetypes.duplicate_ext_types

mimetypes.init()
self.assertIsNot(suffix_map, mimetypes.suffix_map)
Expand All @@ -265,6 +277,7 @@ def test_init_stability(self):
self.assertEqual(encodings_map, mimetypes.encodings_map)
self.assertEqual(types_map, mimetypes.types_map)
self.assertEqual(common_types, mimetypes.common_types)
self.assertEqual(duplicate_ext_types, mimetypes.duplicate_ext_types)

def test_path_like_ob(self):
filename = "LICENSE.txt"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Add :mod:`mimetypes` support for `video/3gpp`_ and `video/3gpp2`_.

.. _video/3gpp: https://www.iana.org/assignments/media-types/video/3gpp
.. _video/3gpp2: https://www.iana.org/assignments/media-types/video/3gpp2