diff --git a/Doc/library/cmdline.rst b/Doc/library/cmdline.rst index 78fe95a014ff7c..59629b693ba00f 100644 --- a/Doc/library/cmdline.rst +++ b/Doc/library/cmdline.rst @@ -24,7 +24,7 @@ The following modules have a command-line interface. * :mod:`!idlelib` * :ref:`inspect ` * :ref:`json ` -* :mod:`mimetypes` +* :ref:`mimetypes ` * :mod:`pdb` * :mod:`pickle` * :ref:`pickletools ` diff --git a/Doc/library/mimetypes.rst b/Doc/library/mimetypes.rst index 514e773359a9aa..5af69455032d71 100644 --- a/Doc/library/mimetypes.rst +++ b/Doc/library/mimetypes.rst @@ -191,7 +191,7 @@ An example usage of the module:: .. _mimetypes-objects: -MimeTypes Objects +MimeTypes objects ----------------- The :class:`MimeTypes` class may be useful for applications which may want more @@ -307,3 +307,97 @@ than one MIME-type database; it provides an interface similar to the one of the When *strict* is ``True`` (the default), the mapping will be added to the official MIME types, otherwise to the non-standard ones. + + +.. _mimetypes-cli: + +Command-line usage +------------------ + +The :mod:`!mimetypes` module can be executed as a script from the command line. + +.. code-block:: sh + + python -m mimetypes [-h] [-e] [-l] type [type ...] + +The following options are accepted: + +.. program:: mimetypes + +.. cmdoption:: -h + --help + + Show the help message and exit. + +.. cmdoption:: -e + --extension + + Guess extension instead of type. + +.. cmdoption:: -l + --lenient + + Additionally search for some common, but non-standard types. + +By default the script converts MIME types to file extensions. +However, if ``--extension`` is specified, +it converts file extensions to MIME types. + +For each ``type`` entry, the script writes a line into the standard output +stream. If an unknown type occurs, it writes an error message into the +standard error stream and exits with the return code ``1``. + + +.. mimetypes-cli-example: + +Command-line example +-------------------- + +Here are some examples of typical usage of the :mod:`!mimetypes` command-line +interface: + +.. code-block:: console + + $ # get a MIME type by a file name + $ python -m mimetypes filename.png + type: image/png encoding: None + + $ # get a MIME type by a URL + $ python -m mimetypes https://example.com/filename.txt + type: text/plain encoding: None + + $ # get a complex MIME type + $ python -m mimetypes filename.tar.gz + type: application/x-tar encoding: gzip + + $ # get a MIME type for a rare file extension + $ python -m mimetypes filename.pict + error: unknown extension of filename.pict + + $ # now look in the extended database built into Python + $ python -m mimetypes --lenient filename.pict + type: image/pict encoding: None + + $ # get a file extension by a MIME type + $ python -m mimetypes --extension text/javascript + .js + + $ # get a file extension by a rare MIME type + $ python -m mimetypes --extension text/xul + error: unknown type text/xul + + $ # now look in the extended database again + $ python -m mimetypes --extension --lenient text/xul + .xul + + $ # try to feed an unknown file extension + $ python -m mimetypes filename.sh filename.nc filename.xxx filename.txt + type: application/x-sh encoding: None + type: application/x-netcdf encoding: None + error: unknown extension of filename.xxx + + $ # try to feed an unknown MIME type + $ python -m mimetypes --extension audio/aac audio/opus audio/future audio/x-wav + .aac + .opus + error: unknown type audio/future diff --git a/Doc/whatsnew/3.14.rst b/Doc/whatsnew/3.14.rst index 6539b23380b6e0..d4bf19a4d66ef3 100644 --- a/Doc/whatsnew/3.14.rst +++ b/Doc/whatsnew/3.14.rst @@ -641,6 +641,13 @@ json mimetypes --------- +* Document the command-line for :mod:`mimetypes`. + It now exits with ``1`` on failure instead of ``0`` + and ``2`` on incorrect command-line parameters instead of ``1``. + Also, errors are printed to stderr instead of stdout and their text is made + tighter. + (Contributed by Oleg Iarygin and Hugo van Kemenade in :gh:`93096`.) + * Add MS and :rfc:`8081` MIME types for fonts: * Embedded OpenType: ``application/vnd.ms-fontobject`` diff --git a/Lib/mimetypes.py b/Lib/mimetypes.py index ebad9a9ed27337..6b94fe3c4df756 100644 --- a/Lib/mimetypes.py +++ b/Lib/mimetypes.py @@ -670,50 +670,38 @@ def _default_mime_types(): def _main(): - import getopt + """Run the mimetypes command-line interface.""" import sys - - USAGE = """\ -Usage: mimetypes.py [options] type - -Options: - --help / -h -- print this message and exit - --lenient / -l -- additionally search of some common, but non-standard - types. - --extension / -e -- guess extension instead of type - -More than one type argument may be given. -""" - - def usage(code, msg=''): - print(USAGE) - if msg: print(msg) - sys.exit(code) - - try: - opts, args = getopt.getopt(sys.argv[1:], 'hle', - ['help', 'lenient', 'extension']) - except getopt.error as msg: - usage(1, msg) - - strict = 1 - extension = 0 - for opt, arg in opts: - if opt in ('-h', '--help'): - usage(0) - elif opt in ('-l', '--lenient'): - strict = 0 - elif opt in ('-e', '--extension'): - extension = 1 - for gtype in args: - if extension: - guess = guess_extension(gtype, strict) - if not guess: print("I don't know anything about type", gtype) - else: print(guess) - else: - guess, encoding = guess_type(gtype, strict) - if not guess: print("I don't know anything about type", gtype) - else: print('type:', guess, 'encoding:', encoding) + from argparse import ArgumentParser + + parser = ArgumentParser(description='map filename extensions to MIME types') + parser.add_argument( + '-e', '--extension', + action='store_true', + help='guess extension instead of type' + ) + parser.add_argument( + '-l', '--lenient', + action='store_true', + help='additionally search for common but non-standard types' + ) + parser.add_argument('type', nargs='+', help='a type to search') + args = parser.parse_args() + + if args.extension: + for gtype in args.type: + guess = guess_extension(gtype, not args.lenient) + if guess: + print(guess) + else: + sys.exit(f"error: unknown type {gtype}") + else: + for gtype in args.type: + guess, encoding = guess_type(gtype, not args.lenient) + if guess: + print('type:', guess, 'encoding:', encoding) + else: + sys.exit(f"error: media type unknown for {gtype}") if __name__ == '__main__': diff --git a/Lib/test/test_mimetypes.py b/Lib/test/test_mimetypes.py index bceb5c2fa0eb24..b5d1f50099e16a 100644 --- a/Lib/test/test_mimetypes.py +++ b/Lib/test/test_mimetypes.py @@ -3,9 +3,11 @@ import os import sys import unittest.mock +from os import linesep from test import support from test.support import os_helper +from test.support.script_helper import run_python_until_end from platform import win32_edition try: @@ -390,50 +392,53 @@ def test__all__(self): class MimetypesCliTestCase(unittest.TestCase): - def mimetypes_cmd(self, *args, **kwargs): - support.patch(self, sys, "argv", [sys.executable, *args]) - with support.captured_stdout() as output: - mimetypes._main() - return output.getvalue().strip() + def mimetypes_cmd(cls, *args, **kwargs): + result, _ = run_python_until_end('-m', 'mimetypes', *args) + return result.rc, result.out.decode(), result.err.decode() def test_help_option(self): - support.patch(self, sys, "argv", [sys.executable, "-h"]) - with support.captured_stdout() as output: - with self.assertRaises(SystemExit) as cm: - mimetypes._main() - - self.assertIn("Usage: mimetypes.py", output.getvalue()) - self.assertEqual(cm.exception.code, 0) + retcode, out, err = self.mimetypes_cmd('-h') + self.assertEqual(retcode, 0) + self.assertStartsWith(out, 'usage: ') + self.assertEqual(err, '') def test_invalid_option(self): - support.patch(self, sys, "argv", [sys.executable, "--invalid"]) - with support.captured_stdout() as output: - with self.assertRaises(SystemExit) as cm: - mimetypes._main() - - self.assertIn("Usage: mimetypes.py", output.getvalue()) - self.assertEqual(cm.exception.code, 1) + retcode, out, err = self.mimetypes_cmd('--invalid') + self.assertEqual(retcode, 2) + self.assertEqual(out, '') + self.assertStartsWith(err, 'usage: ') def test_guess_extension(self): - eq = self.assertEqual - - extension = self.mimetypes_cmd("-l", "-e", "image/jpg") - eq(extension, ".jpg") + retcode, out, err = self.mimetypes_cmd('-l', '-e', 'image/jpg') + self.assertEqual(retcode, 0) + self.assertEqual(out, f'.jpg{linesep}') + self.assertEqual(err, '') - extension = self.mimetypes_cmd("-e", "image/jpg") - eq(extension, "I don't know anything about type image/jpg") + retcode, out, err = self.mimetypes_cmd('-e', 'image/jpg') + self.assertEqual(retcode, 1) + self.assertEqual(out, '') + self.assertEqual(err, f'error: unknown type image/jpg{linesep}') - extension = self.mimetypes_cmd("-e", "image/jpeg") - eq(extension, ".jpg") + retcode, out, err = self.mimetypes_cmd('-e', 'image/jpeg') + self.assertEqual(retcode, 0) + self.assertEqual(out, f'.jpg{linesep}') + self.assertEqual(err, '') def test_guess_type(self): - eq = self.assertEqual - - type_info = self.mimetypes_cmd("-l", "foo.pic") - eq(type_info, "type: image/pict encoding: None") - - type_info = self.mimetypes_cmd("foo.pic") - eq(type_info, "I don't know anything about type foo.pic") + retcode, out, err = self.mimetypes_cmd('-l', 'foo.webp') + self.assertEqual(retcode, 0) + self.assertEqual(out, f'type: image/webp encoding: None{linesep}') + self.assertEqual(err, '') + + @unittest.skipIf( + sys.platform == 'darwin', + 'macOS lists common_types in mime.types thus making them always known' + ) + def test_guess_type_conflicting_with_mimetypes(self): + retcode, out, err = self.mimetypes_cmd('foo.pic') + self.assertEqual(retcode, 1) + self.assertEqual(out, '') + self.assertEqual(err, f'error: media type unknown for foo.pic{linesep}') if __name__ == "__main__": unittest.main() diff --git a/Misc/ACKS b/Misc/ACKS index da528f8b4ca3a7..2663042c06afd6 100644 --- a/Misc/ACKS +++ b/Misc/ACKS @@ -849,6 +849,7 @@ Oleg Höfling Robert Hölzl Stefan Hölzl Catalin Iacob +Oleg Iarygin Mihai Ibanescu Ali Ikinci Aaron Iles diff --git a/Misc/NEWS.d/next/Library/2022-05-28-19-41-02.gh-issue-93096.qjUyRG.rst b/Misc/NEWS.d/next/Library/2022-05-28-19-41-02.gh-issue-93096.qjUyRG.rst new file mode 100644 index 00000000000000..fb9ca441c7e2da --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-05-28-19-41-02.gh-issue-93096.qjUyRG.rst @@ -0,0 +1,5 @@ +Document the command-line for :mod:`mimetypes`. +It now exits with ``1`` on failure instead of ``0`` +and ``2`` on incorrect command-line parameters instead of ``1``. +Also, errors are printed to stderr instead of stdout and their text is made +tighter. Patch by Oleg Iarygin and Hugo van Kemenade. pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy