]> granicus.if.org Git - python/commitdiff
Issue #4969: The mimetypes module now reads the MIME database from
authorAntoine Pitrou <solipsis@pitrou.net>
Sun, 15 Nov 2009 14:10:48 +0000 (14:10 +0000)
committerAntoine Pitrou <solipsis@pitrou.net>
Sun, 15 Nov 2009 14:10:48 +0000 (14:10 +0000)
the registry under Windows.  Patch by Gabriel Genellina.

Doc/library/mimetypes.rst
Lib/mimetypes.py
Lib/test/test_mimetypes.py
Misc/NEWS

index 818f39f9cbb55adf94f2c79e85db7917bfcc3439..956a1f178e8cd519eea7855d96a77de39005330f 100644 (file)
@@ -77,9 +77,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:: 2.7
+      Previously, Windows registry settings were ignored.
 
 
 .. function:: read_mime_types(filename)
@@ -213,6 +217,12 @@ MimeTypes Objects
    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 @@ 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:: 2.7
index f0a5ecf7bba69e22d088efb1b6766a1a72e7fc1a..aead6566a5838daceeafc3e8f207fac924c9a366 100644 (file)
@@ -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
+try:
+    import _winreg
+except ImportError:
+    _winreg = None
 
 __all__ = [
     "guess_type","guess_extension","guess_all_extensions",
@@ -220,6 +226,52 @@ 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
+                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 @@ 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):
index cc1790e0dffa8a0ab1857452f58d0b91c02ba20c..3508b5605684a46092e6b6cb6beab060b58f7adb 100644 (file)
@@ -1,6 +1,7 @@
 import mimetypes
 import StringIO
 import unittest
+import sys
 
 from test import test_support
 
@@ -62,8 +63,31 @@ 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():
-    test_support.run_unittest(MimeTypesTestCase)
+    test_support.run_unittest(MimeTypesTestCase,
+        Win32MimeTypesTestCase
+        )
 
 
 if __name__ == "__main__":
index 3feccda6f66051c695e8f1f1947e76e60f2f9a0a..051bff81a66f168c8c4b1312d7011dd03693d7e7 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -429,6 +429,9 @@ Core and Builtins
 Library
 -------
 
+- Issue #4969: The mimetypes module now reads the MIME database from
+  the registry under Windows.  Patch by Gabriel Genellina.
+
 - Issue #6816: runpy now provides a run_path function that allows Python code
   to execute file paths that refer to source or compiled Python files as well
   as zipfiles, directories and other valid sys.path entries that contain a