From 494fba8d9a424bdc21b83bdae23dc03cad8f05c9 Mon Sep 17 00:00:00 2001
From: Oleg Iarygin <oleg@arhadthedev.net>
Date: Thu, 24 Mar 2022 20:10:32 +0300
Subject: [PATCH 01/56] Make mimetypes CLI tool public

---
 Doc/library/mimetypes.rst | 33 ++++++++++++++++++++++++
 Lib/mimetypes.py          | 54 ++++++++++-----------------------------
 2 files changed, 47 insertions(+), 40 deletions(-)

diff --git a/Doc/library/mimetypes.rst b/Doc/library/mimetypes.rst
index f610032acbe417..63d29a1d0eac50 100644
--- a/Doc/library/mimetypes.rst
+++ b/Doc/library/mimetypes.rst
@@ -272,3 +272,36 @@ than one MIME-type database; it provides an interface similar to the one of the
       types, else to the list of non-standard types.
 
       .. versionadded:: 3.2
+
+
+.. mimetypes-cli:
+
+Command-Line Usage
+------------------
+
+The :mod:`mimetypes` module can be executed as a script from the command line.
+It is as simple as:
+
+.. code-block:: sh
+
+   python -m mimetypes [-e] [-l] type [type ...]
+
+The following options are accepted:
+
+.. program:: filecmp
+
+.. cmdoption:: -h, --help
+
+   Show the help message and exit.
+
+.. cmdoption:: -e, --extension
+
+   Guess extension instead of type.
+
+.. cmdoption:: -l, --lenient
+
+   Additionally search of some common, but non-standard types.
+
+The script scans the internal database and converts either file extensions to
+MIME types or vice versa depending on whether ``--extension`` option is
+specified.
diff --git a/Lib/mimetypes.py b/Lib/mimetypes.py
index 1aa32467e278a3..fc10b99272a433 100644
--- a/Lib/mimetypes.py
+++ b/Lib/mimetypes.py
@@ -596,51 +596,25 @@ def _default_mime_types():
 _default_mime_types()
 
 
-def _main():
-    import getopt
-
-    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)
+def _cli():
+    from argparse import ArgumentParser
+    parser = ArgumentParser(description='compare directories and files')
+    parser.add_argument('-e', '--extension', action='store_true',
+                        help='guess extension instead of type')
+    parser.add_argument('-l', '--lenient', action='store_true',
+                        help='search also for common but non-standard types')
+    parser.add_argument('type', nargs='+', help='type to search')
+    arguments = parser.parse_args()
+    for gtype in arguments.type:
+        if arguments.extension:
+            guess = guess_extension(gtype, not arguments.lenient)
             if not guess: print("I don't know anything about type", gtype)
             else: print(guess)
         else:
-            guess, encoding = guess_type(gtype, strict)
+            guess, encoding = guess_type(gtype, not arguments.lenient)
             if not guess: print("I don't know anything about type", gtype)
             else: print('type:', guess, 'encoding:', encoding)
 
 
 if __name__ == '__main__':
-    _main()
+    _cli()

From 5fdd90992aecbe78a6e597bf2259492cff330d08 Mon Sep 17 00:00:00 2001
From: Oleg Iarygin <oleg@arhadthedev.net>
Date: Mon, 23 May 2022 11:53:43 +0300
Subject: [PATCH 02/56] Add NEWS

---
 .../next/Library/2022-05-23-11-53-24.gh-issue-93096.TIuIhx.rst   | 1 +
 1 file changed, 1 insertion(+)
 create mode 100644 Misc/NEWS.d/next/Library/2022-05-23-11-53-24.gh-issue-93096.TIuIhx.rst

diff --git a/Misc/NEWS.d/next/Library/2022-05-23-11-53-24.gh-issue-93096.TIuIhx.rst b/Misc/NEWS.d/next/Library/2022-05-23-11-53-24.gh-issue-93096.TIuIhx.rst
new file mode 100644
index 00000000000000..3350e57f70f309
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2022-05-23-11-53-24.gh-issue-93096.TIuIhx.rst
@@ -0,0 +1 @@
+Added *Command-Line Usage* section for :mod:`mimetypes`.

From 1d778e2c030b397ea35786dc0c5bb31805be717d Mon Sep 17 00:00:00 2001
From: Oleg Iarygin <oleg@arhadthedev.net>
Date: Mon, 23 May 2022 12:54:57 +0300
Subject: [PATCH 03/56] No other module names the entry point _cli

---
 Lib/mimetypes.py | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/Lib/mimetypes.py b/Lib/mimetypes.py
index c5a0d92c5d0e35..ce68a452a87b94 100644
--- a/Lib/mimetypes.py
+++ b/Lib/mimetypes.py
@@ -598,7 +598,7 @@ def _default_mime_types():
 _default_mime_types()
 
 
-def _cli():
+def _main():
     from argparse import ArgumentParser
     parser = ArgumentParser(description='compare directories and files')
     parser.add_argument('-e', '--extension', action='store_true',
@@ -619,4 +619,4 @@ def _cli():
 
 
 if __name__ == '__main__':
-    _cli()
+    _main()

From d67704f4291ba335187b04ee4b112914aa388d53 Mon Sep 17 00:00:00 2001
From: Oleg Iarygin <oleg@arhadthedev.net>
Date: Mon, 23 May 2022 16:29:29 +0300
Subject: [PATCH 04/56] Adjust tests (capitalization of "Usage:" changed)

---
 Lib/test/test_mimetypes.py | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/Lib/test/test_mimetypes.py b/Lib/test/test_mimetypes.py
index d64aee71fc48b1..ae6b054f38ce1f 100644
--- a/Lib/test/test_mimetypes.py
+++ b/Lib/test/test_mimetypes.py
@@ -297,7 +297,7 @@ def test_help_option(self):
             with self.assertRaises(SystemExit) as cm:
                 mimetypes._main()
 
-        self.assertIn("Usage: mimetypes.py", output.getvalue())
+        self.assertIn("usage: mimetypes.py", output.getvalue())
         self.assertEqual(cm.exception.code, 0)
 
     def test_invalid_option(self):
@@ -306,7 +306,7 @@ def test_invalid_option(self):
             with self.assertRaises(SystemExit) as cm:
                 mimetypes._main()
 
-        self.assertIn("Usage: mimetypes.py", output.getvalue())
+        self.assertIn("usage: mimetypes.py", output.getvalue())
         self.assertEqual(cm.exception.code, 1)
 
     def test_guess_extension(self):

From 55df248ad591c619b647dd34313d1a8d578d0beb Mon Sep 17 00:00:00 2001
From: Oleg Iarygin <oleg@arhadthedev.net>
Date: Mon, 23 May 2022 18:25:01 +0300
Subject: [PATCH 05/56] For CLI tests, make proper script invocations with
 proper checks

---
 Lib/test/test_mimetypes.py | 72 ++++++++++++++++++++------------------
 1 file changed, 38 insertions(+), 34 deletions(-)

diff --git a/Lib/test/test_mimetypes.py b/Lib/test/test_mimetypes.py
index ae6b054f38ce1f..68be10bc829d7d 100644
--- a/Lib/test/test_mimetypes.py
+++ b/Lib/test/test_mimetypes.py
@@ -6,6 +6,7 @@
 
 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:
@@ -285,50 +286,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()
+    @classmethod
+    def to_string(cls, stream):
+        return stream.decode('ascii').strip()
 
-    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()
+    @classmethod
+    def mimetypes_cmd(cls, *args, **kwargs):
+        result, _ = run_python_until_end('-m', 'mimetypes', *args)
+        return result.rc, cls.to_string(result.out), cls.to_string(result.err)
 
-        self.assertIn("usage: mimetypes.py", output.getvalue())
-        self.assertEqual(cm.exception.code, 0)
+    def test_help_option(self):
+        retcode, out, err = self.mimetypes_cmd('-h')
+        self.assertEqual(retcode, 0)
+        self.assertIn('usage: mimetypes.py', out)
+        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.assertIn('usage: mimetypes.py', err)
 
     def test_guess_extension(self):
-        eq = self.assertEqual
+        retcode, out, err = self.mimetypes_cmd('-l', '-e', 'image/jpg')
+        self.assertEqual(retcode, 0)
+        self.assertEqual(out, '.jpg')
+        self.assertEqual(err, '')
 
-        extension = self.mimetypes_cmd("-l", "-e", "image/jpg")
-        eq(extension, ".jpg")
+        retcode, out, err = self.mimetypes_cmd('-e', 'image/jpg')
+        self.assertEqual(retcode, 0)
+        self.assertEqual(out, "I don't know anything about type image/jpg")
+        self.assertEqual(err, '')
 
-        extension = self.mimetypes_cmd("-e", "image/jpg")
-        eq(extension, "I don't know anything about type image/jpg")
-
-        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, '.jpg')
+        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.pic')
+        self.assertEqual(retcode, 0)
+        self.assertEqual(out, "type: image/pict encoding: None")
+        self.assertEqual(err, '')
+
+        retcode, out, err = self.mimetypes_cmd('foo.pic')
+        self.assertEqual(retcode, 0)
+        self.assertEqual(out, "I don't know anything about type foo.pic")
+        self.assertEqual(err, '')
 
 if __name__ == "__main__":
     unittest.main()

From b065ed863cee919cdff4eafecb5af851cc2f514a Mon Sep 17 00:00:00 2001
From: Oleg Iarygin <oleg@arhadthedev.net>
Date: Tue, 24 May 2022 13:01:41 +0300
Subject: [PATCH 06/56] Address @AA-Turner's review

---
 Lib/mimetypes.py | 15 ++++++++++-----
 1 file changed, 10 insertions(+), 5 deletions(-)

diff --git a/Lib/mimetypes.py b/Lib/mimetypes.py
index ce68a452a87b94..495db95163db74 100644
--- a/Lib/mimetypes.py
+++ b/Lib/mimetypes.py
@@ -600,7 +600,7 @@ def _default_mime_types():
 
 def _main():
     from argparse import ArgumentParser
-    parser = ArgumentParser(description='compare directories and files')
+    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',
@@ -610,12 +610,17 @@ def _main():
     for gtype in arguments.type:
         if arguments.extension:
             guess = guess_extension(gtype, not arguments.lenient)
-            if not guess: print("I don't know anything about type", gtype)
-            else: print(guess)
+            if guess:
+                print(guess)
+            else:
+                print("I don't know anything about type", gtype)
+
         else:
             guess, encoding = guess_type(gtype, not arguments.lenient)
-            if not guess: print("I don't know anything about type", gtype)
-            else: print('type:', guess, 'encoding:', encoding)
+            if guess:
+                print('type:', guess, 'encoding:', encoding)
+            else:
+                print("I don't know anything about type", gtype)
 
 
 if __name__ == '__main__':

From e7db03d7482974966288bdabc6f7ed9fe7a54344 Mon Sep 17 00:00:00 2001
From: Oleg Iarygin <oleg@arhadthedev.net>
Date: Tue, 24 May 2022 13:08:39 +0300
Subject: [PATCH 07/56] Move a constant check outside of a loop

---
 Lib/mimetypes.py | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/Lib/mimetypes.py b/Lib/mimetypes.py
index 495db95163db74..47fa01e8485034 100644
--- a/Lib/mimetypes.py
+++ b/Lib/mimetypes.py
@@ -607,15 +607,16 @@ def _main():
                         help='search also for common but non-standard types')
     parser.add_argument('type', nargs='+', help='type to search')
     arguments = parser.parse_args()
-    for gtype in arguments.type:
-        if arguments.extension:
+
+    if arguments.extension:
+        for gtype in arguments.type:
             guess = guess_extension(gtype, not arguments.lenient)
             if guess:
                 print(guess)
             else:
                 print("I don't know anything about type", gtype)
-
-        else:
+    else:
+        for gtype in arguments.type:
             guess, encoding = guess_type(gtype, not arguments.lenient)
             if guess:
                 print('type:', guess, 'encoding:', encoding)

From 6a1c96a9e8c3a265e5be4491fb0dc20b4bb9899f Mon Sep 17 00:00:00 2001
From: Oleg Iarygin <oleg@arhadthedev.net>
Date: Thu, 26 May 2022 08:16:15 +0300
Subject: [PATCH 08/56] Allow .pic MIME type be image/x-pict

---
 Lib/test/test_mimetypes.py | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/Lib/test/test_mimetypes.py b/Lib/test/test_mimetypes.py
index 68be10bc829d7d..6dc9c9cd87ec1a 100644
--- a/Lib/test/test_mimetypes.py
+++ b/Lib/test/test_mimetypes.py
@@ -326,7 +326,10 @@ def test_guess_extension(self):
     def test_guess_type(self):
         retcode, out, err = self.mimetypes_cmd('-l', 'foo.pic')
         self.assertEqual(retcode, 0)
-        self.assertEqual(out, "type: image/pict encoding: None")
+        self.assertIn(out, [
+            'type: image/pict encoding: None',
+            'type: image/x-pict encoding: None'
+        ])
         self.assertEqual(err, '')
 
         retcode, out, err = self.mimetypes_cmd('foo.pic')

From 010354d52abef1b33aa361cbc1f7fa40d18fc9e1 Mon Sep 17 00:00:00 2001
From: Oleg Iarygin <oleg@arhadthedev.net>
Date: Thu, 26 May 2022 09:47:13 +0300
Subject: [PATCH 09/56] Follow PEP 8 more

---
 Lib/mimetypes.py | 16 +++++++++++-----
 1 file changed, 11 insertions(+), 5 deletions(-)

diff --git a/Lib/mimetypes.py b/Lib/mimetypes.py
index 47fa01e8485034..17feffb42aacf4 100644
--- a/Lib/mimetypes.py
+++ b/Lib/mimetypes.py
@@ -601,11 +601,17 @@ def _default_mime_types():
 def _main():
     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='search also for common but non-standard types')
-    parser.add_argument('type', nargs='+', help='type to search')
+    parser.add_argument(
+        '-e', '--extension',
+        action='store_true',
+        help='guess extension instead of type'
+    )
+    parser.add_argument(
+        '-l', '--lenient',
+        action='store_true',
+        help='additianally search for common but non-standard types'
+    )
+    parser.add_argument('type', nargs='+', help='a type to search')
     arguments = parser.parse_args()
 
     if arguments.extension:

From 3368be443189f28da4da43512a3bfe3287f33e72 Mon Sep 17 00:00:00 2001
From: Oleg Iarygin <oleg@arhadthedev.net>
Date: Sat, 28 May 2022 18:59:41 +0300
Subject: [PATCH 10/56] Change forgotten quotation marks

---
 Lib/test/test_mimetypes.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Lib/test/test_mimetypes.py b/Lib/test/test_mimetypes.py
index 6dc9c9cd87ec1a..0bc78dd984217c 100644
--- a/Lib/test/test_mimetypes.py
+++ b/Lib/test/test_mimetypes.py
@@ -318,7 +318,7 @@ def test_guess_extension(self):
         self.assertEqual(out, "I don't know anything about type image/jpg")
         self.assertEqual(err, '')
 
-        retcode, out, err = self.mimetypes_cmd("-e", "image/jpeg")
+        retcode, out, err = self.mimetypes_cmd('-e', 'image/jpeg')
         self.assertEqual(retcode, 0)
         self.assertEqual(out, '.jpg')
         self.assertEqual(err, '')

From 26bec360d282e0cb783d69235486d424c56eb575 Mon Sep 17 00:00:00 2001
From: Oleg Iarygin <oleg@arhadthedev.net>
Date: Sat, 28 May 2022 19:03:19 +0300
Subject: [PATCH 11/56] Temporarily rollback everything but tests

---
 Lib/mimetypes.py | 74 ++++++++++++++++++++++++++++--------------------
 1 file changed, 43 insertions(+), 31 deletions(-)

diff --git a/Lib/mimetypes.py b/Lib/mimetypes.py
index 17feffb42aacf4..1aa32467e278a3 100644
--- a/Lib/mimetypes.py
+++ b/Lib/mimetypes.py
@@ -517,7 +517,6 @@ def _default_mime_types():
         '.aiff'   : 'audio/x-aiff',
         '.ra'     : 'audio/x-pn-realaudio',
         '.wav'    : 'audio/x-wav',
-        '.avif'   : 'image/avif',
         '.bmp'    : 'image/bmp',
         '.gif'    : 'image/gif',
         '.ief'    : 'image/ief',
@@ -590,7 +589,6 @@ def _default_mime_types():
         '.pict': 'image/pict',
         '.pct' : 'image/pict',
         '.pic' : 'image/pict',
-        '.webp': 'image/webp',
         '.xul' : 'text/xul',
         }
 
@@ -599,35 +597,49 @@ def _default_mime_types():
 
 
 def _main():
-    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='additianally search for common but non-standard types'
-    )
-    parser.add_argument('type', nargs='+', help='a type to search')
-    arguments = parser.parse_args()
-
-    if arguments.extension:
-        for gtype in arguments.type:
-            guess = guess_extension(gtype, not arguments.lenient)
-            if guess:
-                print(guess)
-            else:
-                print("I don't know anything about type", gtype)
-    else:
-        for gtype in arguments.type:
-            guess, encoding = guess_type(gtype, not arguments.lenient)
-            if guess:
-                print('type:', guess, 'encoding:', encoding)
-            else:
-                print("I don't know anything about type", gtype)
+    import getopt
+
+    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)
 
 
 if __name__ == '__main__':

From f1d4364a0cef130c2a7c97621e526f9e698cfcae Mon Sep 17 00:00:00 2001
From: Oleg Iarygin <oleg@arhadthedev.net>
Date: Sat, 28 May 2022 19:18:45 +0300
Subject: [PATCH 12/56] Revert "Temporarily rollback everything but tests"

This reverts commit 26bec360d282e0cb783d69235486d424c56eb575.
---
 Lib/mimetypes.py | 74 ++++++++++++++++++++----------------------------
 1 file changed, 31 insertions(+), 43 deletions(-)

diff --git a/Lib/mimetypes.py b/Lib/mimetypes.py
index 1aa32467e278a3..17feffb42aacf4 100644
--- a/Lib/mimetypes.py
+++ b/Lib/mimetypes.py
@@ -517,6 +517,7 @@ def _default_mime_types():
         '.aiff'   : 'audio/x-aiff',
         '.ra'     : 'audio/x-pn-realaudio',
         '.wav'    : 'audio/x-wav',
+        '.avif'   : 'image/avif',
         '.bmp'    : 'image/bmp',
         '.gif'    : 'image/gif',
         '.ief'    : 'image/ief',
@@ -589,6 +590,7 @@ def _default_mime_types():
         '.pict': 'image/pict',
         '.pct' : 'image/pict',
         '.pic' : 'image/pict',
+        '.webp': 'image/webp',
         '.xul' : 'text/xul',
         }
 
@@ -597,49 +599,35 @@ def _default_mime_types():
 
 
 def _main():
-    import getopt
-
-    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='additianally search for common but non-standard types'
+    )
+    parser.add_argument('type', nargs='+', help='a type to search')
+    arguments = parser.parse_args()
+
+    if arguments.extension:
+        for gtype in arguments.type:
+            guess = guess_extension(gtype, not arguments.lenient)
+            if guess:
+                print(guess)
+            else:
+                print("I don't know anything about type", gtype)
+    else:
+        for gtype in arguments.type:
+            guess, encoding = guess_type(gtype, not arguments.lenient)
+            if guess:
+                print('type:', guess, 'encoding:', encoding)
+            else:
+                print("I don't know anything about type", gtype)
 
 
 if __name__ == '__main__':

From 5e1de1777b38c05b0b6774fe723a36bb98b19420 Mon Sep 17 00:00:00 2001
From: Oleg Iarygin <oleg@arhadthedev.net>
Date: Sat, 28 May 2022 19:27:39 +0300
Subject: [PATCH 13/56] Add comments about assertIn()

---
 Lib/test/test_mimetypes.py | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/Lib/test/test_mimetypes.py b/Lib/test/test_mimetypes.py
index 0bc78dd984217c..6c457dabd839cf 100644
--- a/Lib/test/test_mimetypes.py
+++ b/Lib/test/test_mimetypes.py
@@ -327,7 +327,9 @@ def test_guess_type(self):
         retcode, out, err = self.mimetypes_cmd('-l', 'foo.pic')
         self.assertEqual(retcode, 0)
         self.assertIn(out, [
+            # Returned from the defaults when mime.types is missing
             'type: image/pict encoding: None',
+            # May be returned when mime.types is present
             'type: image/x-pict encoding: None'
         ])
         self.assertEqual(err, '')

From 48f1746ef25638b92e5e2037414b460c90e4867f Mon Sep 17 00:00:00 2001
From: Oleg Iarygin <oleg@arhadthedev.net>
Date: Sat, 28 May 2022 19:42:00 +0300
Subject: [PATCH 14/56] Normalize error codes too

---
 Lib/mimetypes.py                                            | 6 +++---
 Lib/test/test_mimetypes.py                                  | 4 ++--
 .../Library/2022-05-28-19-41-02.gh-issue-93096.qjUyRG.rst   | 2 ++
 3 files changed, 7 insertions(+), 5 deletions(-)
 create mode 100644 Misc/NEWS.d/next/Library/2022-05-28-19-41-02.gh-issue-93096.qjUyRG.rst

diff --git a/Lib/mimetypes.py b/Lib/mimetypes.py
index 17feffb42aacf4..fa0db58a0d116b 100644
--- a/Lib/mimetypes.py
+++ b/Lib/mimetypes.py
@@ -24,7 +24,7 @@
 """
 
 import os
-import sys
+from sys import exit
 import posixpath
 import urllib.parse
 
@@ -620,14 +620,14 @@ def _main():
             if guess:
                 print(guess)
             else:
-                print("I don't know anything about type", gtype)
+                exit("I don't know anything about type", gtype)
     else:
         for gtype in arguments.type:
             guess, encoding = guess_type(gtype, not arguments.lenient)
             if guess:
                 print('type:', guess, 'encoding:', encoding)
             else:
-                print("I don't know anything about type", gtype)
+                exit("I don't know anything about type", gtype)
 
 
 if __name__ == '__main__':
diff --git a/Lib/test/test_mimetypes.py b/Lib/test/test_mimetypes.py
index 6c457dabd839cf..f844cad75b2191 100644
--- a/Lib/test/test_mimetypes.py
+++ b/Lib/test/test_mimetypes.py
@@ -314,7 +314,7 @@ def test_guess_extension(self):
         self.assertEqual(err, '')
 
         retcode, out, err = self.mimetypes_cmd('-e', 'image/jpg')
-        self.assertEqual(retcode, 0)
+        self.assertEqual(retcode, 1)
         self.assertEqual(out, "I don't know anything about type image/jpg")
         self.assertEqual(err, '')
 
@@ -335,7 +335,7 @@ def test_guess_type(self):
         self.assertEqual(err, '')
 
         retcode, out, err = self.mimetypes_cmd('foo.pic')
-        self.assertEqual(retcode, 0)
+        self.assertEqual(retcode, 1)
         self.assertEqual(out, "I don't know anything about type foo.pic")
         self.assertEqual(err, '')
 
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..055336abe9627e
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2022-05-28-19-41-02.gh-issue-93096.qjUyRG.rst
@@ -0,0 +1,2 @@
+Command-line :mod:`mimetypes` started to return 1 instead of 0 for
+abruptions and 2 instead of 1 for incorrect command line parameters.

From 11b067dc379918305e3babf925bddbbe69a69a8a Mon Sep 17 00:00:00 2001
From: Oleg Iarygin <oleg@arhadthedev.net>
Date: Sat, 28 May 2022 20:06:23 +0300
Subject: [PATCH 15/56] `from sys import exit` clashes with the exit builtin

---
 Lib/mimetypes.py | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/Lib/mimetypes.py b/Lib/mimetypes.py
index fa0db58a0d116b..dcb037e742f25f 100644
--- a/Lib/mimetypes.py
+++ b/Lib/mimetypes.py
@@ -24,7 +24,7 @@
 """
 
 import os
-from sys import exit
+import sys
 import posixpath
 import urllib.parse
 
@@ -620,14 +620,14 @@ def _main():
             if guess:
                 print(guess)
             else:
-                exit("I don't know anything about type", gtype)
+                sys.exit("I don't know anything about type", gtype)
     else:
         for gtype in arguments.type:
             guess, encoding = guess_type(gtype, not arguments.lenient)
             if guess:
                 print('type:', guess, 'encoding:', encoding)
             else:
-                exit("I don't know anything about type", gtype)
+                sys.exit("I don't know anything about type", gtype)
 
 
 if __name__ == '__main__':

From 5589f7a906cf3b0835ec6f4d76e36e314c57da14 Mon Sep 17 00:00:00 2001
From: Oleg Iarygin <oleg@arhadthedev.net>
Date: Sat, 28 May 2022 20:07:58 +0300
Subject: [PATCH 16/56] Use f-strings for sys.exit()

---
 Lib/mimetypes.py | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/Lib/mimetypes.py b/Lib/mimetypes.py
index dcb037e742f25f..f5c75f9dae4ada 100644
--- a/Lib/mimetypes.py
+++ b/Lib/mimetypes.py
@@ -620,14 +620,14 @@ def _main():
             if guess:
                 print(guess)
             else:
-                sys.exit("I don't know anything about type", gtype)
+                sys.exit(f"I don't know anything about type {gtype}")
     else:
         for gtype in arguments.type:
             guess, encoding = guess_type(gtype, not arguments.lenient)
             if guess:
                 print('type:', guess, 'encoding:', encoding)
             else:
-                sys.exit("I don't know anything about type", gtype)
+                sys.exit(f"I don't know anything about type {gtype}")
 
 
 if __name__ == '__main__':

From 3ade3a603264888137d77f7d80aee20973b073e7 Mon Sep 17 00:00:00 2001
From: Oleg Iarygin <oleg@arhadthedev.net>
Date: Sat, 28 May 2022 20:17:09 +0300
Subject: [PATCH 17/56] Use an extension unknown to macOS

---
 Lib/test/test_mimetypes.py | 14 +++++---------
 1 file changed, 5 insertions(+), 9 deletions(-)

diff --git a/Lib/test/test_mimetypes.py b/Lib/test/test_mimetypes.py
index f844cad75b2191..ac0e5aa8661ba2 100644
--- a/Lib/test/test_mimetypes.py
+++ b/Lib/test/test_mimetypes.py
@@ -324,19 +324,15 @@ def test_guess_extension(self):
         self.assertEqual(err, '')
 
     def test_guess_type(self):
-        retcode, out, err = self.mimetypes_cmd('-l', 'foo.pic')
+        retcode, out, err = self.mimetypes_cmd('-l', 'foo.xul')
         self.assertEqual(retcode, 0)
-        self.assertIn(out, [
-            # Returned from the defaults when mime.types is missing
-            'type: image/pict encoding: None',
-            # May be returned when mime.types is present
-            'type: image/x-pict encoding: None'
-        ])
+        self.assertEqual(out, 'type: image/text encoding: None')
         self.assertEqual(err, '')
 
-        retcode, out, err = self.mimetypes_cmd('foo.pic')
+        # Previously, there was .pic format that macOS knew as strict
+        retcode, out, err = self.mimetypes_cmd('foo.xul')
         self.assertEqual(retcode, 1)
-        self.assertEqual(out, "I don't know anything about type foo.pic")
+        self.assertEqual(out, "I don't know anything about type foo.xul")
         self.assertEqual(err, '')
 
 if __name__ == "__main__":

From 895ac27d127ed8236914f17bc62f5c7f6c301174 Mon Sep 17 00:00:00 2001
From: Oleg Iarygin <oleg@arhadthedev.net>
Date: Sat, 28 May 2022 20:18:41 +0300
Subject: [PATCH 18/56] Fix an incorrect image/text to text/xul

---
 Lib/test/test_mimetypes.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Lib/test/test_mimetypes.py b/Lib/test/test_mimetypes.py
index ac0e5aa8661ba2..7b84667854fb97 100644
--- a/Lib/test/test_mimetypes.py
+++ b/Lib/test/test_mimetypes.py
@@ -326,7 +326,7 @@ def test_guess_extension(self):
     def test_guess_type(self):
         retcode, out, err = self.mimetypes_cmd('-l', 'foo.xul')
         self.assertEqual(retcode, 0)
-        self.assertEqual(out, 'type: image/text encoding: None')
+        self.assertEqual(out, 'type: text/xul encoding: None')
         self.assertEqual(err, '')
 
         # Previously, there was .pic format that macOS knew as strict

From 4476b300b813aae0efbd07d41a3b9b6435feef7f Mon Sep 17 00:00:00 2001
From: Oleg Iarygin <oleg@arhadthedev.net>
Date: Sat, 28 May 2022 20:43:15 +0300
Subject: [PATCH 19/56] Fix stdout/stderr mistesting

---
 Lib/test/test_mimetypes.py                                | 8 ++++----
 .../Library/2022-05-28-19-41-02.gh-issue-93096.qjUyRG.rst | 1 +
 2 files changed, 5 insertions(+), 4 deletions(-)

diff --git a/Lib/test/test_mimetypes.py b/Lib/test/test_mimetypes.py
index 7b84667854fb97..3b3d3bc29da5ef 100644
--- a/Lib/test/test_mimetypes.py
+++ b/Lib/test/test_mimetypes.py
@@ -315,8 +315,8 @@ def test_guess_extension(self):
 
         retcode, out, err = self.mimetypes_cmd('-e', 'image/jpg')
         self.assertEqual(retcode, 1)
-        self.assertEqual(out, "I don't know anything about type image/jpg")
-        self.assertEqual(err, '')
+        self.assertEqual(out, '')
+        self.assertEqual(err, "I don't know anything about type image/jpg")
 
         retcode, out, err = self.mimetypes_cmd('-e', 'image/jpeg')
         self.assertEqual(retcode, 0)
@@ -332,8 +332,8 @@ def test_guess_type(self):
         # Previously, there was .pic format that macOS knew as strict
         retcode, out, err = self.mimetypes_cmd('foo.xul')
         self.assertEqual(retcode, 1)
-        self.assertEqual(out, "I don't know anything about type foo.xul")
-        self.assertEqual(err, '')
+        self.assertEqual(out, '')
+        self.assertEqual(err, "I don't know anything about type foo.xul")
 
 if __name__ == "__main__":
     unittest.main()
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
index 055336abe9627e..ed8dd2769275bb 100644
--- 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
@@ -1,2 +1,3 @@
 Command-line :mod:`mimetypes` started to return 1 instead of 0 for
 abruptions and 2 instead of 1 for incorrect command line parameters.
+Also, errors are printed into stderr instead of stdout.

From 96e127b63d906ff128540d0d1c8390f6077dde58 Mon Sep 17 00:00:00 2001
From: Oleg Iarygin <oleg@arhadthedev.net>
Date: Sat, 28 May 2022 21:01:14 +0300
Subject: [PATCH 20/56] macOS, maybe Midi is what you don't override?

---
 Lib/test/test_mimetypes.py | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/Lib/test/test_mimetypes.py b/Lib/test/test_mimetypes.py
index 3b3d3bc29da5ef..53365ec54d0cc9 100644
--- a/Lib/test/test_mimetypes.py
+++ b/Lib/test/test_mimetypes.py
@@ -324,16 +324,16 @@ def test_guess_extension(self):
         self.assertEqual(err, '')
 
     def test_guess_type(self):
-        retcode, out, err = self.mimetypes_cmd('-l', 'foo.xul')
+        retcode, out, err = self.mimetypes_cmd('-l', 'foo.mid')
         self.assertEqual(retcode, 0)
-        self.assertEqual(out, 'type: text/xul encoding: None')
+        self.assertEqual(out, 'type: audio/midi encoding: None')
         self.assertEqual(err, '')
 
         # Previously, there was .pic format that macOS knew as strict
-        retcode, out, err = self.mimetypes_cmd('foo.xul')
+        retcode, out, err = self.mimetypes_cmd('foo.mid')
         self.assertEqual(retcode, 1)
         self.assertEqual(out, '')
-        self.assertEqual(err, "I don't know anything about type foo.xul")
+        self.assertEqual(err, "I don't know anything about type foo.mid")
 
 if __name__ == "__main__":
     unittest.main()

From 63b762e437e2a8858f7eb0cc660e87b532cb1482 Mon Sep 17 00:00:00 2001
From: Oleg Iarygin <oleg@arhadthedev.net>
Date: Sat, 28 May 2022 21:17:48 +0300
Subject: [PATCH 21/56] One more attempt to fix macOS-specific tests

---
 Lib/test/test_mimetypes.py | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/Lib/test/test_mimetypes.py b/Lib/test/test_mimetypes.py
index 53365ec54d0cc9..eaa0cdf045fffb 100644
--- a/Lib/test/test_mimetypes.py
+++ b/Lib/test/test_mimetypes.py
@@ -324,16 +324,16 @@ def test_guess_extension(self):
         self.assertEqual(err, '')
 
     def test_guess_type(self):
-        retcode, out, err = self.mimetypes_cmd('-l', 'foo.mid')
+        retcode, out, err = self.mimetypes_cmd('-l', 'foo.midi')
         self.assertEqual(retcode, 0)
         self.assertEqual(out, 'type: audio/midi encoding: None')
         self.assertEqual(err, '')
 
         # Previously, there was .pic format that macOS knew as strict
-        retcode, out, err = self.mimetypes_cmd('foo.mid')
+        retcode, out, err = self.mimetypes_cmd('foo.midi')
         self.assertEqual(retcode, 1)
         self.assertEqual(out, '')
-        self.assertEqual(err, "I don't know anything about type foo.mid")
+        self.assertEqual(err, "I don't know anything about type foo.midi")
 
 if __name__ == "__main__":
     unittest.main()

From 543d0037214d279d41db795e0fff161f8beafc39 Mon Sep 17 00:00:00 2001
From: Oleg Iarygin <oleg@arhadthedev.net>
Date: Sat, 28 May 2022 21:19:58 +0300
Subject: [PATCH 22/56] Maybe pict?

---
 Lib/test/test_mimetypes.py | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/Lib/test/test_mimetypes.py b/Lib/test/test_mimetypes.py
index eaa0cdf045fffb..42ea20f5cd0387 100644
--- a/Lib/test/test_mimetypes.py
+++ b/Lib/test/test_mimetypes.py
@@ -324,16 +324,16 @@ def test_guess_extension(self):
         self.assertEqual(err, '')
 
     def test_guess_type(self):
-        retcode, out, err = self.mimetypes_cmd('-l', 'foo.midi')
+        retcode, out, err = self.mimetypes_cmd('-l', 'foo.pict')
         self.assertEqual(retcode, 0)
-        self.assertEqual(out, 'type: audio/midi encoding: None')
+        self.assertEqual(out, 'type: image/pict encoding: None')
         self.assertEqual(err, '')
 
         # Previously, there was .pic format that macOS knew as strict
-        retcode, out, err = self.mimetypes_cmd('foo.midi')
+        retcode, out, err = self.mimetypes_cmd('foo.pict')
         self.assertEqual(retcode, 1)
         self.assertEqual(out, '')
-        self.assertEqual(err, "I don't know anything about type foo.midi")
+        self.assertEqual(err, "I don't know anything about type foo.pict")
 
 if __name__ == "__main__":
     unittest.main()

From 55c6165bce72a0476c9dfb77ec92d857643ca3a5 Mon Sep 17 00:00:00 2001
From: Oleg Iarygin <oleg@arhadthedev.net>
Date: Sat, 28 May 2022 22:08:29 +0300
Subject: [PATCH 23/56] Skip the strict case where mime.types is used

---
 Lib/test/test_mimetypes.py | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/Lib/test/test_mimetypes.py b/Lib/test/test_mimetypes.py
index 42ea20f5cd0387..27d4bc8750af57 100644
--- a/Lib/test/test_mimetypes.py
+++ b/Lib/test/test_mimetypes.py
@@ -324,16 +324,20 @@ def test_guess_extension(self):
         self.assertEqual(err, '')
 
     def test_guess_type(self):
-        retcode, out, err = self.mimetypes_cmd('-l', 'foo.pict')
+        retcode, out, err = self.mimetypes_cmd('-l', 'foo.pic')
         self.assertEqual(retcode, 0)
         self.assertEqual(out, 'type: image/pict encoding: None')
         self.assertEqual(err, '')
 
-        # Previously, there was .pic format that macOS knew as strict
-        retcode, out, err = self.mimetypes_cmd('foo.pict')
+    @unittest.skipIf(
+        sys.platform == "macos",
+        "mime.types knows the whole common_types so they are marked as strict"
+    )
+    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, "I don't know anything about type foo.pict")
+        self.assertEqual(err, "I don't know anything about type foo.pic")
 
 if __name__ == "__main__":
     unittest.main()

From 54f9889081e5b9252a8adb17079ebedd450658a5 Mon Sep 17 00:00:00 2001
From: Oleg Iarygin <oleg@arhadthedev.net>
Date: Sat, 28 May 2022 22:32:24 +0300
Subject: [PATCH 24/56] Temporarily disable all test but the broken one

---
 .github/workflows/build.yml | 271 ------------------------------------
 Lib/test/test_mimetypes.py  |   4 +-
 Tools/scripts/run_tests.py  |   2 +-
 3 files changed, 3 insertions(+), 274 deletions(-)

diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index d800442ad07e36..e643e679687494 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -26,132 +26,10 @@ permissions:
   contents: read
 
 jobs:
-  check_source:
-    name: 'Check for source changes'
-    runs-on: ubuntu-latest
-    outputs:
-      run_tests: ${{ steps.check.outputs.run_tests }}
-      run_ssl_tests: ${{ steps.check.outputs.run_ssl_tests }}
-    steps:
-      - uses: actions/checkout@v3
-      - name: Check for source changes
-        id: check
-        run: |
-          if [ -z "$GITHUB_BASE_REF" ]; then
-            echo '::set-output name=run_tests::true'
-            echo '::set-output name=run_ssl_tests::true'
-          else
-            git fetch origin $GITHUB_BASE_REF --depth=1
-            # git diff "origin/$GITHUB_BASE_REF..." (3 dots) may be more
-            # reliable than git diff "origin/$GITHUB_BASE_REF.." (2 dots),
-            # but it requires to download more commits (this job uses
-            # "git fetch --depth=1").
-            #
-            # git diff "origin/$GITHUB_BASE_REF..." (3 dots) works with Git
-            # 2.26, but Git 2.28 is stricter and fails with "no merge base".
-            #
-            # git diff "origin/$GITHUB_BASE_REF.." (2 dots) should be enough on
-            # GitHub, since GitHub starts by merging origin/$GITHUB_BASE_REF
-            # into the PR branch anyway.
-            #
-            # https://github.com/python/core-workflow/issues/373
-            git diff --name-only origin/$GITHUB_BASE_REF.. | grep -qvE '(\.rst$|^Doc|^Misc)' && echo '::set-output name=run_tests::true' || true
-            git diff --name-only origin/$GITHUB_BASE_REF.. | grep -qE '(ssl|hashlib|hmac|^.github)' && echo '::set-output name=run_ssl_tests::true' || true
-          fi
-
-  check_generated_files:
-    name: 'Check if generated files are up to date'
-    runs-on: ubuntu-latest
-    needs: check_source
-    if: needs.check_source.outputs.run_tests == 'true'
-    steps:
-      - uses: actions/checkout@v3
-      - uses: actions/setup-python@v3
-      - name: Install Dependencies
-        run: sudo ./.github/workflows/posix-deps-apt.sh
-      - name: Add ccache to PATH
-        run: echo "PATH=/usr/lib/ccache:$PATH" >> $GITHUB_ENV
-      - name: Configure ccache action
-        uses: hendrikmuhs/ccache-action@v1
-      - name: Check Autoconf version 2.69 and aclocal 1.16.3
-        run: |
-          grep "Generated by GNU Autoconf 2.69" configure
-          grep "aclocal 1.16.3" aclocal.m4
-          grep -q "runstatedir" configure
-          grep -q "PKG_PROG_PKG_CONFIG" aclocal.m4
-      - name: Configure CPython
-        run: |
-          # Build Python with the libpython dynamic library
-          ./configure --with-pydebug --enable-shared
-      - name: Regenerate autoconf files with container image
-        run: make regen-configure
-      - name: Build CPython
-        run: |
-          # Deepfreeze will usually cause global objects to be added or removed,
-          # so we run it before regen-global-objects gets rum (in regen-all).
-          make regen-deepfreeze
-          make -j4 regen-all
-          make regen-stdlib-module-names
-      - name: Check for changes
-        run: |
-          git add -u
-          changes=$(git status --porcelain)
-          # Check for changes in regenerated files
-          if test -n "$changes"; then
-            echo "Generated files not up to date."
-            echo "Perhaps you forgot to run make regen-all or build.bat --regen. ;)"
-            echo "configure files must be regenerated with a specific version of autoconf."
-            echo "$changes"
-            echo ""
-            git diff --staged || true
-            exit 1
-          fi
-      - name: Check exported libpython symbols
-        run: make smelly
-      - name: Check limited ABI symbols
-        run: make check-limited-abi
-
-  build_win32:
-    name: 'Windows (x86)'
-    runs-on: windows-latest
-    needs: check_source
-    if: needs.check_source.outputs.run_tests == 'true'
-    env:
-       IncludeUwp: 'true'
-    steps:
-    - uses: actions/checkout@v3
-    - name: Build CPython
-      run: .\PCbuild\build.bat -e -d -p Win32
-      timeout-minutes: 30
-    - name: Display build info
-      run: .\python.bat -m test.pythoninfo
-    - name: Tests
-      run: .\PCbuild\rt.bat -p Win32 -d -q -uall -u-cpu -rwW --slowest --timeout=1200 -j0
-
-  build_win_amd64:
-    name: 'Windows (x64)'
-    runs-on: windows-latest
-    needs: check_source
-    if: needs.check_source.outputs.run_tests == 'true'
-    env:
-       IncludeUwp: 'true'
-    steps:
-    - uses: actions/checkout@v3
-    - name: Register MSVC problem matcher
-      run: echo "::add-matcher::.github/problem-matchers/msvc.json"
-    - name: Build CPython
-      run: .\PCbuild\build.bat -e -d -p x64
-      timeout-minutes: 30
-    - name: Display build info
-      run: .\python.bat -m test.pythoninfo
-    - name: Tests
-      run: .\PCbuild\rt.bat -p x64 -d -q -uall -u-cpu -rwW --slowest --timeout=1200 -j0
-
   build_macos:
     name: 'macOS'
     runs-on: macos-latest
     needs: check_source
-    if: needs.check_source.outputs.run_tests == 'true'
     env:
       PYTHONSTRICTEXTENSIONBUILD: 1
     steps:
@@ -168,152 +46,3 @@ jobs:
       run: make pythoninfo
     - name: Tests
       run: make buildbottest TESTOPTS="-j4 -uall,-cpu"
-
-  build_ubuntu:
-    name: 'Ubuntu'
-    runs-on: ubuntu-20.04
-    needs: check_source
-    if: needs.check_source.outputs.run_tests == 'true'
-    env:
-      OPENSSL_VER: 1.1.1n
-      PYTHONSTRICTEXTENSIONBUILD: 1
-    steps:
-    - uses: actions/checkout@v3
-    - name: Register gcc problem matcher
-      run: echo "::add-matcher::.github/problem-matchers/gcc.json"
-    - name: Install Dependencies
-      run: sudo ./.github/workflows/posix-deps-apt.sh
-    - name: Configure OpenSSL env vars
-      run: |
-        echo "MULTISSL_DIR=${GITHUB_WORKSPACE}/multissl" >> $GITHUB_ENV
-        echo "OPENSSL_DIR=${GITHUB_WORKSPACE}/multissl/openssl/${OPENSSL_VER}" >> $GITHUB_ENV
-        echo "LD_LIBRARY_PATH=${GITHUB_WORKSPACE}/multissl/openssl/${OPENSSL_VER}/lib" >> $GITHUB_ENV
-    - name: 'Restore OpenSSL build'
-      id: cache-openssl
-      uses: actions/cache@v3
-      with:
-        path: ./multissl/openssl/${{ env.OPENSSL_VER }}
-        key: ${{ runner.os }}-multissl-openssl-${{ env.OPENSSL_VER }}
-    - name: Install OpenSSL
-      if: steps.cache-openssl.outputs.cache-hit != 'true'
-      run: python3 Tools/ssl/multissltests.py --steps=library --base-directory $MULTISSL_DIR --openssl $OPENSSL_VER --system Linux
-    - name: Add ccache to PATH
-      run: |
-        echo "PATH=/usr/lib/ccache:$PATH" >> $GITHUB_ENV
-    - name: Configure ccache action
-      uses: hendrikmuhs/ccache-action@v1
-    - name: Setup directory envs for out-of-tree builds
-      run: |
-        echo "CPYTHON_RO_SRCDIR=$(realpath -m ${GITHUB_WORKSPACE}/../cpython-ro-srcdir)" >> $GITHUB_ENV
-        echo "CPYTHON_BUILDDIR=$(realpath -m ${GITHUB_WORKSPACE}/../cpython-builddir)" >> $GITHUB_ENV
-    - name: Create directories for read-only out-of-tree builds
-      run: mkdir -p $CPYTHON_RO_SRCDIR $CPYTHON_BUILDDIR
-    - name: Bind mount sources read-only
-      run: sudo mount --bind -o ro $GITHUB_WORKSPACE $CPYTHON_RO_SRCDIR
-    - name: Configure CPython out-of-tree
-      working-directory: ${{ env.CPYTHON_BUILDDIR }}
-      run: ../cpython-ro-srcdir/configure --with-pydebug --with-openssl=$OPENSSL_DIR
-    - name: Build CPython out-of-tree
-      working-directory: ${{ env.CPYTHON_BUILDDIR }}
-      run: make -j4
-    - name: Display build info
-      working-directory: ${{ env.CPYTHON_BUILDDIR }}
-      run: make pythoninfo
-    - name: Remount sources writable for tests
-      # some tests write to srcdir, lack of pyc files slows down testing
-      run: sudo mount $CPYTHON_RO_SRCDIR -oremount,rw
-    - name: Tests
-      working-directory: ${{ env.CPYTHON_BUILDDIR }}
-      run: xvfb-run make buildbottest TESTOPTS="-j4 -uall,-cpu"
-
-  build_ubuntu_ssltests:
-    name: 'Ubuntu SSL tests with OpenSSL'
-    runs-on: ubuntu-20.04
-    needs: check_source
-    if: needs.check_source.outputs.run_tests == 'true' && needs.check_source.outputs.run_ssl_tests == 'true'
-    strategy:
-      fail-fast: false
-      matrix:
-        openssl_ver: [1.1.1n, 3.0.2]
-    env:
-      OPENSSL_VER: ${{ matrix.openssl_ver }}
-      MULTISSL_DIR: ${{ github.workspace }}/multissl
-      OPENSSL_DIR: ${{ github.workspace }}/multissl/openssl/${{ matrix.openssl_ver }}
-      LD_LIBRARY_PATH: ${{ github.workspace }}/multissl/openssl/${{ matrix.openssl_ver }}/lib
-    steps:
-    - uses: actions/checkout@v3
-    - name: Register gcc problem matcher
-      run: echo "::add-matcher::.github/problem-matchers/gcc.json"
-    - name: Install Dependencies
-      run: sudo ./.github/workflows/posix-deps-apt.sh
-    - name: Configure OpenSSL env vars
-      run: |
-        echo "MULTISSL_DIR=${GITHUB_WORKSPACE}/multissl" >> $GITHUB_ENV
-        echo "OPENSSL_DIR=${GITHUB_WORKSPACE}/multissl/openssl/${OPENSSL_VER}" >> $GITHUB_ENV
-        echo "LD_LIBRARY_PATH=${GITHUB_WORKSPACE}/multissl/openssl/${OPENSSL_VER}/lib" >> $GITHUB_ENV
-    - name: 'Restore OpenSSL build'
-      id: cache-openssl
-      uses: actions/cache@v3
-      with:
-        path: ./multissl/openssl/${{ env.OPENSSL_VER }}
-        key: ${{ runner.os }}-multissl-openssl-${{ env.OPENSSL_VER }}
-    - name: Install OpenSSL
-      if: steps.cache-openssl.outputs.cache-hit != 'true'
-      run: python3 Tools/ssl/multissltests.py --steps=library --base-directory $MULTISSL_DIR --openssl $OPENSSL_VER --system Linux
-    - name: Add ccache to PATH
-      run: |
-        echo "PATH=/usr/lib/ccache:$PATH" >> $GITHUB_ENV
-    - name: Configure ccache action
-      uses: hendrikmuhs/ccache-action@v1
-    - name: Configure CPython
-      run: ./configure --with-pydebug --with-openssl=$OPENSSL_DIR
-    - name: Build CPython
-      run: make -j4
-    - name: Display build info
-      run: make pythoninfo
-    - name: SSL tests
-      run: ./python Lib/test/ssltests.py
-
-
-  build_asan:
-    name: 'Address sanitizer'
-    runs-on: ubuntu-20.04
-    needs: check_source
-    if: needs.check_source.outputs.run_tests == 'true'
-    env:
-      OPENSSL_VER: 1.1.1n
-      PYTHONSTRICTEXTENSIONBUILD: 1
-      ASAN_OPTIONS: detect_leaks=0:allocator_may_return_null=1:handle_segv=0
-    steps:
-    - uses: actions/checkout@v3
-    - name: Register gcc problem matcher
-      run: echo "::add-matcher::.github/problem-matchers/gcc.json"
-    - name: Install Dependencies
-      run: sudo ./.github/workflows/posix-deps-apt.sh
-    - name: Configure OpenSSL env vars
-      run: |
-        echo "MULTISSL_DIR=${GITHUB_WORKSPACE}/multissl" >> $GITHUB_ENV
-        echo "OPENSSL_DIR=${GITHUB_WORKSPACE}/multissl/openssl/${OPENSSL_VER}" >> $GITHUB_ENV
-        echo "LD_LIBRARY_PATH=${GITHUB_WORKSPACE}/multissl/openssl/${OPENSSL_VER}/lib" >> $GITHUB_ENV
-    - name: 'Restore OpenSSL build'
-      id: cache-openssl
-      uses: actions/cache@v3
-      with:
-        path: ./multissl/openssl/${{ env.OPENSSL_VER }}
-        key: ${{ runner.os }}-multissl-openssl-${{ env.OPENSSL_VER }}
-    - name: Install OpenSSL
-      if: steps.cache-openssl.outputs.cache-hit != 'true'
-      run: python3 Tools/ssl/multissltests.py --steps=library --base-directory $MULTISSL_DIR --openssl $OPENSSL_VER --system Linux
-    - name: Add ccache to PATH
-      run: |
-        echo "PATH=/usr/lib/ccache:$PATH" >> $GITHUB_ENV
-    - name: Configure ccache action
-      uses: hendrikmuhs/ccache-action@v1
-    - name: Configure CPython
-      run: ./configure --with-address-sanitizer --without-pymalloc
-    - name: Build CPython
-      run: make -j4
-    - name: Display build info
-      run: make pythoninfo
-    - name: Tests
-      run: xvfb-run make buildbottest TESTOPTS="-j4 -uall,-cpu"
diff --git a/Lib/test/test_mimetypes.py b/Lib/test/test_mimetypes.py
index 27d4bc8750af57..d71005f8ff8809 100644
--- a/Lib/test/test_mimetypes.py
+++ b/Lib/test/test_mimetypes.py
@@ -330,8 +330,8 @@ def test_guess_type(self):
         self.assertEqual(err, '')
 
     @unittest.skipIf(
-        sys.platform == "macos",
-        "mime.types knows the whole common_types so they are marked as strict"
+        sys.platform == 'darwin',
+        'mime.types knows the whole common_types so they are marked as strict'
     )
     def test_guess_type_conflicting_with_mimetypes(self):
         retcode, out, err = self.mimetypes_cmd('foo.pic')
diff --git a/Tools/scripts/run_tests.py b/Tools/scripts/run_tests.py
index 48feb3f778ee8d..4cc1ab8baff917 100644
--- a/Tools/scripts/run_tests.py
+++ b/Tools/scripts/run_tests.py
@@ -33,7 +33,7 @@ def main(regrtest_args):
 
     args.extend(['-m', 'test',    # Run the test suite
                  '-r',            # Randomize test order
-                 '-w',            # Re-run failed tests in verbose mode
+                 'test_mimetypes'
                  ])
     if sys.platform == 'win32':
         args.append('-n')         # Silence alerts under Windows

From be068976489b0aeb786299ba82273ab5c5cf490e Mon Sep 17 00:00:00 2001
From: Oleg Iarygin <oleg@arhadthedev.net>
Date: Sat, 28 May 2022 22:38:19 +0300
Subject: [PATCH 25/56] Temporarily remove doc building too

---
 .github/workflows/build.yml |  1 -
 .github/workflows/doc.yml   | 59 -------------------------------------
 2 files changed, 60 deletions(-)
 delete mode 100644 .github/workflows/doc.yml

diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index e643e679687494..fcd35107f005c4 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -29,7 +29,6 @@ jobs:
   build_macos:
     name: 'macOS'
     runs-on: macos-latest
-    needs: check_source
     env:
       PYTHONSTRICTEXTENSIONBUILD: 1
     steps:
diff --git a/.github/workflows/doc.yml b/.github/workflows/doc.yml
deleted file mode 100644
index 9cd251648cdeaf..00000000000000
--- a/.github/workflows/doc.yml
+++ /dev/null
@@ -1,59 +0,0 @@
-name: Docs
-
-on:
-  workflow_dispatch:
-  #push:
-  #  branches:
-  #  - 'main'
-  #  - '3.11'
-  #  - '3.10'
-  #  - '3.9'
-  #  - '3.8'
-  #  - '3.7'
-  #  paths:
-  #  - 'Doc/**'
-  pull_request:
-    branches:
-    - 'main'
-    - '3.11'
-    - '3.10'
-    - '3.9'
-    - '3.8'
-    - '3.7'
-    paths:
-    - 'Doc/**'
-    - 'Misc/**'
-
-permissions:
-  contents: read
-
-jobs:
-  build_doc:
-    name: 'Docs'
-    runs-on: ubuntu-latest
-    steps:
-    - uses: actions/checkout@v3
-    - name: Register Sphinx problem matcher
-      run: echo "::add-matcher::.github/problem-matchers/sphinx.json"
-    - name: 'Install Dependencies'
-      run: sudo ./.github/workflows/posix-deps-apt.sh && sudo apt-get install wamerican
-    - name: 'Configure CPython'
-      run: ./configure --with-pydebug
-    - name: 'Build CPython'
-      run: make -j4
-    - name: 'Install build dependencies'
-      run: make -C Doc/ PYTHON=../python venv
-    # Run "check doctest html" as 3 steps to get a more readable output
-    # in the web UI
-    - name: 'Check documentation'
-      run: make -C Doc/ PYTHON=../python SPHINXOPTS="-q -W --keep-going" check
-    # Use "xvfb-run" since some doctest tests open GUI windows
-    - name: 'Run documentation doctest'
-      run: xvfb-run make -C Doc/ PYTHON=../python SPHINXOPTS="-q -W --keep-going" doctest
-    - name: 'Build HTML documentation'
-      run: make -C Doc/ PYTHON=../python SPHINXOPTS="-q -W --keep-going" html
-    - name: 'Upload'
-      uses: actions/upload-artifact@v3
-      with:
-        name: doc-html
-        path: Doc/build/html

From 6af766869ce03af17f1484a7b727f9e8f2f17a10 Mon Sep 17 00:00:00 2001
From: Oleg Iarygin <oleg@arhadthedev.net>
Date: Sat, 28 May 2022 22:57:55 +0300
Subject: [PATCH 26/56] temporary: Add printing of a platform name

---
 Lib/test/test_mimetypes.py | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Lib/test/test_mimetypes.py b/Lib/test/test_mimetypes.py
index d71005f8ff8809..be8eeeb17a9243 100644
--- a/Lib/test/test_mimetypes.py
+++ b/Lib/test/test_mimetypes.py
@@ -328,6 +328,7 @@ def test_guess_type(self):
         self.assertEqual(retcode, 0)
         self.assertEqual(out, 'type: image/pict encoding: None')
         self.assertEqual(err, '')
+        print(f'====================================================================={sys.platform}')
 
     @unittest.skipIf(
         sys.platform == 'darwin',

From 037b68e70272310e7f47981db8f34b857ca105ae Mon Sep 17 00:00:00 2001
From: Oleg Iarygin <oleg@arhadthedev.net>
Date: Sat, 28 May 2022 23:13:49 +0300
Subject: [PATCH 27/56] temporary: Another attempt

---
 Lib/test/test_mimetypes.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Lib/test/test_mimetypes.py b/Lib/test/test_mimetypes.py
index be8eeeb17a9243..b92c0f8b6343ca 100644
--- a/Lib/test/test_mimetypes.py
+++ b/Lib/test/test_mimetypes.py
@@ -324,11 +324,11 @@ def test_guess_extension(self):
         self.assertEqual(err, '')
 
     def test_guess_type(self):
+        print(f'====================================================================={sys.platform}')
         retcode, out, err = self.mimetypes_cmd('-l', 'foo.pic')
         self.assertEqual(retcode, 0)
         self.assertEqual(out, 'type: image/pict encoding: None')
         self.assertEqual(err, '')
-        print(f'====================================================================={sys.platform}')
 
     @unittest.skipIf(
         sys.platform == 'darwin',

From de4f377b609208f573a01cf099c952c12d5928ca Mon Sep 17 00:00:00 2001
From: Oleg Iarygin <oleg@arhadthedev.net>
Date: Sat, 28 May 2022 23:22:24 +0300
Subject: [PATCH 28/56] Return to MIDI

---
 Lib/test/test_mimetypes.py | 9 ++++-----
 1 file changed, 4 insertions(+), 5 deletions(-)

diff --git a/Lib/test/test_mimetypes.py b/Lib/test/test_mimetypes.py
index b92c0f8b6343ca..ff4bdbf7f1de1a 100644
--- a/Lib/test/test_mimetypes.py
+++ b/Lib/test/test_mimetypes.py
@@ -324,10 +324,9 @@ def test_guess_extension(self):
         self.assertEqual(err, '')
 
     def test_guess_type(self):
-        print(f'====================================================================={sys.platform}')
-        retcode, out, err = self.mimetypes_cmd('-l', 'foo.pic')
+        retcode, out, err = self.mimetypes_cmd('-l', 'foo.mid')
         self.assertEqual(retcode, 0)
-        self.assertEqual(out, 'type: image/pict encoding: None')
+        self.assertEqual(out, 'type: audio/midi encoding: None')
         self.assertEqual(err, '')
 
     @unittest.skipIf(
@@ -335,10 +334,10 @@ def test_guess_type(self):
         'mime.types knows the whole common_types so they are marked as strict'
     )
     def test_guess_type_conflicting_with_mimetypes(self):
-        retcode, out, err = self.mimetypes_cmd('foo.pic')
+        retcode, out, err = self.mimetypes_cmd('foo.mid')
         self.assertEqual(retcode, 1)
         self.assertEqual(out, '')
-        self.assertEqual(err, "I don't know anything about type foo.pic")
+        self.assertEqual(err, "I don't know anything about type foo.mid")
 
 if __name__ == "__main__":
     unittest.main()

From a8e77189051d76cc3e955a7a559b9cb3640c04f2 Mon Sep 17 00:00:00 2001
From: Oleg Iarygin <oleg@arhadthedev.net>
Date: Sat, 28 May 2022 23:31:19 +0300
Subject: [PATCH 29/56] Restore build scripts

---
 .github/workflows/build.yml | 272 ++++++++++++++++++++++++++++++++++++
 .github/workflows/doc.yml   |  59 ++++++++
 Tools/scripts/run_tests.py  |   2 +-
 3 files changed, 332 insertions(+), 1 deletion(-)
 create mode 100644 .github/workflows/doc.yml

diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index fcd35107f005c4..d800442ad07e36 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -26,9 +26,132 @@ permissions:
   contents: read
 
 jobs:
+  check_source:
+    name: 'Check for source changes'
+    runs-on: ubuntu-latest
+    outputs:
+      run_tests: ${{ steps.check.outputs.run_tests }}
+      run_ssl_tests: ${{ steps.check.outputs.run_ssl_tests }}
+    steps:
+      - uses: actions/checkout@v3
+      - name: Check for source changes
+        id: check
+        run: |
+          if [ -z "$GITHUB_BASE_REF" ]; then
+            echo '::set-output name=run_tests::true'
+            echo '::set-output name=run_ssl_tests::true'
+          else
+            git fetch origin $GITHUB_BASE_REF --depth=1
+            # git diff "origin/$GITHUB_BASE_REF..." (3 dots) may be more
+            # reliable than git diff "origin/$GITHUB_BASE_REF.." (2 dots),
+            # but it requires to download more commits (this job uses
+            # "git fetch --depth=1").
+            #
+            # git diff "origin/$GITHUB_BASE_REF..." (3 dots) works with Git
+            # 2.26, but Git 2.28 is stricter and fails with "no merge base".
+            #
+            # git diff "origin/$GITHUB_BASE_REF.." (2 dots) should be enough on
+            # GitHub, since GitHub starts by merging origin/$GITHUB_BASE_REF
+            # into the PR branch anyway.
+            #
+            # https://github.com/python/core-workflow/issues/373
+            git diff --name-only origin/$GITHUB_BASE_REF.. | grep -qvE '(\.rst$|^Doc|^Misc)' && echo '::set-output name=run_tests::true' || true
+            git diff --name-only origin/$GITHUB_BASE_REF.. | grep -qE '(ssl|hashlib|hmac|^.github)' && echo '::set-output name=run_ssl_tests::true' || true
+          fi
+
+  check_generated_files:
+    name: 'Check if generated files are up to date'
+    runs-on: ubuntu-latest
+    needs: check_source
+    if: needs.check_source.outputs.run_tests == 'true'
+    steps:
+      - uses: actions/checkout@v3
+      - uses: actions/setup-python@v3
+      - name: Install Dependencies
+        run: sudo ./.github/workflows/posix-deps-apt.sh
+      - name: Add ccache to PATH
+        run: echo "PATH=/usr/lib/ccache:$PATH" >> $GITHUB_ENV
+      - name: Configure ccache action
+        uses: hendrikmuhs/ccache-action@v1
+      - name: Check Autoconf version 2.69 and aclocal 1.16.3
+        run: |
+          grep "Generated by GNU Autoconf 2.69" configure
+          grep "aclocal 1.16.3" aclocal.m4
+          grep -q "runstatedir" configure
+          grep -q "PKG_PROG_PKG_CONFIG" aclocal.m4
+      - name: Configure CPython
+        run: |
+          # Build Python with the libpython dynamic library
+          ./configure --with-pydebug --enable-shared
+      - name: Regenerate autoconf files with container image
+        run: make regen-configure
+      - name: Build CPython
+        run: |
+          # Deepfreeze will usually cause global objects to be added or removed,
+          # so we run it before regen-global-objects gets rum (in regen-all).
+          make regen-deepfreeze
+          make -j4 regen-all
+          make regen-stdlib-module-names
+      - name: Check for changes
+        run: |
+          git add -u
+          changes=$(git status --porcelain)
+          # Check for changes in regenerated files
+          if test -n "$changes"; then
+            echo "Generated files not up to date."
+            echo "Perhaps you forgot to run make regen-all or build.bat --regen. ;)"
+            echo "configure files must be regenerated with a specific version of autoconf."
+            echo "$changes"
+            echo ""
+            git diff --staged || true
+            exit 1
+          fi
+      - name: Check exported libpython symbols
+        run: make smelly
+      - name: Check limited ABI symbols
+        run: make check-limited-abi
+
+  build_win32:
+    name: 'Windows (x86)'
+    runs-on: windows-latest
+    needs: check_source
+    if: needs.check_source.outputs.run_tests == 'true'
+    env:
+       IncludeUwp: 'true'
+    steps:
+    - uses: actions/checkout@v3
+    - name: Build CPython
+      run: .\PCbuild\build.bat -e -d -p Win32
+      timeout-minutes: 30
+    - name: Display build info
+      run: .\python.bat -m test.pythoninfo
+    - name: Tests
+      run: .\PCbuild\rt.bat -p Win32 -d -q -uall -u-cpu -rwW --slowest --timeout=1200 -j0
+
+  build_win_amd64:
+    name: 'Windows (x64)'
+    runs-on: windows-latest
+    needs: check_source
+    if: needs.check_source.outputs.run_tests == 'true'
+    env:
+       IncludeUwp: 'true'
+    steps:
+    - uses: actions/checkout@v3
+    - name: Register MSVC problem matcher
+      run: echo "::add-matcher::.github/problem-matchers/msvc.json"
+    - name: Build CPython
+      run: .\PCbuild\build.bat -e -d -p x64
+      timeout-minutes: 30
+    - name: Display build info
+      run: .\python.bat -m test.pythoninfo
+    - name: Tests
+      run: .\PCbuild\rt.bat -p x64 -d -q -uall -u-cpu -rwW --slowest --timeout=1200 -j0
+
   build_macos:
     name: 'macOS'
     runs-on: macos-latest
+    needs: check_source
+    if: needs.check_source.outputs.run_tests == 'true'
     env:
       PYTHONSTRICTEXTENSIONBUILD: 1
     steps:
@@ -45,3 +168,152 @@ jobs:
       run: make pythoninfo
     - name: Tests
       run: make buildbottest TESTOPTS="-j4 -uall,-cpu"
+
+  build_ubuntu:
+    name: 'Ubuntu'
+    runs-on: ubuntu-20.04
+    needs: check_source
+    if: needs.check_source.outputs.run_tests == 'true'
+    env:
+      OPENSSL_VER: 1.1.1n
+      PYTHONSTRICTEXTENSIONBUILD: 1
+    steps:
+    - uses: actions/checkout@v3
+    - name: Register gcc problem matcher
+      run: echo "::add-matcher::.github/problem-matchers/gcc.json"
+    - name: Install Dependencies
+      run: sudo ./.github/workflows/posix-deps-apt.sh
+    - name: Configure OpenSSL env vars
+      run: |
+        echo "MULTISSL_DIR=${GITHUB_WORKSPACE}/multissl" >> $GITHUB_ENV
+        echo "OPENSSL_DIR=${GITHUB_WORKSPACE}/multissl/openssl/${OPENSSL_VER}" >> $GITHUB_ENV
+        echo "LD_LIBRARY_PATH=${GITHUB_WORKSPACE}/multissl/openssl/${OPENSSL_VER}/lib" >> $GITHUB_ENV
+    - name: 'Restore OpenSSL build'
+      id: cache-openssl
+      uses: actions/cache@v3
+      with:
+        path: ./multissl/openssl/${{ env.OPENSSL_VER }}
+        key: ${{ runner.os }}-multissl-openssl-${{ env.OPENSSL_VER }}
+    - name: Install OpenSSL
+      if: steps.cache-openssl.outputs.cache-hit != 'true'
+      run: python3 Tools/ssl/multissltests.py --steps=library --base-directory $MULTISSL_DIR --openssl $OPENSSL_VER --system Linux
+    - name: Add ccache to PATH
+      run: |
+        echo "PATH=/usr/lib/ccache:$PATH" >> $GITHUB_ENV
+    - name: Configure ccache action
+      uses: hendrikmuhs/ccache-action@v1
+    - name: Setup directory envs for out-of-tree builds
+      run: |
+        echo "CPYTHON_RO_SRCDIR=$(realpath -m ${GITHUB_WORKSPACE}/../cpython-ro-srcdir)" >> $GITHUB_ENV
+        echo "CPYTHON_BUILDDIR=$(realpath -m ${GITHUB_WORKSPACE}/../cpython-builddir)" >> $GITHUB_ENV
+    - name: Create directories for read-only out-of-tree builds
+      run: mkdir -p $CPYTHON_RO_SRCDIR $CPYTHON_BUILDDIR
+    - name: Bind mount sources read-only
+      run: sudo mount --bind -o ro $GITHUB_WORKSPACE $CPYTHON_RO_SRCDIR
+    - name: Configure CPython out-of-tree
+      working-directory: ${{ env.CPYTHON_BUILDDIR }}
+      run: ../cpython-ro-srcdir/configure --with-pydebug --with-openssl=$OPENSSL_DIR
+    - name: Build CPython out-of-tree
+      working-directory: ${{ env.CPYTHON_BUILDDIR }}
+      run: make -j4
+    - name: Display build info
+      working-directory: ${{ env.CPYTHON_BUILDDIR }}
+      run: make pythoninfo
+    - name: Remount sources writable for tests
+      # some tests write to srcdir, lack of pyc files slows down testing
+      run: sudo mount $CPYTHON_RO_SRCDIR -oremount,rw
+    - name: Tests
+      working-directory: ${{ env.CPYTHON_BUILDDIR }}
+      run: xvfb-run make buildbottest TESTOPTS="-j4 -uall,-cpu"
+
+  build_ubuntu_ssltests:
+    name: 'Ubuntu SSL tests with OpenSSL'
+    runs-on: ubuntu-20.04
+    needs: check_source
+    if: needs.check_source.outputs.run_tests == 'true' && needs.check_source.outputs.run_ssl_tests == 'true'
+    strategy:
+      fail-fast: false
+      matrix:
+        openssl_ver: [1.1.1n, 3.0.2]
+    env:
+      OPENSSL_VER: ${{ matrix.openssl_ver }}
+      MULTISSL_DIR: ${{ github.workspace }}/multissl
+      OPENSSL_DIR: ${{ github.workspace }}/multissl/openssl/${{ matrix.openssl_ver }}
+      LD_LIBRARY_PATH: ${{ github.workspace }}/multissl/openssl/${{ matrix.openssl_ver }}/lib
+    steps:
+    - uses: actions/checkout@v3
+    - name: Register gcc problem matcher
+      run: echo "::add-matcher::.github/problem-matchers/gcc.json"
+    - name: Install Dependencies
+      run: sudo ./.github/workflows/posix-deps-apt.sh
+    - name: Configure OpenSSL env vars
+      run: |
+        echo "MULTISSL_DIR=${GITHUB_WORKSPACE}/multissl" >> $GITHUB_ENV
+        echo "OPENSSL_DIR=${GITHUB_WORKSPACE}/multissl/openssl/${OPENSSL_VER}" >> $GITHUB_ENV
+        echo "LD_LIBRARY_PATH=${GITHUB_WORKSPACE}/multissl/openssl/${OPENSSL_VER}/lib" >> $GITHUB_ENV
+    - name: 'Restore OpenSSL build'
+      id: cache-openssl
+      uses: actions/cache@v3
+      with:
+        path: ./multissl/openssl/${{ env.OPENSSL_VER }}
+        key: ${{ runner.os }}-multissl-openssl-${{ env.OPENSSL_VER }}
+    - name: Install OpenSSL
+      if: steps.cache-openssl.outputs.cache-hit != 'true'
+      run: python3 Tools/ssl/multissltests.py --steps=library --base-directory $MULTISSL_DIR --openssl $OPENSSL_VER --system Linux
+    - name: Add ccache to PATH
+      run: |
+        echo "PATH=/usr/lib/ccache:$PATH" >> $GITHUB_ENV
+    - name: Configure ccache action
+      uses: hendrikmuhs/ccache-action@v1
+    - name: Configure CPython
+      run: ./configure --with-pydebug --with-openssl=$OPENSSL_DIR
+    - name: Build CPython
+      run: make -j4
+    - name: Display build info
+      run: make pythoninfo
+    - name: SSL tests
+      run: ./python Lib/test/ssltests.py
+
+
+  build_asan:
+    name: 'Address sanitizer'
+    runs-on: ubuntu-20.04
+    needs: check_source
+    if: needs.check_source.outputs.run_tests == 'true'
+    env:
+      OPENSSL_VER: 1.1.1n
+      PYTHONSTRICTEXTENSIONBUILD: 1
+      ASAN_OPTIONS: detect_leaks=0:allocator_may_return_null=1:handle_segv=0
+    steps:
+    - uses: actions/checkout@v3
+    - name: Register gcc problem matcher
+      run: echo "::add-matcher::.github/problem-matchers/gcc.json"
+    - name: Install Dependencies
+      run: sudo ./.github/workflows/posix-deps-apt.sh
+    - name: Configure OpenSSL env vars
+      run: |
+        echo "MULTISSL_DIR=${GITHUB_WORKSPACE}/multissl" >> $GITHUB_ENV
+        echo "OPENSSL_DIR=${GITHUB_WORKSPACE}/multissl/openssl/${OPENSSL_VER}" >> $GITHUB_ENV
+        echo "LD_LIBRARY_PATH=${GITHUB_WORKSPACE}/multissl/openssl/${OPENSSL_VER}/lib" >> $GITHUB_ENV
+    - name: 'Restore OpenSSL build'
+      id: cache-openssl
+      uses: actions/cache@v3
+      with:
+        path: ./multissl/openssl/${{ env.OPENSSL_VER }}
+        key: ${{ runner.os }}-multissl-openssl-${{ env.OPENSSL_VER }}
+    - name: Install OpenSSL
+      if: steps.cache-openssl.outputs.cache-hit != 'true'
+      run: python3 Tools/ssl/multissltests.py --steps=library --base-directory $MULTISSL_DIR --openssl $OPENSSL_VER --system Linux
+    - name: Add ccache to PATH
+      run: |
+        echo "PATH=/usr/lib/ccache:$PATH" >> $GITHUB_ENV
+    - name: Configure ccache action
+      uses: hendrikmuhs/ccache-action@v1
+    - name: Configure CPython
+      run: ./configure --with-address-sanitizer --without-pymalloc
+    - name: Build CPython
+      run: make -j4
+    - name: Display build info
+      run: make pythoninfo
+    - name: Tests
+      run: xvfb-run make buildbottest TESTOPTS="-j4 -uall,-cpu"
diff --git a/.github/workflows/doc.yml b/.github/workflows/doc.yml
new file mode 100644
index 00000000000000..9cd251648cdeaf
--- /dev/null
+++ b/.github/workflows/doc.yml
@@ -0,0 +1,59 @@
+name: Docs
+
+on:
+  workflow_dispatch:
+  #push:
+  #  branches:
+  #  - 'main'
+  #  - '3.11'
+  #  - '3.10'
+  #  - '3.9'
+  #  - '3.8'
+  #  - '3.7'
+  #  paths:
+  #  - 'Doc/**'
+  pull_request:
+    branches:
+    - 'main'
+    - '3.11'
+    - '3.10'
+    - '3.9'
+    - '3.8'
+    - '3.7'
+    paths:
+    - 'Doc/**'
+    - 'Misc/**'
+
+permissions:
+  contents: read
+
+jobs:
+  build_doc:
+    name: 'Docs'
+    runs-on: ubuntu-latest
+    steps:
+    - uses: actions/checkout@v3
+    - name: Register Sphinx problem matcher
+      run: echo "::add-matcher::.github/problem-matchers/sphinx.json"
+    - name: 'Install Dependencies'
+      run: sudo ./.github/workflows/posix-deps-apt.sh && sudo apt-get install wamerican
+    - name: 'Configure CPython'
+      run: ./configure --with-pydebug
+    - name: 'Build CPython'
+      run: make -j4
+    - name: 'Install build dependencies'
+      run: make -C Doc/ PYTHON=../python venv
+    # Run "check doctest html" as 3 steps to get a more readable output
+    # in the web UI
+    - name: 'Check documentation'
+      run: make -C Doc/ PYTHON=../python SPHINXOPTS="-q -W --keep-going" check
+    # Use "xvfb-run" since some doctest tests open GUI windows
+    - name: 'Run documentation doctest'
+      run: xvfb-run make -C Doc/ PYTHON=../python SPHINXOPTS="-q -W --keep-going" doctest
+    - name: 'Build HTML documentation'
+      run: make -C Doc/ PYTHON=../python SPHINXOPTS="-q -W --keep-going" html
+    - name: 'Upload'
+      uses: actions/upload-artifact@v3
+      with:
+        name: doc-html
+        path: Doc/build/html
diff --git a/Tools/scripts/run_tests.py b/Tools/scripts/run_tests.py
index 4cc1ab8baff917..48feb3f778ee8d 100644
--- a/Tools/scripts/run_tests.py
+++ b/Tools/scripts/run_tests.py
@@ -33,7 +33,7 @@ def main(regrtest_args):
 
     args.extend(['-m', 'test',    # Run the test suite
                  '-r',            # Randomize test order
-                 'test_mimetypes'
+                 '-w',            # Re-run failed tests in verbose mode
                  ])
     if sys.platform == 'win32':
         args.append('-n')         # Silence alerts under Windows

From df910bc0ddeca1c6aefb265beabe06fd60267b4e Mon Sep 17 00:00:00 2001
From: Oleg Iarygin <oleg@arhadthedev.net>
Date: Sun, 29 May 2022 00:09:12 +0300
Subject: [PATCH 30/56] One more attempt

---
 Lib/test/test_mimetypes.py | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/Lib/test/test_mimetypes.py b/Lib/test/test_mimetypes.py
index ff4bdbf7f1de1a..c68b023bf0b56c 100644
--- a/Lib/test/test_mimetypes.py
+++ b/Lib/test/test_mimetypes.py
@@ -324,9 +324,9 @@ def test_guess_extension(self):
         self.assertEqual(err, '')
 
     def test_guess_type(self):
-        retcode, out, err = self.mimetypes_cmd('-l', 'foo.mid')
+        retcode, out, err = self.mimetypes_cmd('-l', 'foo.webp')
         self.assertEqual(retcode, 0)
-        self.assertEqual(out, 'type: audio/midi encoding: None')
+        self.assertEqual(out, 'type: image/webp encoding: None')
         self.assertEqual(err, '')
 
     @unittest.skipIf(
@@ -334,10 +334,10 @@ def test_guess_type(self):
         'mime.types knows the whole common_types so they are marked as strict'
     )
     def test_guess_type_conflicting_with_mimetypes(self):
-        retcode, out, err = self.mimetypes_cmd('foo.mid')
+        retcode, out, err = self.mimetypes_cmd('foo.webp')
         self.assertEqual(retcode, 1)
         self.assertEqual(out, '')
-        self.assertEqual(err, "I don't know anything about type foo.mid")
+        self.assertEqual(err, "I don't know anything about type foo.webp")
 
 if __name__ == "__main__":
     unittest.main()

From cf2a7687adfefa8ae8e912ca5986e8cdcf6d0e28 Mon Sep 17 00:00:00 2001
From: Oleg Iarygin <oleg@arhadthedev.net>
Date: Sun, 29 May 2022 17:29:23 +0300
Subject: [PATCH 31/56] Fix a typo

---
 Lib/mimetypes.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Lib/mimetypes.py b/Lib/mimetypes.py
index f5c75f9dae4ada..e641e1c942213c 100644
--- a/Lib/mimetypes.py
+++ b/Lib/mimetypes.py
@@ -609,7 +609,7 @@ def _main():
     parser.add_argument(
         '-l', '--lenient',
         action='store_true',
-        help='additianally search for common but non-standard types'
+        help='additionally search for common but non-standard types'
     )
     parser.add_argument('type', nargs='+', help='a type to search')
     arguments = parser.parse_args()

From c975d4c0646034138f0f909f471f7235ded97393 Mon Sep 17 00:00:00 2001
From: Oleg Iarygin <oleg@arhadthedev.net>
Date: Thu, 2 Jun 2022 09:38:43 +0300
Subject: [PATCH 32/56] Move a documentation-related news entry

---
 .../2022-05-23-11-53-24.gh-issue-93096.TIuIhx.rst                 | 0
 1 file changed, 0 insertions(+), 0 deletions(-)
 rename Misc/NEWS.d/next/{Library => Documentation}/2022-05-23-11-53-24.gh-issue-93096.TIuIhx.rst (100%)

diff --git a/Misc/NEWS.d/next/Library/2022-05-23-11-53-24.gh-issue-93096.TIuIhx.rst b/Misc/NEWS.d/next/Documentation/2022-05-23-11-53-24.gh-issue-93096.TIuIhx.rst
similarity index 100%
rename from Misc/NEWS.d/next/Library/2022-05-23-11-53-24.gh-issue-93096.TIuIhx.rst
rename to Misc/NEWS.d/next/Documentation/2022-05-23-11-53-24.gh-issue-93096.TIuIhx.rst

From bc1c707c4649d058825a7de3f426167726a81669 Mon Sep 17 00:00:00 2001
From: Oleg Iarygin <oleg@arhadthedev.net>
Date: Fri, 10 Jun 2022 22:46:43 +0300
Subject: [PATCH 33/56] Apply suggestions from the @AA-Turner's code review

Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com>
---
 Doc/library/mimetypes.rst                                   | 2 +-
 .../Library/2022-05-28-19-41-02.gh-issue-93096.qjUyRG.rst   | 6 +++---
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/Doc/library/mimetypes.rst b/Doc/library/mimetypes.rst
index 63d29a1d0eac50..a4a94b7c24aa46 100644
--- a/Doc/library/mimetypes.rst
+++ b/Doc/library/mimetypes.rst
@@ -288,7 +288,7 @@ It is as simple as:
 
 The following options are accepted:
 
-.. program:: filecmp
+.. program:: mimetypes
 
 .. cmdoption:: -h, --help
 
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
index ed8dd2769275bb..0fb651d048a9ab 100644
--- 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
@@ -1,3 +1,3 @@
-Command-line :mod:`mimetypes` started to return 1 instead of 0 for
-abruptions and 2 instead of 1 for incorrect command line parameters.
-Also, errors are printed into stderr instead of stdout.
+Command-line :mod:`mimetypes` started to exit with 1 instead of 0
+on failure and 2 instead of 1 for incorrect command line parameters.
+Also, errors are printed to stderr instead of stdout.

From aeba8202d41534c62cd33379b00b7663476dcd3e Mon Sep 17 00:00:00 2001
From: Oleg Iarygin <oleg@arhadthedev.net>
Date: Tue, 25 Oct 2022 09:41:50 +0400
Subject: [PATCH 34/56] Make CLI tests more strict

---
 Lib/test/test_mimetypes.py | 6 +-----
 1 file changed, 1 insertion(+), 5 deletions(-)

diff --git a/Lib/test/test_mimetypes.py b/Lib/test/test_mimetypes.py
index c68b023bf0b56c..765d114c3f8317 100644
--- a/Lib/test/test_mimetypes.py
+++ b/Lib/test/test_mimetypes.py
@@ -286,14 +286,10 @@ def test__all__(self):
 
 class MimetypesCliTestCase(unittest.TestCase):
 
-    @classmethod
-    def to_string(cls, stream):
-        return stream.decode('ascii').strip()
-
     @classmethod
     def mimetypes_cmd(cls, *args, **kwargs):
         result, _ = run_python_until_end('-m', 'mimetypes', *args)
-        return result.rc, cls.to_string(result.out), cls.to_string(result.err)
+        return result.rc, result.out.decode(), result.err.decode()
 
     def test_help_option(self):
         retcode, out, err = self.mimetypes_cmd('-h')

From c94593f5c6fc7934477c00b792eb48113279481f Mon Sep 17 00:00:00 2001
From: Oleg Iarygin <oleg@arhadthedev.net>
Date: Tue, 25 Oct 2022 20:38:13 +0400
Subject: [PATCH 35/56] Add newlines into assertEqual reference strings

---
 Lib/test/test_mimetypes.py | 13 +++++++------
 1 file changed, 7 insertions(+), 6 deletions(-)

diff --git a/Lib/test/test_mimetypes.py b/Lib/test/test_mimetypes.py
index 765d114c3f8317..01d6932ed71126 100644
--- a/Lib/test/test_mimetypes.py
+++ b/Lib/test/test_mimetypes.py
@@ -1,5 +1,6 @@
 import io
 import mimetypes
+from os import linesep
 import pathlib
 import sys
 import unittest.mock
@@ -306,34 +307,34 @@ def test_invalid_option(self):
     def test_guess_extension(self):
         retcode, out, err = self.mimetypes_cmd('-l', '-e', 'image/jpg')
         self.assertEqual(retcode, 0)
-        self.assertEqual(out, '.jpg')
+        self.assertEqual(out, f'.jpg{linesep}')
         self.assertEqual(err, '')
 
         retcode, out, err = self.mimetypes_cmd('-e', 'image/jpg')
         self.assertEqual(retcode, 1)
         self.assertEqual(out, '')
-        self.assertEqual(err, "I don't know anything about type image/jpg")
+        self.assertEqual(err, f"I don't know anything about type image/jpg{linesep}")
 
         retcode, out, err = self.mimetypes_cmd('-e', 'image/jpeg')
         self.assertEqual(retcode, 0)
-        self.assertEqual(out, '.jpg')
+        self.assertEqual(out, f'.jpg{linesep}')
         self.assertEqual(err, '')
 
     def test_guess_type(self):
         retcode, out, err = self.mimetypes_cmd('-l', 'foo.webp')
         self.assertEqual(retcode, 0)
-        self.assertEqual(out, 'type: image/webp encoding: None')
+        self.assertEqual(out, f'type: image/webp encoding: None{linesep}')
         self.assertEqual(err, '')
 
     @unittest.skipIf(
         sys.platform == 'darwin',
-        'mime.types knows the whole common_types so they are marked as strict'
+        '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.webp')
         self.assertEqual(retcode, 1)
         self.assertEqual(out, '')
-        self.assertEqual(err, "I don't know anything about type foo.webp")
+        self.assertEqual(err, f"I don't know anything about type foo.webp{linesep}")
 
 if __name__ == "__main__":
     unittest.main()

From 8b20082b3363d737a765ece3d843e055fde8ef5e Mon Sep 17 00:00:00 2001
From: Oleg Iarygin <oleg@arhadthedev.net>
Date: Tue, 25 Oct 2022 20:26:39 +0400
Subject: [PATCH 36/56] Clarify the NEWS entries

---
 .../2022-05-23-11-53-24.gh-issue-93096.TIuIhx.rst           | 2 +-
 .../Library/2022-05-28-19-41-02.gh-issue-93096.qjUyRG.rst   | 6 +++---
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/Misc/NEWS.d/next/Documentation/2022-05-23-11-53-24.gh-issue-93096.TIuIhx.rst b/Misc/NEWS.d/next/Documentation/2022-05-23-11-53-24.gh-issue-93096.TIuIhx.rst
index 3350e57f70f309..08c37c8a77046b 100644
--- a/Misc/NEWS.d/next/Documentation/2022-05-23-11-53-24.gh-issue-93096.TIuIhx.rst
+++ b/Misc/NEWS.d/next/Documentation/2022-05-23-11-53-24.gh-issue-93096.TIuIhx.rst
@@ -1 +1 @@
-Added *Command-Line Usage* section for :mod:`mimetypes`.
+Added *Command-Line Usage* section for :mod:`mimetypes`. Patch by Oleg Iarygin.
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
index 0fb651d048a9ab..36d1a2cf0291e1 100644
--- 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
@@ -1,3 +1,3 @@
-Command-line :mod:`mimetypes` started to exit with 1 instead of 0
-on failure and 2 instead of 1 for incorrect command line parameters.
-Also, errors are printed to stderr instead of stdout.
+Command-line :mod:`mimetypes` now exits with ``1`` instead of ``0``
+on failure and ``2`` instead of ``1`` on incorrect command line parameters.
+Also, errors are printed to stderr instead of stdout. Patch by Oleg Iarygin.

From 407413ddae178cff68e7cae04ed9dde9f6dcf9b8 Mon Sep 17 00:00:00 2001
From: Oleg Iarygin <oleg@arhadthedev.net>
Date: Tue, 24 Jan 2023 11:23:57 +0400
Subject: [PATCH 37/56] Slightly reword documentation

---
 Doc/library/mimetypes.rst | 46 ++++++++++++++++++++++++++++++++++-----
 Lib/mimetypes.py          |  1 +
 2 files changed, 42 insertions(+), 5 deletions(-)

diff --git a/Doc/library/mimetypes.rst b/Doc/library/mimetypes.rst
index a4a94b7c24aa46..5e0e023abd5315 100644
--- a/Doc/library/mimetypes.rst
+++ b/Doc/library/mimetypes.rst
@@ -280,7 +280,6 @@ Command-Line Usage
 ------------------
 
 The :mod:`mimetypes` module can be executed as a script from the command line.
-It is as simple as:
 
 .. code-block:: sh
 
@@ -290,18 +289,55 @@ The following options are accepted:
 
 .. program:: mimetypes
 
-.. cmdoption:: -h, --help
+.. cmdoption:: -h
+               --help
 
    Show the help message and exit.
 
-.. cmdoption:: -e, --extension
+.. cmdoption:: -e
+               --extension
 
    Guess extension instead of type.
 
-.. cmdoption:: -l, --lenient
+.. cmdoption:: -l
+               --lenient
 
-   Additionally search of some common, but non-standard types.
+   Additionally search for some common, but non-standard types.s
 
 The script scans the internal database and converts either file extensions to
 MIME types or vice versa depending on whether ``--extension`` option is
 specified.
+
+.. mimetypes-cli-example:
+
+Command-Line Example
+--------------------
+
+Here are some examples of typical usage of the :mod:`mimetypes` command
+line interface:
+
+.. code-block:: shell
+
+   # get a MIME type by a file name
+   $ python -m mimetypes filename.png
+   type: image/png encoding: None
+
+   # get a MIME type for a rare file format
+   $ python -m mimetypes filename.pict
+   I don't know anything about type filename.pict
+
+   # now look in the extended database built into Python
+   $ python -m mimetypes -l filename.pict
+   type: image/pict encoding: None
+
+   # get a file extension by a MIME type
+   $ python -m mimetypes -e text/javascript
+   .js
+
+   # get a file extension by a rare MIME type
+   $ python -m mimetypes -e text/xul
+   I don't know anything about type text/xul
+
+   # now look in the extended database again
+   $ python -m mimetypes -e -l text/xul
+   .xul
diff --git a/Lib/mimetypes.py b/Lib/mimetypes.py
index 06f4fbb795a807..b6e9543ece48b7 100644
--- a/Lib/mimetypes.py
+++ b/Lib/mimetypes.py
@@ -596,6 +596,7 @@ def _default_mime_types():
 
 
 def _main():
+    """Run the mimetypes command line interface."""
     from argparse import ArgumentParser
     parser = ArgumentParser(description='map filename extensions to MIME types')
     parser.add_argument(

From d58d5bac211f5825bc1df52e47accd91d01d0563 Mon Sep 17 00:00:00 2001
From: Oleg Iarygin <oleg@arhadthedev.net>
Date: Tue, 24 Jan 2023 11:27:59 +0400
Subject: [PATCH 38/56] Reword the news entry

---
 Misc/ACKS                                                     | 1 +
 .../Library/2022-05-28-19-41-02.gh-issue-93096.qjUyRG.rst     | 4 ++--
 2 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/Misc/ACKS b/Misc/ACKS
index 74abcebe21ea60..6e964850ff8b4f 100644
--- a/Misc/ACKS
+++ b/Misc/ACKS
@@ -814,6 +814,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
index 36d1a2cf0291e1..65c03441a59cca 100644
--- 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
@@ -1,3 +1,3 @@
-Command-line :mod:`mimetypes` now exits with ``1`` instead of ``0``
-on failure and ``2`` instead of ``1`` on incorrect command line parameters.
+Command-line :mod:`mimetypes` 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. Patch by Oleg Iarygin.

From 0cfe67ef5b634ab1f62052c112763b745e43b30b Mon Sep 17 00:00:00 2001
From: Oleg Iarygin <oleg@arhadthedev.net>
Date: Tue, 24 Jan 2023 11:37:55 +0400
Subject: [PATCH 39/56] Add more examples

---
 Doc/library/mimetypes.rst | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/Doc/library/mimetypes.rst b/Doc/library/mimetypes.rst
index 5e0e023abd5315..4904061d5ce133 100644
--- a/Doc/library/mimetypes.rst
+++ b/Doc/library/mimetypes.rst
@@ -308,6 +308,7 @@ The script scans the internal database and converts either file extensions to
 MIME types or vice versa depending on whether ``--extension`` option is
 specified.
 
+
 .. mimetypes-cli-example:
 
 Command-Line Example
@@ -322,6 +323,14 @@ line interface:
    $ python -m mimetypes filename.png
    type: image/png encoding: None
 
+   # get a MIME type by a URL
+   python -m mimetypes http://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 format
    $ python -m mimetypes filename.pict
    I don't know anything about type filename.pict

From d2797f062a93a36f8644f650eccc172e9a5f0c51 Mon Sep 17 00:00:00 2001
From: Oleg Iarygin <oleg@arhadthedev.net>
Date: Tue, 24 Jan 2023 11:56:43 +0400
Subject: [PATCH 40/56] Clarify multi-input usage

---
 Doc/library/mimetypes.rst | 19 ++++++++++++++++++-
 1 file changed, 18 insertions(+), 1 deletion(-)

diff --git a/Doc/library/mimetypes.rst b/Doc/library/mimetypes.rst
index 4904061d5ce133..b95e9b1cf5dda3 100644
--- a/Doc/library/mimetypes.rst
+++ b/Doc/library/mimetypes.rst
@@ -308,6 +308,11 @@ The script scans the internal database and converts either file extensions to
 MIME types or vice versa depending on whether ``--extension`` option is
 specified.
 
+The script processes input types in supplied order. For each input type, it
+writes a line into the standard output stream. For an unknown type, it writes
+an error message into a standard error stream end exits with return code
+``1``.
+
 
 .. mimetypes-cli-example:
 
@@ -331,7 +336,7 @@ line interface:
    python -m mimetypes filename.tar.gz
    type: application/x-tar encoding: gzip
 
-   # get a MIME type for a rare file format
+   # get a MIME type for a rare file extension
    $ python -m mimetypes filename.pict
    I don't know anything about type filename.pict
 
@@ -350,3 +355,15 @@ line interface:
    # now look in the extended database again
    $ python -m mimetypes -e -l 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
+   I don't know anything about type filename.xxx
+
+   # try to feed an unknown MIME type
+   $ python -m mimetypes -e audio/aac audio/opus audio/future audio/x-wav
+   .aac
+   .opus
+   I don't know anything about type audio/future

From fd590f548c4d05fd81aefabc6343a4e768a3513e Mon Sep 17 00:00:00 2001
From: Oleg Iarygin <oleg@arhadthedev.net>
Date: Tue, 24 Jan 2023 12:02:32 +0400
Subject: [PATCH 41/56] Further rewording of the notes

---
 Doc/library/mimetypes.rst | 14 ++++++--------
 1 file changed, 6 insertions(+), 8 deletions(-)

diff --git a/Doc/library/mimetypes.rst b/Doc/library/mimetypes.rst
index b95e9b1cf5dda3..a53bf09481566e 100644
--- a/Doc/library/mimetypes.rst
+++ b/Doc/library/mimetypes.rst
@@ -302,16 +302,14 @@ The following options are accepted:
 .. cmdoption:: -l
                --lenient
 
-   Additionally search for some common, but non-standard types.s
+   Additionally search for some common, but non-standard types.
 
-The script scans the internal database and converts either file extensions to
-MIME types or vice versa depending on whether ``--extension`` option is
-specified.
+The script scans the internal database and converts file extensions to
+MIME types if ``--extension`` option is specified, or vice versa if not.
 
-The script processes input types in supplied order. For each input type, it
-writes a line into the standard output stream. For an unknown type, it writes
-an error message into a standard error stream end exits with return code
-``1``.
+For each ``type`` entry, the script writes a line into the standard output
+stream. For an unknown type, it writes an error message into a standard error
+stream end exits with the return code ``1``.
 
 
 .. mimetypes-cli-example:

From 1ef41ddc480a7380ddb36b389311524ccb8fdb0d Mon Sep 17 00:00:00 2001
From: Oleg Iarygin <oleg@arhadthedev.net>
Date: Tue, 24 Jan 2023 12:26:27 +0400
Subject: [PATCH 42/56] Clarify data source

---
 Doc/library/mimetypes.rst | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/Doc/library/mimetypes.rst b/Doc/library/mimetypes.rst
index a53bf09481566e..3faf248ec3eab3 100644
--- a/Doc/library/mimetypes.rst
+++ b/Doc/library/mimetypes.rst
@@ -304,8 +304,8 @@ The following options are accepted:
 
    Additionally search for some common, but non-standard types.
 
-The script scans the internal database and converts file extensions to
-MIME types if ``--extension`` option is specified, or vice versa if not.
+The script converts file extensions to MIME types if ``--extension`` option
+is specified, or vice versa if not.
 
 For each ``type`` entry, the script writes a line into the standard output
 stream. For an unknown type, it writes an error message into a standard error

From 2797fc4ee924452cb990cd6439b1c22ba4a4a3c4 Mon Sep 17 00:00:00 2001
From: Oleg Iarygin <oleg@arhadthedev.net>
Date: Tue, 24 Jan 2023 12:32:23 +0400
Subject: [PATCH 43/56] Remove formatting-breaking "don't" from error messages

---
 Doc/library/mimetypes.rst                                 | 8 ++++----
 Lib/mimetypes.py                                          | 4 ++--
 .../Library/2022-05-28-19-41-02.gh-issue-93096.qjUyRG.rst | 3 ++-
 3 files changed, 8 insertions(+), 7 deletions(-)

diff --git a/Doc/library/mimetypes.rst b/Doc/library/mimetypes.rst
index 3faf248ec3eab3..02e1afc89c6bfc 100644
--- a/Doc/library/mimetypes.rst
+++ b/Doc/library/mimetypes.rst
@@ -336,7 +336,7 @@ line interface:
 
    # get a MIME type for a rare file extension
    $ python -m mimetypes filename.pict
-   I don't know anything about type filename.pict
+   error: unknown extension filename.pict
 
    # now look in the extended database built into Python
    $ python -m mimetypes -l filename.pict
@@ -348,7 +348,7 @@ line interface:
 
    # get a file extension by a rare MIME type
    $ python -m mimetypes -e text/xul
-   I don't know anything about type text/xul
+   error: unknown type text/xul
 
    # now look in the extended database again
    $ python -m mimetypes -e -l text/xul
@@ -358,10 +358,10 @@ line interface:
    $ python -m mimetypes filename.sh filename.nc filename.xxx filename.txt
    type: application/x-sh encoding: None
    type: application/x-netcdf encoding: None
-   I don't know anything about type filename.xxx
+   error: unknown extension filename.xxx
 
    # try to feed an unknown MIME type
    $ python -m mimetypes -e audio/aac audio/opus audio/future audio/x-wav
    .aac
    .opus
-   I don't know anything about type audio/future
+   error: unknown type audio/future
diff --git a/Lib/mimetypes.py b/Lib/mimetypes.py
index b6e9543ece48b7..a563b18053b4e0 100644
--- a/Lib/mimetypes.py
+++ b/Lib/mimetypes.py
@@ -618,14 +618,14 @@ def _main():
             if guess:
                 print(guess)
             else:
-                sys.exit(f"I don't know anything about type {gtype}")
+                sys.exit(f"error: unknown type {gtype}")
     else:
         for gtype in arguments.type:
             guess, encoding = guess_type(gtype, not arguments.lenient)
             if guess:
                 print('type:', guess, 'encoding:', encoding)
             else:
-                sys.exit(f"I don't know anything about type {gtype}")
+                sys.exit(f"error: unknown extension {gtype}")
 
 
 if __name__ == '__main__':
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
index 65c03441a59cca..44797ce6e015b7 100644
--- 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
@@ -1,3 +1,4 @@
 Command-line :mod:`mimetypes` 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. Patch by Oleg Iarygin.
+Also, errors are printed to stderr instead of stdout and their text is made
+tighter. Patch by Oleg Iarygin.

From 78c0c5051c952e7a2e817c8059e4196d53c84f96 Mon Sep 17 00:00:00 2001
From: Oleg Iarygin <oleg@arhadthedev.net>
Date: Tue, 24 Jan 2023 12:44:17 +0400
Subject: [PATCH 44/56] Fix a grammar mistake

---
 Doc/library/mimetypes.rst | 4 ++--
 Lib/mimetypes.py          | 2 +-
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/Doc/library/mimetypes.rst b/Doc/library/mimetypes.rst
index 02e1afc89c6bfc..a2df23b0de8b72 100644
--- a/Doc/library/mimetypes.rst
+++ b/Doc/library/mimetypes.rst
@@ -336,7 +336,7 @@ line interface:
 
    # get a MIME type for a rare file extension
    $ python -m mimetypes filename.pict
-   error: unknown extension filename.pict
+   error: unknown extension of filename.pict
 
    # now look in the extended database built into Python
    $ python -m mimetypes -l filename.pict
@@ -358,7 +358,7 @@ line interface:
    $ 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 filename.xxx
+   error: unknown extension of filename.xxx
 
    # try to feed an unknown MIME type
    $ python -m mimetypes -e audio/aac audio/opus audio/future audio/x-wav
diff --git a/Lib/mimetypes.py b/Lib/mimetypes.py
index a563b18053b4e0..2bbd0084d1db7b 100644
--- a/Lib/mimetypes.py
+++ b/Lib/mimetypes.py
@@ -625,7 +625,7 @@ def _main():
             if guess:
                 print('type:', guess, 'encoding:', encoding)
             else:
-                sys.exit(f"error: unknown extension {gtype}")
+                sys.exit(f"error: unknown extension of {gtype}")
 
 
 if __name__ == '__main__':

From 1afb6d6b63355e57cfcc86c7620b847a637c716b Mon Sep 17 00:00:00 2001
From: Oleg Iarygin <oleg@arhadthedev.net>
Date: Tue, 24 Jan 2023 12:57:51 +0400
Subject: [PATCH 45/56] Make wording tighter

---
 Doc/library/mimetypes.rst | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/Doc/library/mimetypes.rst b/Doc/library/mimetypes.rst
index a2df23b0de8b72..29c5349c99bd7e 100644
--- a/Doc/library/mimetypes.rst
+++ b/Doc/library/mimetypes.rst
@@ -308,8 +308,8 @@ The script converts file extensions to MIME types if ``--extension`` option
 is specified, or vice versa if not.
 
 For each ``type`` entry, the script writes a line into the standard output
-stream. For an unknown type, it writes an error message into a standard error
-stream end exits with the return code ``1``.
+stream. If an unknown type occurs, it writes an error message into the
+standard error stream and aborts with the return code ``1``.
 
 
 .. mimetypes-cli-example:

From a22d630bcc59c327c0179c65771097119c871980 Mon Sep 17 00:00:00 2001
From: Oleg Iarygin <oleg@arhadthedev.net>
Date: Tue, 24 Jan 2023 13:37:01 +0400
Subject: [PATCH 46/56] Fix tests

---
 Lib/test/test_mimetypes.py | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/Lib/test/test_mimetypes.py b/Lib/test/test_mimetypes.py
index 01d6932ed71126..cd28634051bd4f 100644
--- a/Lib/test/test_mimetypes.py
+++ b/Lib/test/test_mimetypes.py
@@ -287,7 +287,6 @@ def test__all__(self):
 
 class MimetypesCliTestCase(unittest.TestCase):
 
-    @classmethod
     def mimetypes_cmd(cls, *args, **kwargs):
         result, _ = run_python_until_end('-m', 'mimetypes', *args)
         return result.rc, result.out.decode(), result.err.decode()
@@ -313,7 +312,7 @@ def test_guess_extension(self):
         retcode, out, err = self.mimetypes_cmd('-e', 'image/jpg')
         self.assertEqual(retcode, 1)
         self.assertEqual(out, '')
-        self.assertEqual(err, f"I don't know anything about type image/jpg{linesep}")
+        self.assertEqual(err, f'error: unknown type image/jpg{linesep}')
 
         retcode, out, err = self.mimetypes_cmd('-e', 'image/jpeg')
         self.assertEqual(retcode, 0)
@@ -334,7 +333,7 @@ def test_guess_type_conflicting_with_mimetypes(self):
         retcode, out, err = self.mimetypes_cmd('foo.webp')
         self.assertEqual(retcode, 1)
         self.assertEqual(out, '')
-        self.assertEqual(err, f"I don't know anything about type foo.webp{linesep}")
+        self.assertEqual(err, f'error: unknown extension of foo.webp{linesep}')
 
 if __name__ == "__main__":
     unittest.main()

From b9d530948fe0b105d8cec5e701651a9573236fa8 Mon Sep 17 00:00:00 2001
From: Oleg Iarygin <oleg@arhadthedev.net>
Date: Tue, 24 Jan 2023 14:13:04 +0400
Subject: [PATCH 47/56] Remove the command line input prefix

---
 Doc/library/mimetypes.rst | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/Doc/library/mimetypes.rst b/Doc/library/mimetypes.rst
index 29c5349c99bd7e..6f87bbf267ab81 100644
--- a/Doc/library/mimetypes.rst
+++ b/Doc/library/mimetypes.rst
@@ -323,7 +323,7 @@ line interface:
 .. code-block:: shell
 
    # get a MIME type by a file name
-   $ python -m mimetypes filename.png
+   python -m mimetypes filename.png
    type: image/png encoding: None
 
    # get a MIME type by a URL
@@ -335,33 +335,33 @@ line interface:
    type: application/x-tar encoding: gzip
 
    # get a MIME type for a rare file extension
-   $ python -m mimetypes filename.pict
+   python -m mimetypes filename.pict
    error: unknown extension of filename.pict
 
    # now look in the extended database built into Python
-   $ python -m mimetypes -l filename.pict
+   python -m mimetypes -l filename.pict
    type: image/pict encoding: None
 
    # get a file extension by a MIME type
-   $ python -m mimetypes -e text/javascript
+   python -m mimetypes -e text/javascript
    .js
 
    # get a file extension by a rare MIME type
-   $ python -m mimetypes -e text/xul
+   python -m mimetypes -e text/xul
    error: unknown type text/xul
 
    # now look in the extended database again
-   $ python -m mimetypes -e -l text/xul
+   python -m mimetypes -e -l text/xul
    .xul
 
    # try to feed an unknown file extension
-   $ python -m mimetypes filename.sh filename.nc filename.xxx filename.txt
+   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 -e audio/aac audio/opus audio/future audio/x-wav
+   python -m mimetypes -e audio/aac audio/opus audio/future audio/x-wav
    .aac
    .opus
    error: unknown type audio/future

From a9a43f70b518decbf86da7602bb5de5108d0da2c Mon Sep 17 00:00:00 2001
From: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com>
Date: Fri, 7 Mar 2025 15:22:38 +0200
Subject: [PATCH 48/56] Fix tests

---
 Lib/test/test_mimetypes.py | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/Lib/test/test_mimetypes.py b/Lib/test/test_mimetypes.py
index 34856688272f65..5facab6fcbefaf 100644
--- a/Lib/test/test_mimetypes.py
+++ b/Lib/test/test_mimetypes.py
@@ -399,14 +399,14 @@ def mimetypes_cmd(cls, *args, **kwargs):
     def test_help_option(self):
         retcode, out, err = self.mimetypes_cmd('-h')
         self.assertEqual(retcode, 0)
-        self.assertIn('usage: mimetypes.py', out)
+        self.assertStartsWith(out, 'usage: ')
         self.assertEqual(err, '')
 
     def test_invalid_option(self):
         retcode, out, err = self.mimetypes_cmd('--invalid')
         self.assertEqual(retcode, 2)
         self.assertEqual(out, '')
-        self.assertIn('usage: mimetypes.py', err)
+        self.assertStartsWith(err, 'usage: ')
 
     def test_guess_extension(self):
         retcode, out, err = self.mimetypes_cmd('-l', '-e', 'image/jpg')

From 85727bf473865b4a107c96c935aabdcbebe949e2 Mon Sep 17 00:00:00 2001
From: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com>
Date: Fri, 7 Mar 2025 18:25:13 +0200
Subject: [PATCH 49/56] Fix test

---
 Lib/test/test_mimetypes.py | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/Lib/test/test_mimetypes.py b/Lib/test/test_mimetypes.py
index 5facab6fcbefaf..3eee13979f28d4 100644
--- a/Lib/test/test_mimetypes.py
+++ b/Lib/test/test_mimetypes.py
@@ -435,10 +435,10 @@ def test_guess_type(self):
         '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.webp')
+        retcode, out, err = self.mimetypes_cmd('foo.pic')
         self.assertEqual(retcode, 1)
         self.assertEqual(out, '')
-        self.assertEqual(err, f'error: unknown extension of foo.webp{linesep}')
+        self.assertEqual(err, f'error: unknown extension of foo.pic{linesep}')
 
 if __name__ == "__main__":
     unittest.main()

From f1535fd18342e26a1be9bb7cfcc358b8b1507a43 Mon Sep 17 00:00:00 2001
From: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com>
Date: Fri, 7 Mar 2025 19:09:55 +0200
Subject: [PATCH 50/56] Use console formatting for commands with output

---
 Doc/library/mimetypes.rst | 42 +++++++++++++++++++--------------------
 1 file changed, 21 insertions(+), 21 deletions(-)

diff --git a/Doc/library/mimetypes.rst b/Doc/library/mimetypes.rst
index 248bdcd3fc44fb..f20183f6ecbfcd 100644
--- a/Doc/library/mimetypes.rst
+++ b/Doc/library/mimetypes.rst
@@ -355,48 +355,48 @@ Command-Line Example
 Here are some examples of typical usage of the :mod:`mimetypes` command
 line interface:
 
-.. code-block:: shell
+.. code-block:: console
 
-   # get a MIME type by a file name
-   python -m mimetypes filename.png
+   $ # 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 http://example.com/filename.txt
+   $ # get a MIME type by a URL
+   $ python -m mimetypes http://example.com/filename.txt
    type: text/plain encoding: None
 
-   # get a complex MIME type
-   python -m mimetypes filename.tar.gz
+   $ # 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
+   $ # 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 -l filename.pict
+   $ # now look in the extended database built into Python
+   $ python -m mimetypes -l filename.pict
    type: image/pict encoding: None
 
-   # get a file extension by a MIME type
-   python -m mimetypes -e text/javascript
+   $ # get a file extension by a MIME type
+   $ python -m mimetypes -e text/javascript
    .js
 
-   # get a file extension by a rare MIME type
-   python -m mimetypes -e text/xul
+   $ # get a file extension by a rare MIME type
+   $ python -m mimetypes -e text/xul
    error: unknown type text/xul
 
-   # now look in the extended database again
-   python -m mimetypes -e -l text/xul
+   $ # now look in the extended database again
+   $ python -m mimetypes -e -l text/xul
    .xul
 
-   # try to feed an unknown file extension
-   python -m mimetypes filename.sh filename.nc filename.xxx filename.txt
+   $ # 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 -e audio/aac audio/opus audio/future audio/x-wav
+   $ # try to feed an unknown MIME type
+   $ python -m mimetypes -e audio/aac audio/opus audio/future audio/x-wav
    .aac
    .opus
    error: unknown type audio/future

From 8509c06cc16f577ca01277d790afb8944994efc0 Mon Sep 17 00:00:00 2001
From: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com>
Date: Sat, 8 Mar 2025 17:05:46 +0200
Subject: [PATCH 51/56] Docs: default case first, put condition first, avoid
 Latin, adjust wording

---
 Doc/library/mimetypes.rst | 15 ++++++++-------
 1 file changed, 8 insertions(+), 7 deletions(-)

diff --git a/Doc/library/mimetypes.rst b/Doc/library/mimetypes.rst
index f20183f6ecbfcd..467b478e00612e 100644
--- a/Doc/library/mimetypes.rst
+++ b/Doc/library/mimetypes.rst
@@ -314,11 +314,11 @@ than one MIME-type database; it provides an interface similar to the one of the
 Command-Line Usage
 ------------------
 
-The :mod:`mimetypes` module can be executed as a script from the command line.
+The :mod:`!mimetypes` module can be executed as a script from the command line.
 
 .. code-block:: sh
 
-   python -m mimetypes [-e] [-l] type [type ...]
+   python -m mimetypes [-h] [-e] [-l] type [type ...]
 
 The following options are accepted:
 
@@ -339,12 +339,13 @@ The following options are accepted:
 
    Additionally search for some common, but non-standard types.
 
-The script converts file extensions to MIME types if ``--extension`` option
-is specified, or vice versa if not.
+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 aborts with the return code ``1``.
+standard error stream and exits with the return code ``1``.
 
 
 .. mimetypes-cli-example:
@@ -352,8 +353,8 @@ standard error stream and aborts with the return code ``1``.
 Command-Line Example
 --------------------
 
-Here are some examples of typical usage of the :mod:`mimetypes` command
-line interface:
+Here are some examples of typical usage of the :mod:`!mimetypes` command-line
+interface:
 
 .. code-block:: console
 

From 9ad283c62033c84eef564345af44af1d611a0fcf Mon Sep 17 00:00:00 2001
From: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com>
Date: Sat, 8 Mar 2025 17:19:25 +0200
Subject: [PATCH 52/56] Use long options in examples so no need to refer back
 to usage

---
 Doc/library/mimetypes.rst | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/Doc/library/mimetypes.rst b/Doc/library/mimetypes.rst
index 467b478e00612e..2e5eca83f91abe 100644
--- a/Doc/library/mimetypes.rst
+++ b/Doc/library/mimetypes.rst
@@ -363,7 +363,7 @@ interface:
    type: image/png encoding: None
 
    $ # get a MIME type by a URL
-   $ python -m mimetypes http://example.com/filename.txt
+   $ python -m mimetypes https://example.com/filename.txt
    type: text/plain encoding: None
 
    $ # get a complex MIME type
@@ -375,19 +375,19 @@ interface:
    error: unknown extension of filename.pict
 
    $ # now look in the extended database built into Python
-   $ python -m mimetypes -l filename.pict
+   $ python -m mimetypes --lenient filename.pict
    type: image/pict encoding: None
 
    $ # get a file extension by a MIME type
-   $ python -m mimetypes -e text/javascript
+   $ python -m mimetypes --extension text/javascript
    .js
 
    $ # get a file extension by a rare MIME type
-   $ python -m mimetypes -e text/xul
+   $ python -m mimetypes --extension text/xul
    error: unknown type text/xul
 
    $ # now look in the extended database again
-   $ python -m mimetypes -e -l text/xul
+   $ python -m mimetypes --extension --lenient text/xul
    .xul
 
    $ # try to feed an unknown file extension
@@ -397,7 +397,7 @@ interface:
    error: unknown extension of filename.xxx
 
    $ # try to feed an unknown MIME type
-   $ python -m mimetypes -e audio/aac audio/opus audio/future audio/x-wav
+   $ python -m mimetypes --extension audio/aac audio/opus audio/future audio/x-wav
    .aac
    .opus
    error: unknown type audio/future

From a2c0d53c099b7913c7c25cddbcd6fe572f1090d7 Mon Sep 17 00:00:00 2001
From: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com>
Date: Sat, 8 Mar 2025 17:29:28 +0200
Subject: [PATCH 53/56] Follow argparse docs and use 'args'

---
 Lib/mimetypes.py | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/Lib/mimetypes.py b/Lib/mimetypes.py
index 54795ff7ab05ea..e0ec00a57ec5ce 100644
--- a/Lib/mimetypes.py
+++ b/Lib/mimetypes.py
@@ -686,18 +686,18 @@ def _main():
         help='additionally search for common but non-standard types'
     )
     parser.add_argument('type', nargs='+', help='a type to search')
-    arguments = parser.parse_args()
+    args = parser.parse_args()
 
-    if arguments.extension:
-        for gtype in arguments.type:
-            guess = guess_extension(gtype, not arguments.lenient)
+    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 arguments.type:
-            guess, encoding = guess_type(gtype, not arguments.lenient)
+        for gtype in args.type:
+            guess, encoding = guess_type(gtype, not args.lenient)
             if guess:
                 print('type:', guess, 'encoding:', encoding)
             else:

From 34e05912c2c10c3b7e78ecfa918965158197dcde Mon Sep 17 00:00:00 2001
From: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com>
Date: Sat, 8 Mar 2025 22:39:14 +0200
Subject: [PATCH 54/56] Add to What's New, combine NEWS files, update
 reference, use sentence case

https://devguide.python.org/documentation/style-guide/\#capitalization
---
 Doc/library/cmdline.rst                                   | 2 +-
 Doc/library/mimetypes.rst                                 | 8 ++++----
 Doc/whatsnew/3.14.rst                                     | 7 +++++++
 .../2022-05-23-11-53-24.gh-issue-93096.TIuIhx.rst         | 1 -
 .../Library/2022-05-28-19-41-02.gh-issue-93096.qjUyRG.rst | 7 ++++---
 5 files changed, 16 insertions(+), 9 deletions(-)
 delete mode 100644 Misc/NEWS.d/next/Documentation/2022-05-23-11-53-24.gh-issue-93096.TIuIhx.rst

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 <inspect-module-cli>`
 * :ref:`json <json-commandline>`
-* :mod:`mimetypes`
+* :ref:`mimetypes <mimetypes-cli>`
 * :mod:`pdb`
 * :mod:`pickle`
 * :ref:`pickletools <pickletools-cli>`
diff --git a/Doc/library/mimetypes.rst b/Doc/library/mimetypes.rst
index 2e5eca83f91abe..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
@@ -309,9 +309,9 @@ than one MIME-type database; it provides an interface similar to the one of the
       official MIME types, otherwise to the non-standard ones.
 
 
-.. mimetypes-cli:
+.. _mimetypes-cli:
 
-Command-Line Usage
+Command-line usage
 ------------------
 
 The :mod:`!mimetypes` module can be executed as a script from the command line.
@@ -350,7 +350,7 @@ standard error stream and exits with the return code ``1``.
 
 .. mimetypes-cli-example:
 
-Command-Line Example
+Command-line example
 --------------------
 
 Here are some examples of typical usage of the :mod:`!mimetypes` command-line
diff --git a/Doc/whatsnew/3.14.rst b/Doc/whatsnew/3.14.rst
index 2402fb23c86b85..2129b3cbd4841a 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/Misc/NEWS.d/next/Documentation/2022-05-23-11-53-24.gh-issue-93096.TIuIhx.rst b/Misc/NEWS.d/next/Documentation/2022-05-23-11-53-24.gh-issue-93096.TIuIhx.rst
deleted file mode 100644
index 08c37c8a77046b..00000000000000
--- a/Misc/NEWS.d/next/Documentation/2022-05-23-11-53-24.gh-issue-93096.TIuIhx.rst
+++ /dev/null
@@ -1 +0,0 @@
-Added *Command-Line Usage* section for :mod:`mimetypes`. Patch by Oleg Iarygin.
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
index 44797ce6e015b7..fb9ca441c7e2da 100644
--- 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
@@ -1,4 +1,5 @@
-Command-line :mod:`mimetypes` now exits with ``1`` on failure instead of ``0``
-and ``2`` on incorrect command line parameters instead of ``1``.
+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.
+tighter. Patch by Oleg Iarygin and Hugo van Kemenade.

From 80e1734a63f6209c004e0938b0c05356d9836add Mon Sep 17 00:00:00 2001
From: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com>
Date: Sat, 8 Mar 2025 23:05:12 +0200
Subject: [PATCH 55/56] Hyphen

---
 Lib/mimetypes.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Lib/mimetypes.py b/Lib/mimetypes.py
index e0ec00a57ec5ce..619c46d24de735 100644
--- a/Lib/mimetypes.py
+++ b/Lib/mimetypes.py
@@ -670,7 +670,7 @@ def _default_mime_types():
 
 
 def _main():
-    """Run the mimetypes command line interface."""
+    """Run the mimetypes command-line interface."""
     import sys
     from argparse import ArgumentParser
 

From 7cb62c5159294a44e90b2a27d24abf182ec02493 Mon Sep 17 00:00:00 2001
From: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com>
Date: Tue, 11 Mar 2025 00:31:42 +0200
Subject: [PATCH 56/56] Update error message

---
 Lib/mimetypes.py           | 2 +-
 Lib/test/test_mimetypes.py | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/Lib/mimetypes.py b/Lib/mimetypes.py
index 619c46d24de735..6b94fe3c4df756 100644
--- a/Lib/mimetypes.py
+++ b/Lib/mimetypes.py
@@ -701,7 +701,7 @@ def _main():
             if guess:
                 print('type:', guess, 'encoding:', encoding)
             else:
-                sys.exit(f"error: unknown extension of {gtype}")
+                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 3eee13979f28d4..b5d1f50099e16a 100644
--- a/Lib/test/test_mimetypes.py
+++ b/Lib/test/test_mimetypes.py
@@ -438,7 +438,7 @@ 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: unknown extension of foo.pic{linesep}')
+        self.assertEqual(err, f'error: media type unknown for foo.pic{linesep}')
 
 if __name__ == "__main__":
     unittest.main()