Skip to content

Commit 4701ff9

Browse files
authored
gh-130645: Add color to argparse help (GH-132323)
1 parent ba16ba3 commit 4701ff9

File tree

5 files changed

+342
-31
lines changed

5 files changed

+342
-31
lines changed

Doc/library/argparse.rst

+35-3
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ ArgumentParser objects
7474
prefix_chars='-', fromfile_prefix_chars=None, \
7575
argument_default=None, conflict_handler='error', \
7676
add_help=True, allow_abbrev=True, exit_on_error=True, \
77-
suggest_on_error=False)
77+
suggest_on_error=False, color=False)
7878

7979
Create a new :class:`ArgumentParser` object. All parameters should be passed
8080
as keyword arguments. Each parameter has its own more detailed description
@@ -111,14 +111,15 @@ ArgumentParser objects
111111
* add_help_ - Add a ``-h/--help`` option to the parser (default: ``True``)
112112

113113
* allow_abbrev_ - Allows long options to be abbreviated if the
114-
abbreviation is unambiguous. (default: ``True``)
114+
abbreviation is unambiguous (default: ``True``)
115115

116116
* exit_on_error_ - Determines whether or not :class:`!ArgumentParser` exits with
117117
error info when an error occurs. (default: ``True``)
118118

119119
* suggest_on_error_ - Enables suggestions for mistyped argument choices
120120
and subparser names (default: ``False``)
121121

122+
* color_ - Allow color output (default: ``False``)
122123

123124
.. versionchanged:: 3.5
124125
*allow_abbrev* parameter was added.
@@ -130,6 +131,9 @@ ArgumentParser objects
130131
.. versionchanged:: 3.9
131132
*exit_on_error* parameter was added.
132133

134+
.. versionchanged:: 3.14
135+
*suggest_on_error* and *color* parameters were added.
136+
133137
The following sections describe how each of these are used.
134138

135139

@@ -594,7 +598,8 @@ subparser names, the feature can be enabled by setting ``suggest_on_error`` to
594598
``True``. Note that this only applies for arguments when the choices specified
595599
are strings::
596600

597-
>>> parser = argparse.ArgumentParser(description='Process some integers.', suggest_on_error=True)
601+
>>> parser = argparse.ArgumentParser(description='Process some integers.',
602+
suggest_on_error=True)
598603
>>> parser.add_argument('--action', choices=['sum', 'max'])
599604
>>> parser.add_argument('integers', metavar='N', type=int, nargs='+',
600605
... help='an integer for the accumulator')
@@ -612,6 +617,33 @@ keyword argument::
612617
.. versionadded:: 3.14
613618

614619

620+
color
621+
^^^^^
622+
623+
By default, the help message is printed in plain text. If you want to allow
624+
color in help messages, you can enable it by setting ``color`` to ``True``::
625+
626+
>>> parser = argparse.ArgumentParser(description='Process some integers.',
627+
... color=True)
628+
>>> parser.add_argument('--action', choices=['sum', 'max'])
629+
>>> parser.add_argument('integers', metavar='N', type=int, nargs='+',
630+
... help='an integer for the accumulator')
631+
>>> parser.parse_args(['--help'])
632+
633+
Even if a CLI author has enabled color, it can be
634+
:ref:`controlled using environment variables <using-on-controlling-color>`.
635+
636+
If you're writing code that needs to be compatible with older Python versions
637+
and want to opportunistically use ``color`` when it's available, you
638+
can set it as an attribute after initializing the parser instead of using the
639+
keyword argument::
640+
641+
>>> parser = argparse.ArgumentParser(description='Process some integers.')
642+
>>> parser.color = True
643+
644+
.. versionadded:: next
645+
646+
615647
The add_argument() method
616648
-------------------------
617649

Lib/_colorize.py

+11-1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ class ANSIColors:
1717
BLUE = "\x1b[34m"
1818
CYAN = "\x1b[36m"
1919
GREEN = "\x1b[32m"
20+
GREY = "\x1b[90m"
2021
MAGENTA = "\x1b[35m"
2122
RED = "\x1b[31m"
2223
WHITE = "\x1b[37m" # more like LIGHT GRAY
@@ -60,10 +61,12 @@ class ANSIColors:
6061
INTENSE_BACKGROUND_YELLOW = "\x1b[103m"
6162

6263

64+
ColorCodes = set()
6365
NoColors = ANSIColors()
6466

65-
for attr in dir(NoColors):
67+
for attr, code in ANSIColors.__dict__.items():
6668
if not attr.startswith("__"):
69+
ColorCodes.add(code)
6770
setattr(NoColors, attr, "")
6871

6972

@@ -76,6 +79,13 @@ def get_colors(
7679
return NoColors
7780

7881

82+
def decolor(text: str) -> str:
83+
"""Remove ANSI color codes from a string."""
84+
for code in ColorCodes:
85+
text = text.replace(code, "")
86+
return text
87+
88+
7989
def can_colorize(*, file: IO[str] | IO[bytes] | None = None) -> bool:
8090
if file is None:
8191
file = sys.stdout

0 commit comments

Comments
 (0)