From b8108e2425546635176495dec0d70d3c87a1f309 Mon Sep 17 00:00:00 2001 From: Antoine Pitrou Date: Sun, 15 Nov 2009 14:25:16 +0000 Subject: [PATCH] Merged revisions 76306 via svnmerge from svn+ssh://pythondev@svn.python.org/python/trunk ........ r76306 | antoine.pitrou | 2009-11-15 15:10:48 +0100 (dim., 15 nov. 2009) | 4 lines Issue #4969: The mimetypes module now reads the MIME database from the registry under Windows. Patch by Gabriel Genellina. ........ --- Doc/library/mimetypes.rst | 16 ++++++++++--- Lib/mimetypes.py | 48 +++++++++++++++++++++++++++++++++++++- Lib/test/test_mimetypes.py | 27 ++++++++++++++++++++- Misc/NEWS | 3 +++ 4 files changed, 89 insertions(+), 5 deletions(-) diff --git a/Doc/library/mimetypes.rst b/Doc/library/mimetypes.rst index fe1437a85b9..d2d20d2ec31 100644 --- a/Doc/library/mimetypes.rst +++ b/Doc/library/mimetypes.rst @@ -76,9 +76,13 @@ behavior of the module. 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:: 3.2 + Previously, Windows registry settings were ignored. .. function:: read_mime_types(filename) @@ -228,3 +232,9 @@ MimeTypes Objects 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:: 3.2 diff --git a/Lib/mimetypes.py b/Lib/mimetypes.py index f0da453da05..f63a733e879 100644 --- a/Lib/mimetypes.py +++ b/Lib/mimetypes.py @@ -18,13 +18,19 @@ types_map -- dictionary mapping suffixes to types 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.parse +try: + import winreg as _winreg +except ImportError: + _winreg = None __all__ = [ "guess_type","guess_extension","guess_all_extensions", @@ -220,6 +226,44 @@ class MimeTypes: 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 + 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 + self.add_type(ctype, suffix, strict) + + def guess_type(url, strict=True): """Guess the type of a file based on its URL. @@ -299,6 +343,8 @@ def init(files=None): 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): diff --git a/Lib/test/test_mimetypes.py b/Lib/test/test_mimetypes.py index 7918de6a57f..2caa7aa21d6 100644 --- a/Lib/test/test_mimetypes.py +++ b/Lib/test/test_mimetypes.py @@ -1,6 +1,7 @@ import mimetypes import io import unittest +import sys from test import support @@ -62,8 +63,32 @@ class MimeTypesTestCase(unittest.TestCase): 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(): - support.run_unittest(MimeTypesTestCase) + support.run_unittest(MimeTypesTestCase, + Win32MimeTypesTestCase + ) if __name__ == "__main__": diff --git a/Misc/NEWS b/Misc/NEWS index 9480d9f61e6..438352ee511 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -132,6 +132,9 @@ C-API Library ------- +- Issue #4969: The mimetypes module now reads the MIME database from + the registry under Windows. Patch by Gabriel Genellina. + - Issue #7318: multiprocessing now uses a timeout when it fails to establish a connection with another process, rather than looping endlessly. The default timeout is 20 seconds, which should be amply sufficient for