]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-130645: Add color to stdlib argparse CLIs (gh-133380)
authorHugo van Kemenade <1324225+hugovk@users.noreply.github.com>
Mon, 5 May 2025 17:46:46 +0000 (20:46 +0300)
committerGitHub <noreply@github.com>
Mon, 5 May 2025 17:46:46 +0000 (19:46 +0200)
36 files changed:
Lib/ast.py
Lib/calendar.py
Lib/code.py
Lib/compileall.py
Lib/dis.py
Lib/doctest.py
Lib/ensurepip/__init__.py
Lib/gzip.py
Lib/http/server.py
Lib/inspect.py
Lib/json/tool.py
Lib/mimetypes.py
Lib/pdb.py
Lib/pickle.py
Lib/pickletools.py
Lib/platform.py
Lib/py_compile.py
Lib/random.py
Lib/sqlite3/__main__.py
Lib/tarfile.py
Lib/test/test_ast/test_ast.py
Lib/test/test_calendar.py
Lib/test/test_mimetypes.py
Lib/test/test_pickle.py
Lib/test/test_platform.py
Lib/test/test_random.py
Lib/test/test_sqlite3/test_cli.py
Lib/tokenize.py
Lib/trace.py
Lib/unittest/main.py
Lib/uuid.py
Lib/venv/__init__.py
Lib/webbrowser.py
Lib/zipapp.py
Lib/zipfile/__init__.py
Misc/NEWS.d/next/Library/2025-05-04-16-00-01.gh-issue-130645.yNwKue.rst [new file with mode: 0644]

index be6ed0805d63ddbbd158c1bdb16133c2a0a455a8..b9791bf52d3e08a20060ea7022f5da9641a19fb9 100644 (file)
@@ -630,7 +630,7 @@ def main(args=None):
     import argparse
     import sys
 
-    parser = argparse.ArgumentParser()
+    parser = argparse.ArgumentParser(color=True)
     parser.add_argument('infile', nargs='?', default='-',
                         help='the file to parse; defaults to stdin')
     parser.add_argument('-m', '--mode', default='exec',
index 01a76ff8e78c45ad7a64ddf254f1cac30558ab43..18f76d52ff858199f606a35273b47606d5f3937d 100644 (file)
@@ -810,7 +810,7 @@ def timegm(tuple):
 
 def main(args=None):
     import argparse
-    parser = argparse.ArgumentParser()
+    parser = argparse.ArgumentParser(color=True)
     textgroup = parser.add_argument_group('text only arguments')
     htmlgroup = parser.add_argument_group('html only arguments')
     textgroup.add_argument(
index 41331dfd071f1103931c7155baeb11219470b403..b134886dc267fbd2f242c4ccdb68fc497b63164d 100644 (file)
@@ -385,7 +385,7 @@ def interact(banner=None, readfunc=None, local=None, exitmsg=None, local_exit=Fa
 if __name__ == "__main__":
     import argparse
 
-    parser = argparse.ArgumentParser()
+    parser = argparse.ArgumentParser(color=True)
     parser.add_argument('-q', action='store_true',
                        help="don't print version and copyright messages")
     args = parser.parse_args()
index 47e2446356e7d7dd73c163ef6f28d660545ac6c4..67fe370451e1efbaf97f2972d54bb316914ef842 100644 (file)
@@ -317,7 +317,9 @@ def main():
     import argparse
 
     parser = argparse.ArgumentParser(
-        description='Utilities to support installing Python libraries.')
+        description='Utilities to support installing Python libraries.',
+        color=True,
+    )
     parser.add_argument('-l', action='store_const', const=0,
                         default=None, dest='maxlevels',
                         help="don't recurse into subdirectories")
index cb6d077a391677cfc1e53fc8ca82ecff7cb8835d..d6d2c1386dd7858db7aa00becfc690e7d38146da 100644 (file)
@@ -1131,7 +1131,7 @@ class Bytecode:
 def main(args=None):
     import argparse
 
-    parser = argparse.ArgumentParser()
+    parser = argparse.ArgumentParser(color=True)
     parser.add_argument('-C', '--show-caches', action='store_true',
                         help='show inline caches')
     parser.add_argument('-O', '--show-offsets', action='store_true',
index e02e73ed722f7ec29b2487b15da95aa49bb96576..2acb6cb79f394d336f0220447c0cfe3578608b22 100644 (file)
@@ -2870,7 +2870,7 @@ __test__ = {"_TestClass": _TestClass,
 def _test():
     import argparse
 
-    parser = argparse.ArgumentParser(description="doctest runner")
+    parser = argparse.ArgumentParser(description="doctest runner", color=True)
     parser.add_argument('-v', '--verbose', action='store_true', default=False,
                         help='print very verbose output for all tests')
     parser.add_argument('-o', '--option', action='append',
index 6fc9f39b24cb9cbb1357297cdc9c05e905ae3363..aa641e94a8b33648d260cbd5ae8087a112b7a6fc 100644 (file)
@@ -205,7 +205,7 @@ def _uninstall_helper(*, verbosity=0):
 
 def _main(argv=None):
     import argparse
-    parser = argparse.ArgumentParser()
+    parser = argparse.ArgumentParser(color=True)
     parser.add_argument(
         "--version",
         action="version",
index b7375b2547314f07b72275e8cecec68b07708a3c..c00f51858de0f0d5f04d6b54641cc4147e81a165 100644 (file)
@@ -667,7 +667,9 @@ def main():
     from argparse import ArgumentParser
     parser = ArgumentParser(description=
         "A simple command line interface for the gzip module: act like gzip, "
-        "but do not delete the input file.")
+        "but do not delete the input file.",
+        color=True,
+    )
     group = parser.add_mutually_exclusive_group()
     group.add_argument('--fast', action='store_true', help='compress faster')
     group.add_argument('--best', action='store_true', help='compress better')
index a2aad4c9be3c51bcf71e543df38442da8e43cca5..64f766f9bc2c1b496b3b2545ada9acdf2b89499f 100644 (file)
@@ -1340,7 +1340,7 @@ if __name__ == '__main__':
     import argparse
     import contextlib
 
-    parser = argparse.ArgumentParser()
+    parser = argparse.ArgumentParser(color=True)
     parser.add_argument('--cgi', action='store_true',
                         help='run as CGI server')
     parser.add_argument('-b', '--bind', metavar='ADDRESS',
index 9592559ba6dcaa96d82c43842422183f1eb89938..52c9bb05b31f372777ac82de9f05c2fa2a17cb25 100644 (file)
@@ -3343,7 +3343,7 @@ def _main():
     import argparse
     import importlib
 
-    parser = argparse.ArgumentParser()
+    parser = argparse.ArgumentParser(color=True)
     parser.add_argument(
         'object',
          help="The object to be analysed. "
index 585583da8604ac242dbee99ff5f25b538d3d0608..de186368545329ab93de109d45c345d73218f117 100644 (file)
@@ -44,7 +44,7 @@ def _colorize_json(json_str):
 def main():
     description = ('A simple command line interface for json module '
                    'to validate and pretty-print JSON objects.')
-    parser = argparse.ArgumentParser(description=description)
+    parser = argparse.ArgumentParser(description=description, color=True)
     parser.add_argument('infile', nargs='?',
                         help='a JSON file to be validated or pretty-printed',
                         default='-')
index b5a1b8da2638e07f64c14730e5059f209c79ecda..33e86d51a0fe508dab237f425f0ea64557e902c8 100644 (file)
@@ -698,7 +698,9 @@ _default_mime_types()
 def _parse_args(args):
     from argparse import ArgumentParser
 
-    parser = ArgumentParser(description='map filename extensions to MIME types')
+    parser = ArgumentParser(
+        description='map filename extensions to MIME types', color=True
+    )
     parser.add_argument(
         '-e', '--extension',
         action='store_true',
index 195bfa557ef1e47be795625d010395bc7e1ddc2a..b30df59d793f244973b5a560f8a6db7d91b26a9a 100644 (file)
@@ -3296,10 +3296,13 @@ To let the script run up to a given line X in the debugged file, use
 def main():
     import argparse
 
-    parser = argparse.ArgumentParser(usage="%(prog)s [-h] [-c command] (-m module | -p pid | pyfile) [args ...]",
-                                     description=_usage,
-                                     formatter_class=argparse.RawDescriptionHelpFormatter,
-                                     allow_abbrev=False)
+    parser = argparse.ArgumentParser(
+        usage="%(prog)s [-h] [-c command] (-m module | -p pid | pyfile) [args ...]",
+        description=_usage,
+        formatter_class=argparse.RawDescriptionHelpFormatter,
+        allow_abbrev=False,
+        color=True,
+    )
 
     # We need to maunally get the script from args, because the first positional
     # arguments could be either the script we need to debug, or the argument
index 4fa3632d1a738f26a1b61340cb85878a9975b881..beaefae0479d3ca15347f6b1393b57e19c01b2ef 100644 (file)
@@ -1911,7 +1911,9 @@ def _main(args=None):
     import argparse
     import pprint
     parser = argparse.ArgumentParser(
-        description='display contents of the pickle files')
+        description='display contents of the pickle files',
+        color=True,
+    )
     parser.add_argument(
         'pickle_file',
         nargs='+', help='the pickle file')
index 53f25ea4e46b4d3a03b0fc476fac12d92d673a6f..bcddfb722bd26dedec001455ff8c7a0f087b6db9 100644 (file)
@@ -2842,7 +2842,9 @@ __test__ = {'disassembler_test': _dis_test,
 if __name__ == "__main__":
     import argparse
     parser = argparse.ArgumentParser(
-        description='disassemble one or more pickle files')
+        description='disassemble one or more pickle files',
+        color=True,
+    )
     parser.add_argument(
         'pickle_file',
         nargs='+', help='the pickle file')
index 507552f360ba595e9365246322483ea55e5ee3cd..55e211212d42097e863337bdf204bc8b6f98ad31 100644 (file)
@@ -1467,7 +1467,7 @@ def invalidate_caches():
 def _parse_args(args: list[str] | None):
     import argparse
 
-    parser = argparse.ArgumentParser()
+    parser = argparse.ArgumentParser(color=True)
     parser.add_argument("args", nargs="*", choices=["nonaliased", "terse"])
     parser.add_argument(
         "--terse",
index 388614e51b1847cbd81400d9ce48dd734e050e14..43d8ec90ffb6b1d3f5456dd3bbfe37f3f800a20a 100644 (file)
@@ -177,7 +177,7 @@ def main():
     import argparse
 
     description = 'A simple command-line interface for py_compile module.'
-    parser = argparse.ArgumentParser(description=description)
+    parser = argparse.ArgumentParser(description=description, color=True)
     parser.add_argument(
         '-q', '--quiet',
         action='store_true',
index 5e5d0c4c694a1ced241f99afb06b3dfd625675d6..86d562f0b8aaf60eece0f1c1c8e240cd499b049e 100644 (file)
@@ -1011,7 +1011,7 @@ if hasattr(_os, "fork"):
 def _parse_args(arg_list: list[str] | None):
     import argparse
     parser = argparse.ArgumentParser(
-        formatter_class=argparse.RawTextHelpFormatter)
+        formatter_class=argparse.RawTextHelpFormatter, color=True)
     group = parser.add_mutually_exclusive_group()
     group.add_argument(
         "-c", "--choice", nargs="+",
index 79a6209468dae4efcadf162ec6581b353bd6bba1..002f1986cddb89b9b56e017053a8c3a1d5135244 100644 (file)
@@ -65,6 +65,7 @@ class SqliteInteractiveConsole(InteractiveConsole):
 def main(*args):
     parser = ArgumentParser(
         description="Python sqlite3 CLI",
+        color=True,
     )
     parser.add_argument(
         "filename", type=str, default=":memory:", nargs="?",
index 82c5f6704cbd24f4c814932f8cc6c01591df738d..28581f3e7a2692dd5d8fbfe7e0116312565bde0b 100644 (file)
@@ -2883,7 +2883,7 @@ def main():
     import argparse
 
     description = 'A simple command-line interface for tarfile module.'
-    parser = argparse.ArgumentParser(description=description)
+    parser = argparse.ArgumentParser(description=description, color=True)
     parser.add_argument('-v', '--verbose', action='store_true', default=False,
                         help='Verbose output')
     parser.add_argument('--filter', metavar='<filtername>',
index ae82395e9a005a89ed0cfc994a414a14a135e3d5..530b5ec428eaa8466936e3071740eba2369737fb 100644 (file)
@@ -3289,6 +3289,7 @@ class CommandLineTests(unittest.TestCase):
                     with self.subTest(flags=args):
                         self.invoke_ast(*args)
 
+    @support.force_not_colorized
     def test_help_message(self):
         for flag in ('-h', '--help', '--unknown'):
             with self.subTest(flag=flag):
index 073df310bb49ebdddb5d894da41db876b31c3749..cbfee604b7a8b595876eecdf2e7d7d6beca9cc08 100644 (file)
@@ -987,6 +987,7 @@ class CommandLineTestCase(unittest.TestCase):
         self.assertCLIFails(*args)
         self.assertCmdFails(*args)
 
+    @support.force_not_colorized
     def test_help(self):
         stdout = self.run_cmd_ok('-h')
         self.assertIn(b'usage:', stdout)
index dad5dbde7cd7831ccb1c96cd6ce14b38ee572f2a..1db3277e3902755ca1bb41d2176b7095eaed4b81 100644 (file)
@@ -6,7 +6,7 @@ import sys
 import unittest.mock
 from platform import win32_edition
 from test import support
-from test.support import os_helper
+from test.support import force_not_colorized, os_helper
 
 try:
     import _winapi
@@ -437,6 +437,7 @@ class MiscTestCase(unittest.TestCase):
 
 
 class CommandLineTest(unittest.TestCase):
+    @force_not_colorized
     def test_parse_args(self):
         args, help_text = mimetypes._parse_args("-h")
         self.assertTrue(help_text.startswith("usage: "))
index 296d4b882e138ca0764e73ee5593b85e071567a7..3b46e524aac477bca10cb692c469904e0c115b3a 100644 (file)
@@ -745,6 +745,7 @@ class CommandLineTest(unittest.TestCase):
             expect = self.text_normalize(expect)
             self.assertListEqual(res.splitlines(), expect.splitlines())
 
+    @support.force_not_colorized
     def test_unknown_flag(self):
         stderr = io.StringIO()
         with self.assertRaises(SystemExit):
index b90edc05e0454e41bf26c6974a66cdf62c210197..818e807dd3a6fb68c7af311f270de70ec3ab136e 100644 (file)
@@ -794,6 +794,7 @@ class CommandLineTest(unittest.TestCase):
                     self.invoke_platform(*flags)
                     obj.assert_called_once_with(aliased, terse)
 
+    @support.force_not_colorized
     def test_help(self):
         output = io.StringIO()
 
index 96f6cc86219a5daff778c8156873b31443ad9a7c..43957f525f10c03416ec060d75df6bb060945ded 100644 (file)
@@ -1411,6 +1411,7 @@ class TestModule(unittest.TestCase):
 
 
 class CommandLineTest(unittest.TestCase):
+    @support.force_not_colorized
     def test_parse_args(self):
         args, help_text = random._parse_args(shlex.split("--choice a b c"))
         self.assertEqual(args.choice, ["a", "b", "c"])
index dcd90d11d4681928efe6e896a57b1f1cbce43fc4..ad0dcb3cccb5dab26d8e11a7f413c0ab0fd20162 100644 (file)
@@ -4,7 +4,12 @@ import unittest
 
 from sqlite3.__main__ import main as cli
 from test.support.os_helper import TESTFN, unlink
-from test.support import captured_stdout, captured_stderr, captured_stdin
+from test.support import (
+    captured_stdout,
+    captured_stderr,
+    captured_stdin,
+    force_not_colorized,
+)
 
 
 class CommandLineInterface(unittest.TestCase):
@@ -32,6 +37,7 @@ class CommandLineInterface(unittest.TestCase):
         self.assertEqual(out, "")
         return err
 
+    @force_not_colorized
     def test_cli_help(self):
         out = self.expect_success("-h")
         self.assertIn("usage: ", out)
index 117b485b9344e62435193ee85e408ced2623c332..8d01fd7bce41b043b2827a89cb2bfd828bbdfbbb 100644 (file)
@@ -518,7 +518,7 @@ def _main(args=None):
         sys.exit(1)
 
     # Parse the arguments and options
-    parser = argparse.ArgumentParser()
+    parser = argparse.ArgumentParser(color=True)
     parser.add_argument(dest='filename', nargs='?',
                         metavar='filename.py',
                         help='the file to tokenize; defaults to stdin')
index a87bc6d61a884f4da0f97ff575518a87bd7f709c..cf8817f4383fc1d513bc54dc977bc5b3e255f52e 100644 (file)
@@ -604,7 +604,7 @@ class Trace:
 def main():
     import argparse
 
-    parser = argparse.ArgumentParser()
+    parser = argparse.ArgumentParser(color=True)
     parser.add_argument('--version', action='version', version='trace 2.0')
 
     grp = parser.add_argument_group('Main options',
index c3869de3f6f18e111585a776b961d9a9986a1161..6fd949581f3146768e406484e6d42e1037bc4669 100644 (file)
@@ -197,7 +197,7 @@ class TestProgram(object):
         return parser
 
     def _getMainArgParser(self, parent):
-        parser = argparse.ArgumentParser(parents=[parent])
+        parser = argparse.ArgumentParser(parents=[parent], color=True)
         parser.prog = self.progName
         parser.print_help = self._print_help
 
@@ -208,7 +208,7 @@ class TestProgram(object):
         return parser
 
     def _getDiscoveryArgParser(self, parent):
-        parser = argparse.ArgumentParser(parents=[parent])
+        parser = argparse.ArgumentParser(parents=[parent], color=True)
         parser.prog = '%s discover' % self.progName
         parser.epilog = ('For test discovery all test modules must be '
                          'importable from the top level directory of the '
index 2c16c3f0f5a5b5c1326be9fa6bd051762d93585e..036ffebf67a0be672b945399dc2beaba263048e1 100644 (file)
@@ -949,7 +949,9 @@ def main():
     import argparse
     parser = argparse.ArgumentParser(
         formatter_class=argparse.ArgumentDefaultsHelpFormatter,
-        description="Generate a UUID using the selected UUID function.")
+        description="Generate a UUID using the selected UUID function.",
+        color=True,
+    )
     parser.add_argument("-u", "--uuid",
                         choices=uuid_funcs.keys(),
                         default="uuid4",
index dc4c9ef353199197d612738527ff5bc21cc869ad..15e15b7a5184c277274f962badcdcef3b081ef63 100644 (file)
@@ -624,7 +624,9 @@ def main(args=None):
                                             'created, you may wish to '
                                             'activate it, e.g. by '
                                             'sourcing an activate script '
-                                            'in its bin directory.')
+                                            'in its bin directory.',
+                                     color=True,
+                                     )
     parser.add_argument('dirs', metavar='ENV_DIR', nargs='+',
                         help='A directory to create the environment in.')
     parser.add_argument('--system-site-packages', default=False,
index ab50ec1ee95f9e45ffb468c9fdf5c00fbf2c2a8c..f2e2394089d5a1662eeca96ef04836297f318b8e 100644 (file)
@@ -719,7 +719,9 @@ if sys.platform == "ios":
 
 def parse_args(arg_list: list[str] | None):
     import argparse
-    parser = argparse.ArgumentParser(description="Open URL in a web browser.")
+    parser = argparse.ArgumentParser(
+        description="Open URL in a web browser.", color=True,
+    )
     parser.add_argument("url", help="URL to open")
 
     group = parser.add_mutually_exclusive_group()
index 59b444075a62d01bd12253dc0371266b701fbea7..7a4ef96ea0f07793b76527a691c95fdf9d577107 100644 (file)
@@ -187,7 +187,7 @@ def main(args=None):
     """
     import argparse
 
-    parser = argparse.ArgumentParser()
+    parser = argparse.ArgumentParser(color=True)
     parser.add_argument('--output', '-o', default=None,
             help="The name of the output archive. "
                  "Required if SOURCE is an archive.")
index b7840d0f945a66064fed227576df204b236acbda..cfb44f3ed970eeae1358231c3b353a84ee26d9c1 100644 (file)
@@ -2317,7 +2317,7 @@ def main(args=None):
     import argparse
 
     description = 'A simple command-line interface for zipfile module.'
-    parser = argparse.ArgumentParser(description=description)
+    parser = argparse.ArgumentParser(description=description, color=True)
     group = parser.add_mutually_exclusive_group(required=True)
     group.add_argument('-l', '--list', metavar='<zipfile>',
                        help='Show listing of a zipfile')
diff --git a/Misc/NEWS.d/next/Library/2025-05-04-16-00-01.gh-issue-130645.yNwKue.rst b/Misc/NEWS.d/next/Library/2025-05-04-16-00-01.gh-issue-130645.yNwKue.rst
new file mode 100644 (file)
index 0000000..8109564
--- /dev/null
@@ -0,0 +1 @@
+Add color to stdlib argparse CLIs. Patch by Hugo van Kemenade.