Skip to content

Commit d5b34d4

Browse files
committed
Issue #4969: The mimetypes module now reads the MIME database from
the registry under Windows. Patch by Gabriel Genellina.
1 parent a548dee commit d5b34d4

File tree

4 files changed

+102
-5
lines changed

4 files changed

+102
-5
lines changed

Doc/library/mimetypes.rst

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -77,9 +77,13 @@ behavior of the module.
7777

7878
Initialize the internal data structures. If given, *files* must be a sequence
7979
of file names which should be used to augment the default type map. If omitted,
80-
the file names to use are taken from :const:`knownfiles`. Each file named in
81-
*files* or :const:`knownfiles` takes precedence over those named before it.
82-
Calling :func:`init` repeatedly is allowed.
80+
the file names to use are taken from :const:`knownfiles`; on Windows, the
81+
current registry settings are loaded. Each file named in *files* or
82+
:const:`knownfiles` takes precedence over those named before it. Calling
83+
:func:`init` repeatedly is allowed.
84+
85+
.. versionchanged:: 2.7
86+
Previously, Windows registry settings were ignored.
8387

8488

8589
.. function:: read_mime_types(filename)
@@ -213,6 +217,12 @@ MimeTypes Objects
213217
of the object.
214218

215219

220+
.. method:: MimeTypes.guess_all_extensions(type[, strict])
221+
222+
Similar to the :func:`guess_all_extensions` function, using the tables stored as part
223+
of the object.
224+
225+
216226
.. method:: MimeTypes.guess_type(url[, strict])
217227

218228
Similar to the :func:`guess_type` function, using the tables stored as part of
@@ -230,3 +240,9 @@ MimeTypes Objects
230240
Load MIME type information from an open file. The file must have the format of
231241
the standard :file:`mime.types` files.
232242

243+
244+
.. method:: MimeTypes.read_windows_registry()
245+
246+
Load MIME type information from the Windows registry. Availability: Windows.
247+
248+
.. versionadded:: 2.7

Lib/mimetypes.py

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,19 @@
1818
1919
Functions:
2020
21-
init([files]) -- parse a list of files, default knownfiles
21+
init([files]) -- parse a list of files, default knownfiles (on Windows, the
22+
default values are taken from the registry)
2223
read_mime_types(file) -- parse one file, return a dictionary or None
2324
"""
2425

2526
import os
27+
import sys
2628
import posixpath
2729
import urllib
30+
try:
31+
import _winreg
32+
except ImportError:
33+
_winreg = None
2834

2935
__all__ = [
3036
"guess_type","guess_extension","guess_all_extensions",
@@ -220,6 +226,52 @@ def readfp(self, fp, strict=True):
220226
for suff in suffixes:
221227
self.add_type(type, '.' + suff, strict)
222228

229+
def read_windows_registry(self, strict=True):
230+
"""
231+
Load the MIME types database from Windows registry.
232+
233+
If strict is true, information will be added to
234+
list of standard types, else to the list of non-standard
235+
types.
236+
"""
237+
238+
# Windows only
239+
if not _winreg:
240+
return
241+
242+
def enum_types(mimedb):
243+
i = 0
244+
while True:
245+
try:
246+
ctype = _winreg.EnumKey(mimedb, i)
247+
except EnvironmentError:
248+
break
249+
try:
250+
ctype = ctype.encode(default_encoding) # omit in 3.x!
251+
except UnicodeEncodeError:
252+
pass
253+
else:
254+
yield ctype
255+
i += 1
256+
257+
default_encoding = sys.getdefaultencoding()
258+
with _winreg.OpenKey(_winreg.HKEY_CLASSES_ROOT,
259+
r'MIME\Database\Content Type') as mimedb:
260+
for ctype in enum_types(mimedb):
261+
with _winreg.OpenKey(mimedb, ctype) as key:
262+
try:
263+
suffix, datatype = _winreg.QueryValueEx(key, 'Extension')
264+
except EnvironmentError:
265+
continue
266+
if datatype != _winreg.REG_SZ:
267+
continue
268+
try:
269+
suffix = suffix.encode(default_encoding) # omit in 3.x!
270+
except UnicodeEncodeError:
271+
continue
272+
self.add_type(ctype, suffix, strict)
273+
274+
223275
def guess_type(url, strict=True):
224276
"""Guess the type of a file based on its URL.
225277
@@ -299,6 +351,8 @@ def init(files=None):
299351
inited = True # so that MimeTypes.__init__() doesn't call us again
300352
db = MimeTypes()
301353
if files is None:
354+
if _winreg:
355+
db.read_windows_registry()
302356
files = knownfiles
303357
for file in files:
304358
if os.path.isfile(file):

Lib/test/test_mimetypes.py

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import mimetypes
22
import StringIO
33
import unittest
4+
import sys
45

56
from test import test_support
67

@@ -62,8 +63,31 @@ def test_guess_all_types(self):
6263
eq(all, [])
6364

6465

66+
@unittest.skipUnless(sys.platform.startswith("win"), "Windows only")
67+
class Win32MimeTypesTestCase(unittest.TestCase):
68+
def setUp(self):
69+
# ensure all entries actually come from the Windows registry
70+
self.original_types_map = mimetypes.types_map.copy()
71+
mimetypes.types_map.clear()
72+
mimetypes.init()
73+
self.db = mimetypes.MimeTypes()
74+
75+
def tearDown(self):
76+
# restore default settings
77+
mimetypes.types_map.clear()
78+
mimetypes.types_map.update(self.original_types_map)
79+
80+
def test_registry_parsing(self):
81+
# the original, minimum contents of the MIME database in the
82+
# Windows registry is undocumented AFAIK.
83+
# Use file types that should *always* exist:
84+
eq = self.assertEqual
85+
eq(self.db.guess_type("foo.txt"), ("text/plain", None))
86+
6587
def test_main():
66-
test_support.run_unittest(MimeTypesTestCase)
88+
test_support.run_unittest(MimeTypesTestCase,
89+
Win32MimeTypesTestCase
90+
)
6791

6892

6993
if __name__ == "__main__":

Misc/NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -429,6 +429,9 @@ Core and Builtins
429429
Library
430430
-------
431431

432+
- Issue #4969: The mimetypes module now reads the MIME database from
433+
the registry under Windows. Patch by Gabriel Genellina.
434+
432435
- Issue #6816: runpy now provides a run_path function that allows Python code
433436
to execute file paths that refer to source or compiled Python files as well
434437
as zipfiles, directories and other valid sys.path entries that contain a

0 commit comments

Comments
 (0)