(root)/
Python-3.11.7/
Lib/
test/
test_mimetypes.py
       1  import io
       2  import mimetypes
       3  import pathlib
       4  import sys
       5  import unittest.mock
       6  
       7  from test import support
       8  from test.support import os_helper
       9  from platform import win32_edition
      10  
      11  try:
      12      import _winapi
      13  except ImportError:
      14      _winapi = None
      15  
      16  
      17  def setUpModule():
      18      global knownfiles
      19      knownfiles = mimetypes.knownfiles
      20  
      21      # Tell it we don't know about external files:
      22      mimetypes.knownfiles = []
      23      mimetypes.inited = False
      24      mimetypes._default_mime_types()
      25  
      26  
      27  def tearDownModule():
      28      # Restore knownfiles to its initial state
      29      mimetypes.knownfiles = knownfiles
      30  
      31  
      32  class ESC[4;38;5;81mMimeTypesTestCase(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
      33      def setUp(self):
      34          self.db = mimetypes.MimeTypes()
      35  
      36      def test_case_sensitivity(self):
      37          eq = self.assertEqual
      38          eq(self.db.guess_type("foobar.HTML"), self.db.guess_type("foobar.html"))
      39          eq(self.db.guess_type("foobar.TGZ"), self.db.guess_type("foobar.tgz"))
      40          eq(self.db.guess_type("foobar.tar.Z"), ("application/x-tar", "compress"))
      41          eq(self.db.guess_type("foobar.tar.z"), (None, None))
      42  
      43      def test_default_data(self):
      44          eq = self.assertEqual
      45          eq(self.db.guess_type("foo.html"), ("text/html", None))
      46          eq(self.db.guess_type("foo.HTML"), ("text/html", None))
      47          eq(self.db.guess_type("foo.tgz"), ("application/x-tar", "gzip"))
      48          eq(self.db.guess_type("foo.tar.gz"), ("application/x-tar", "gzip"))
      49          eq(self.db.guess_type("foo.tar.Z"), ("application/x-tar", "compress"))
      50          eq(self.db.guess_type("foo.tar.bz2"), ("application/x-tar", "bzip2"))
      51          eq(self.db.guess_type("foo.tar.xz"), ("application/x-tar", "xz"))
      52  
      53      def test_data_urls(self):
      54          eq = self.assertEqual
      55          guess_type = self.db.guess_type
      56          eq(guess_type("data:invalidDataWithoutComma"), (None, None))
      57          eq(guess_type("data:,thisIsTextPlain"), ("text/plain", None))
      58          eq(guess_type("data:;base64,thisIsTextPlain"), ("text/plain", None))
      59          eq(guess_type("data:text/x-foo,thisIsTextXFoo"), ("text/x-foo", None))
      60  
      61      def test_file_parsing(self):
      62          eq = self.assertEqual
      63          sio = io.StringIO("x-application/x-unittest pyunit\n")
      64          self.db.readfp(sio)
      65          eq(self.db.guess_type("foo.pyunit"),
      66             ("x-application/x-unittest", None))
      67          eq(self.db.guess_extension("x-application/x-unittest"), ".pyunit")
      68  
      69      def test_read_mime_types(self):
      70          eq = self.assertEqual
      71  
      72          # Unreadable file returns None
      73          self.assertIsNone(mimetypes.read_mime_types("non-existent"))
      74  
      75          with os_helper.temp_dir() as directory:
      76              data = "x-application/x-unittest pyunit\n"
      77              file = pathlib.Path(directory, "sample.mimetype")
      78              file.write_text(data, encoding="utf-8")
      79              mime_dict = mimetypes.read_mime_types(file)
      80              eq(mime_dict[".pyunit"], "x-application/x-unittest")
      81  
      82          # bpo-41048: read_mime_types should read the rule file with 'utf-8' encoding.
      83          # Not with locale encoding. _bootlocale has been imported because io.open(...)
      84          # uses it.
      85          data = "application/no-mans-land  Fran\u00E7ais"
      86          filename = "filename"
      87          fp = io.StringIO(data)
      88          with unittest.mock.patch.object(mimetypes, 'open',
      89                                          return_value=fp) as mock_open:
      90              mime_dict = mimetypes.read_mime_types(filename)
      91              mock_open.assert_called_with(filename, encoding='utf-8')
      92          eq(mime_dict[".Français"], "application/no-mans-land")
      93  
      94      def test_non_standard_types(self):
      95          eq = self.assertEqual
      96          # First try strict
      97          eq(self.db.guess_type('foo.xul', strict=True), (None, None))
      98          eq(self.db.guess_extension('image/jpg', strict=True), None)
      99          eq(self.db.guess_extension('image/webp', strict=True), None)
     100          # And then non-strict
     101          eq(self.db.guess_type('foo.xul', strict=False), ('text/xul', None))
     102          eq(self.db.guess_type('foo.XUL', strict=False), ('text/xul', None))
     103          eq(self.db.guess_type('foo.invalid', strict=False), (None, None))
     104          eq(self.db.guess_extension('image/jpg', strict=False), '.jpg')
     105          eq(self.db.guess_extension('image/JPG', strict=False), '.jpg')
     106          eq(self.db.guess_extension('image/webp', strict=False), '.webp')
     107  
     108      def test_filename_with_url_delimiters(self):
     109          # bpo-38449: URL delimiters cases should be handled also.
     110          # They would have different mime types if interpreted as URL as
     111          # compared to when interpreted as filename because of the semicolon.
     112          eq = self.assertEqual
     113          gzip_expected = ('application/x-tar', 'gzip')
     114          eq(self.db.guess_type(";1.tar.gz"), gzip_expected)
     115          eq(self.db.guess_type("?1.tar.gz"), gzip_expected)
     116          eq(self.db.guess_type("#1.tar.gz"), gzip_expected)
     117          eq(self.db.guess_type("#1#.tar.gz"), gzip_expected)
     118          eq(self.db.guess_type(";1#.tar.gz"), gzip_expected)
     119          eq(self.db.guess_type(";&1=123;?.tar.gz"), gzip_expected)
     120          eq(self.db.guess_type("?k1=v1&k2=v2.tar.gz"), gzip_expected)
     121          eq(self.db.guess_type(r" \"\`;b&b&c |.tar.gz"), gzip_expected)
     122  
     123      def test_guess_all_types(self):
     124          # First try strict.  Use a set here for testing the results because if
     125          # test_urllib2 is run before test_mimetypes, global state is modified
     126          # such that the 'all' set will have more items in it.
     127          all = self.db.guess_all_extensions('text/plain', strict=True)
     128          self.assertTrue(set(all) >= {'.bat', '.c', '.h', '.ksh', '.pl', '.txt'})
     129          self.assertEqual(len(set(all)), len(all))  # no duplicates
     130          # And now non-strict
     131          all = self.db.guess_all_extensions('image/jpg', strict=False)
     132          self.assertEqual(all, ['.jpg'])
     133          # And now for no hits
     134          all = self.db.guess_all_extensions('image/jpg', strict=True)
     135          self.assertEqual(all, [])
     136          # And now for type existing in both strict and non-strict mappings.
     137          self.db.add_type('test-type', '.strict-ext')
     138          self.db.add_type('test-type', '.non-strict-ext', strict=False)
     139          all = self.db.guess_all_extensions('test-type', strict=False)
     140          self.assertEqual(all, ['.strict-ext', '.non-strict-ext'])
     141          all = self.db.guess_all_extensions('test-type')
     142          self.assertEqual(all, ['.strict-ext'])
     143          # Test that changing the result list does not affect the global state
     144          all.append('.no-such-ext')
     145          all = self.db.guess_all_extensions('test-type')
     146          self.assertNotIn('.no-such-ext', all)
     147  
     148      def test_encoding(self):
     149          filename = support.findfile("mime.types")
     150          mimes = mimetypes.MimeTypes([filename])
     151          exts = mimes.guess_all_extensions('application/vnd.geocube+xml',
     152                                            strict=True)
     153          self.assertEqual(exts, ['.g3', '.g\xb3'])
     154  
     155      def test_init_reinitializes(self):
     156          # Issue 4936: make sure an init starts clean
     157          # First, put some poison into the types table
     158          mimetypes.add_type('foo/bar', '.foobar')
     159          self.assertEqual(mimetypes.guess_extension('foo/bar'), '.foobar')
     160          # Reinitialize
     161          mimetypes.init()
     162          # Poison should be gone.
     163          self.assertEqual(mimetypes.guess_extension('foo/bar'), None)
     164  
     165      @unittest.skipIf(sys.platform.startswith("win"), "Non-Windows only")
     166      def test_guess_known_extensions(self):
     167          # Issue 37529
     168          # The test fails on Windows because Windows adds mime types from the Registry
     169          # and that creates some duplicates.
     170          from mimetypes import types_map
     171          for v in types_map.values():
     172              self.assertIsNotNone(mimetypes.guess_extension(v))
     173  
     174      def test_preferred_extension(self):
     175          def check_extensions():
     176              self.assertEqual(mimetypes.guess_extension('application/octet-stream'), '.bin')
     177              self.assertEqual(mimetypes.guess_extension('application/postscript'), '.ps')
     178              self.assertEqual(mimetypes.guess_extension('application/vnd.apple.mpegurl'), '.m3u')
     179              self.assertEqual(mimetypes.guess_extension('application/vnd.ms-excel'), '.xls')
     180              self.assertEqual(mimetypes.guess_extension('application/vnd.ms-powerpoint'), '.ppt')
     181              self.assertEqual(mimetypes.guess_extension('application/x-texinfo'), '.texi')
     182              self.assertEqual(mimetypes.guess_extension('application/x-troff'), '.roff')
     183              self.assertEqual(mimetypes.guess_extension('application/xml'), '.xsl')
     184              self.assertEqual(mimetypes.guess_extension('audio/mpeg'), '.mp3')
     185              self.assertEqual(mimetypes.guess_extension('image/avif'), '.avif')
     186              self.assertEqual(mimetypes.guess_extension('image/jpeg'), '.jpg')
     187              self.assertEqual(mimetypes.guess_extension('image/tiff'), '.tiff')
     188              self.assertEqual(mimetypes.guess_extension('message/rfc822'), '.eml')
     189              self.assertEqual(mimetypes.guess_extension('text/html'), '.html')
     190              self.assertEqual(mimetypes.guess_extension('text/plain'), '.txt')
     191              self.assertEqual(mimetypes.guess_extension('video/mpeg'), '.mpeg')
     192              self.assertEqual(mimetypes.guess_extension('video/quicktime'), '.mov')
     193  
     194          check_extensions()
     195          mimetypes.init()
     196          check_extensions()
     197  
     198      def test_init_stability(self):
     199          mimetypes.init()
     200  
     201          suffix_map = mimetypes.suffix_map
     202          encodings_map = mimetypes.encodings_map
     203          types_map = mimetypes.types_map
     204          common_types = mimetypes.common_types
     205  
     206          mimetypes.init()
     207          self.assertIsNot(suffix_map, mimetypes.suffix_map)
     208          self.assertIsNot(encodings_map, mimetypes.encodings_map)
     209          self.assertIsNot(types_map, mimetypes.types_map)
     210          self.assertIsNot(common_types, mimetypes.common_types)
     211          self.assertEqual(suffix_map, mimetypes.suffix_map)
     212          self.assertEqual(encodings_map, mimetypes.encodings_map)
     213          self.assertEqual(types_map, mimetypes.types_map)
     214          self.assertEqual(common_types, mimetypes.common_types)
     215  
     216      def test_path_like_ob(self):
     217          filename = "LICENSE.txt"
     218          filepath = pathlib.Path(filename)
     219          filepath_with_abs_dir = pathlib.Path('/dir/'+filename)
     220          filepath_relative = pathlib.Path('../dir/'+filename)
     221          path_dir = pathlib.Path('./')
     222  
     223          expected = self.db.guess_type(filename)
     224  
     225          self.assertEqual(self.db.guess_type(filepath), expected)
     226          self.assertEqual(self.db.guess_type(
     227              filepath_with_abs_dir), expected)
     228          self.assertEqual(self.db.guess_type(filepath_relative), expected)
     229          self.assertEqual(self.db.guess_type(path_dir), (None, None))
     230  
     231      def test_keywords_args_api(self):
     232          self.assertEqual(self.db.guess_type(
     233              url="foo.html", strict=True), ("text/html", None))
     234          self.assertEqual(self.db.guess_all_extensions(
     235              type='image/jpg', strict=True), [])
     236          self.assertEqual(self.db.guess_extension(
     237              type='image/jpg', strict=False), '.jpg')
     238  
     239  
     240  @unittest.skipUnless(sys.platform.startswith("win"), "Windows only")
     241  class ESC[4;38;5;81mWin32MimeTypesTestCase(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
     242      def setUp(self):
     243          # ensure all entries actually come from the Windows registry
     244          self.original_types_map = mimetypes.types_map.copy()
     245          mimetypes.types_map.clear()
     246          mimetypes.init()
     247          self.db = mimetypes.MimeTypes()
     248  
     249      def tearDown(self):
     250          # restore default settings
     251          mimetypes.types_map.clear()
     252          mimetypes.types_map.update(self.original_types_map)
     253  
     254      @unittest.skipIf(win32_edition() in ('NanoServer', 'WindowsCoreHeadless', 'IoTEdgeOS'),
     255                                           "MIME types registry keys unavailable")
     256      def test_registry_parsing(self):
     257          # the original, minimum contents of the MIME database in the
     258          # Windows registry is undocumented AFAIK.
     259          # Use file types that should *always* exist:
     260          eq = self.assertEqual
     261          eq(self.db.guess_type("foo.txt"), ("text/plain", None))
     262          eq(self.db.guess_type("image.jpg"), ("image/jpeg", None))
     263          eq(self.db.guess_type("image.png"), ("image/png", None))
     264  
     265      @unittest.skipIf(not hasattr(_winapi, "_mimetypes_read_windows_registry"),
     266                       "read_windows_registry accelerator unavailable")
     267      def test_registry_accelerator(self):
     268          from_accel = {}
     269          from_reg = {}
     270          _winapi._mimetypes_read_windows_registry(
     271              lambda v, k: from_accel.setdefault(k, set()).add(v)
     272          )
     273          mimetypes.MimeTypes._read_windows_registry(
     274              lambda v, k: from_reg.setdefault(k, set()).add(v)
     275          )
     276          self.assertEqual(list(from_reg), list(from_accel))
     277          for k in from_reg:
     278              self.assertEqual(from_reg[k], from_accel[k])
     279  
     280  
     281  class ESC[4;38;5;81mMiscTestCase(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
     282      def test__all__(self):
     283          support.check__all__(self, mimetypes)
     284  
     285  
     286  class ESC[4;38;5;81mMimetypesCliTestCase(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
     287  
     288      def mimetypes_cmd(self, *args, **kwargs):
     289          support.patch(self, sys, "argv", [sys.executable, *args])
     290          with support.captured_stdout() as output:
     291              mimetypes._main()
     292              return output.getvalue().strip()
     293  
     294      def test_help_option(self):
     295          support.patch(self, sys, "argv", [sys.executable, "-h"])
     296          with support.captured_stdout() as output:
     297              with self.assertRaises(SystemExit) as cm:
     298                  mimetypes._main()
     299  
     300          self.assertIn("Usage: mimetypes.py", output.getvalue())
     301          self.assertEqual(cm.exception.code, 0)
     302  
     303      def test_invalid_option(self):
     304          support.patch(self, sys, "argv", [sys.executable, "--invalid"])
     305          with support.captured_stdout() as output:
     306              with self.assertRaises(SystemExit) as cm:
     307                  mimetypes._main()
     308  
     309          self.assertIn("Usage: mimetypes.py", output.getvalue())
     310          self.assertEqual(cm.exception.code, 1)
     311  
     312      def test_guess_extension(self):
     313          eq = self.assertEqual
     314  
     315          extension = self.mimetypes_cmd("-l", "-e", "image/jpg")
     316          eq(extension, ".jpg")
     317  
     318          extension = self.mimetypes_cmd("-e", "image/jpg")
     319          eq(extension, "I don't know anything about type image/jpg")
     320  
     321          extension = self.mimetypes_cmd("-e", "image/jpeg")
     322          eq(extension, ".jpg")
     323  
     324      def test_guess_type(self):
     325          eq = self.assertEqual
     326  
     327          type_info = self.mimetypes_cmd("-l", "foo.pic")
     328          eq(type_info, "type: image/pict encoding: None")
     329  
     330          type_info = self.mimetypes_cmd("foo.pic")
     331          eq(type_info, "I don't know anything about type foo.pic")
     332  
     333  if __name__ == "__main__":
     334      unittest.main()