Index: Lib/mimetypes.py =================================================================== --- Lib/mimetypes.py (revision 76273) +++ Lib/mimetypes.py (working copy) @@ -18,13 +18,19 @@ Functions: -init([files]) -- parse a list of files, default knownfiles +init([files]) -- parse a list of files, default knownfiles (on Windows, the + default values are taken from the registry) read_mime_types(file) -- parse one file, return a dictionary or None """ import os +import sys import posixpath import urllib +try: + import _winreg +except ImportError: + _winreg = None __all__ = [ "guess_type","guess_extension","guess_all_extensions", @@ -220,6 +226,52 @@ for suff in suffixes: self.add_type(type, '.' + suff, strict) + def read_windows_registry(self, strict=True): + """ + Load the MIME types database from Windows registry. + + If strict is true, information will be added to + list of standard types, else to the list of non-standard + types. + """ + + # Windows only + if not _winreg: + return + + def enum_types(mimedb): + i = 0 + while True: + try: + ctype = _winreg.EnumKey(mimedb, i) + except EnvironmentError: + break + try: + ctype = ctype.encode(default_encoding) # omit in 3.x! + except UnicodeEncodeError: + pass + else: + yield ctype + i += 1 + + default_encoding = sys.getdefaultencoding() + with _winreg.OpenKey(_winreg.HKEY_CLASSES_ROOT, + r'MIME\Database\Content Type') as mimedb: + for ctype in enum_types(mimedb): + with _winreg.OpenKey(mimedb, ctype) as key: + try: + suffix, datatype = _winreg.QueryValueEx(key, 'Extension') + except EnvironmentError: + continue + if datatype != _winreg.REG_SZ: + continue + try: + suffix = suffix.encode(default_encoding) # omit in 3.x! + except UnicodeEncodeError: + continue + self.add_type(ctype, suffix, strict) + + def guess_type(url, strict=True): """Guess the type of a file based on its URL. @@ -299,6 +351,8 @@ inited = True # so that MimeTypes.__init__() doesn't call us again db = MimeTypes() if files is None: + if _winreg: + db.read_windows_registry() files = knownfiles for file in files: if os.path.isfile(file): Index: Lib/test/test_mimetypes.py =================================================================== --- Lib/test/test_mimetypes.py (revision 76258) +++ Lib/test/test_mimetypes.py (working copy) @@ -1,6 +1,7 @@ import mimetypes import StringIO import unittest +import sys from test import test_support @@ -62,8 +63,31 @@ eq(all, []) +@unittest.skipUnless(sys.platform.startswith("win"), "Windows only") +class Win32MimeTypesTestCase(unittest.TestCase): + def setUp(self): + # ensure all entries actually come from the Windows registry + self.original_types_map = mimetypes.types_map.copy() + mimetypes.types_map.clear() + mimetypes.init() + self.db = mimetypes.MimeTypes() + + def tearDown(self): + # restore default settings + mimetypes.types_map.clear() + mimetypes.types_map.update(self.original_types_map) + + def test_registry_parsing(self): + # the original, minimum contents of the MIME database in the + # Windows registry is undocumented AFAIK. + # Use file types that should *always* exist: + eq = self.assertEqual + eq(self.db.guess_type("foo.txt"), ("text/plain", None)) + def test_main(): - test_support.run_unittest(MimeTypesTestCase) + test_support.run_unittest(MimeTypesTestCase, + Win32MimeTypesTestCase + ) if __name__ == "__main__": Index: doc/library/mimetypes.rst =================================================================== --- doc/library/mimetypes.rst (revision 76258) +++ doc/library/mimetypes.rst (working copy) @@ -77,11 +77,15 @@ Initialize the internal data structures. If given, *files* must be a sequence of file names which should be used to augment the default type map. If omitted, - the file names to use are taken from :const:`knownfiles`. Each file named in - *files* or :const:`knownfiles` takes precedence over those named before it. - Calling :func:`init` repeatedly is allowed. + the file names to use are taken from :const:`knownfiles`; on Windows, the + current registry settings are loaded. Each file named in *files* or + :const:`knownfiles` takes precedence over those named before it. Calling + :func:`init` repeatedly is allowed. + .. versionchanged:: 2.7 + Previously, Windows registry settings were ignored. + .. function:: read_mime_types(filename) Load the type map given in the file *filename*, if it exists. The type map is @@ -213,6 +217,12 @@ of the object. +.. method:: MimeTypes.guess_all_extensions(type[, strict]) + + Similar to the :func:`guess_all_extensions` function, using the tables stored as part + of the object. + + .. method:: MimeTypes.guess_type(url[, strict]) Similar to the :func:`guess_type` function, using the tables stored as part of @@ -230,3 +240,9 @@ Load MIME type information from an open file. The file must have the format of the standard :file:`mime.types` files. + +.. method:: MimeTypes.read_windows_registry() + + Load MIME type information from the Windows registry. Availability: Windows. + + .. versionadded:: 2.7