Skip to content

Commit acbe896

Browse files
pablogsalhugovkambvAA-Turner
authored
GH-130645: Default to color help in argparse (#136809)
Co-authored-by: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com> Co-authored-by: Łukasz Langa <lukasz@langa.pl> Co-authored-by: Adam Turner <9087854+aa-turner@users.noreply.github.com>
1 parent 65d2c51 commit acbe896

File tree

6 files changed

+39
-25
lines changed

6 files changed

+39
-25
lines changed

Doc/library/argparse.rst

Lines changed: 8 additions & 16 deletions
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, color=False)
77+
*, suggest_on_error=False, color=True)
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
@@ -119,7 +119,7 @@ ArgumentParser objects
119119
* suggest_on_error_ - Enables suggestions for mistyped argument choices
120120
and subparser names (default: ``False``)
121121

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

124124
.. versionchanged:: 3.5
125125
*allow_abbrev* parameter was added.
@@ -626,27 +626,19 @@ keyword argument::
626626
color
627627
^^^^^
628628

629-
By default, the help message is printed in plain text. If you want to allow
630-
color in help messages, you can enable it by setting ``color`` to ``True``::
629+
By default, the help message is printed in color using `ANSI escape sequences
630+
<https://en.wikipedia.org/wiki/ANSI_escape_code>`__.
631+
If you want plain text help messages, you can disable this :ref:`in your local
632+
environment <using-on-controlling-color>`, or in the argument parser itself
633+
by setting ``color`` to ``False``::
631634

632635
>>> parser = argparse.ArgumentParser(description='Process some integers.',
633-
... color=True)
636+
... color=False)
634637
>>> parser.add_argument('--action', choices=['sum', 'max'])
635638
>>> parser.add_argument('integers', metavar='N', type=int, nargs='+',
636639
... help='an integer for the accumulator')
637640
>>> parser.parse_args(['--help'])
638641

639-
Even if a CLI author has enabled color, it can be
640-
:ref:`controlled using environment variables <using-on-controlling-color>`.
641-
642-
If you're writing code that needs to be compatible with older Python versions
643-
and want to opportunistically use ``color`` when it's available, you
644-
can set it as an attribute after initializing the parser instead of using the
645-
keyword argument::
646-
647-
>>> parser = argparse.ArgumentParser(description='Process some integers.')
648-
>>> parser.color = True
649-
650642
.. versionadded:: 3.14
651643

652644

Doc/whatsnew/3.14.rst

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1228,11 +1228,10 @@ argparse
12281228

12291229
.. _whatsnew314-color-argparse:
12301230

1231-
* Introduced the optional *color* parameter to
1232-
:class:`argparse.ArgumentParser`, enabling color for help text.
1233-
This can be controlled by :ref:`environment variables
1234-
<using-on-controlling-color>`. Color has also been enabled for help in the
1235-
:ref:`stdlib CLIs <library-cmdline>` which use :mod:`!argparse`.
1231+
* Enable color for help text, which can be disabled with the optional *color*
1232+
parameter to :class:`argparse.ArgumentParser`.
1233+
This can also be controlled by :ref:`environment variables
1234+
<using-on-controlling-color>`.
12361235
(Contributed by Hugo van Kemenade in :gh:`130645`.)
12371236

12381237

Lib/argparse.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ def __init__(
167167
indent_increment=2,
168168
max_help_position=24,
169169
width=None,
170-
color=False,
170+
color=True,
171171
):
172172
# default setting for width
173173
if width is None:
@@ -1231,7 +1231,7 @@ def __init__(self,
12311231
self._name_parser_map = {}
12321232
self._choices_actions = []
12331233
self._deprecated = set()
1234-
self._color = False
1234+
self._color = True
12351235

12361236
super(_SubParsersAction, self).__init__(
12371237
option_strings=option_strings,
@@ -1878,7 +1878,7 @@ def __init__(self,
18781878
exit_on_error=True,
18791879
*,
18801880
suggest_on_error=False,
1881-
color=False,
1881+
color=True,
18821882
):
18831883
superinit = super(ArgumentParser, self).__init__
18841884
superinit(description=description,

Lib/test/test_argparse.py

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,11 @@
1818
import warnings
1919

2020
from enum import StrEnum
21-
from test.support import captured_stderr
21+
from test.support import (
22+
captured_stderr,
23+
force_not_colorized,
24+
force_not_colorized_test_class,
25+
)
2226
from test.support import import_helper
2327
from test.support import os_helper
2428
from test.support import script_helper
@@ -1007,6 +1011,7 @@ def test_parse_enum_value(self):
10071011
args = parser.parse_args(['--color', 'red'])
10081012
self.assertEqual(args.color, self.Color.RED)
10091013

1014+
@force_not_colorized
10101015
def test_help_message_contains_enum_choices(self):
10111016
parser = argparse.ArgumentParser()
10121017
parser.add_argument('--color', choices=self.Color, help='Choose a color')
@@ -2403,6 +2408,7 @@ def test_modified_invalid_action(self):
24032408
# Subparsers tests
24042409
# ================
24052410

2411+
@force_not_colorized_test_class
24062412
class TestAddSubparsers(TestCase):
24072413
"""Test the add_subparsers method"""
24082414

@@ -3009,6 +3015,7 @@ def test_nested_argument_group(self):
30093015
# Parent parser tests
30103016
# ===================
30113017

3018+
@force_not_colorized_test_class
30123019
class TestParentParsers(TestCase):
30133020
"""Tests that parsers can be created with parent parsers"""
30143021

@@ -3216,6 +3223,7 @@ def test_mutex_groups_parents(self):
32163223
# Mutually exclusive group tests
32173224
# ==============================
32183225

3226+
@force_not_colorized_test_class
32193227
class TestMutuallyExclusiveGroupErrors(TestCase):
32203228

32213229
def test_invalid_add_argument_group(self):
@@ -3344,21 +3352,25 @@ def test_successes_when_required(self):
33443352
actual_ns = parse_args(args_string.split())
33453353
self.assertEqual(actual_ns, expected_ns)
33463354

3355+
@force_not_colorized
33473356
def test_usage_when_not_required(self):
33483357
format_usage = self.get_parser(required=False).format_usage
33493358
expected_usage = self.usage_when_not_required
33503359
self.assertEqual(format_usage(), textwrap.dedent(expected_usage))
33513360

3361+
@force_not_colorized
33523362
def test_usage_when_required(self):
33533363
format_usage = self.get_parser(required=True).format_usage
33543364
expected_usage = self.usage_when_required
33553365
self.assertEqual(format_usage(), textwrap.dedent(expected_usage))
33563366

3367+
@force_not_colorized
33573368
def test_help_when_not_required(self):
33583369
format_help = self.get_parser(required=False).format_help
33593370
help = self.usage_when_not_required + self.help
33603371
self.assertEqual(format_help(), textwrap.dedent(help))
33613372

3373+
@force_not_colorized
33623374
def test_help_when_required(self):
33633375
format_help = self.get_parser(required=True).format_help
33643376
help = self.usage_when_required + self.help
@@ -4030,11 +4042,13 @@ def _test(self, tester, parser_text):
40304042
tester.maxDiff = None
40314043
tester.assertEqual(expected_text, parser_text)
40324044

4045+
@force_not_colorized
40334046
def test_format(self, tester):
40344047
parser = self._get_parser(tester)
40354048
format = getattr(parser, 'format_%s' % self.func_suffix)
40364049
self._test(tester, format())
40374050

4051+
@force_not_colorized
40384052
def test_print(self, tester):
40394053
parser = self._get_parser(tester)
40404054
print_ = getattr(parser, 'print_%s' % self.func_suffix)
@@ -4047,6 +4061,7 @@ def test_print(self, tester):
40474061
setattr(sys, self.std_name, old_stream)
40484062
self._test(tester, parser_text)
40494063

4064+
@force_not_colorized
40504065
def test_print_file(self, tester):
40514066
parser = self._get_parser(tester)
40524067
print_ = getattr(parser, 'print_%s' % self.func_suffix)
@@ -4788,6 +4803,7 @@ class TestHelpUsageMetavarsSpacesParentheses(HelpTestCase):
47884803
version = ''
47894804

47904805

4806+
@force_not_colorized_test_class
47914807
class TestHelpUsageNoWhitespaceCrash(TestCase):
47924808

47934809
def test_all_suppressed_mutex_followed_by_long_arg(self):
@@ -5469,6 +5485,7 @@ def custom_type(string):
54695485
version = ''
54705486

54715487

5488+
@force_not_colorized_test_class
54725489
class TestHelpCustomHelpFormatter(TestCase):
54735490
maxDiff = None
54745491

@@ -5765,6 +5782,7 @@ def test_conflict_error(self):
57655782
self.assertRaises(argparse.ArgumentError,
57665783
parser.add_argument, '--spam')
57675784

5785+
@force_not_colorized
57685786
def test_resolve_error(self):
57695787
get_parser = argparse.ArgumentParser
57705788
parser = get_parser(prog='PROG', conflict_handler='resolve')
@@ -6031,6 +6049,7 @@ def test_argument_error(self):
60316049

60326050
class TestArgumentTypeError(TestCase):
60336051

6052+
@force_not_colorized
60346053
def test_argument_type_error(self):
60356054

60366055
def spam(string):
@@ -6829,6 +6848,7 @@ def setUp(self):
68296848
metavar = '<http[s]://example:1234>'
68306849
self.parser.add_argument('--proxy', metavar=metavar)
68316850

6851+
@force_not_colorized
68326852
def test_help_with_metavar(self):
68336853
help_text = self.parser.format_help()
68346854
self.assertEqual(help_text, textwrap.dedent('''\
@@ -6994,6 +7014,7 @@ def test_os_error(self):
69947014
self.parser.parse_args, ['@no-such-file'])
69957015

69967016

7017+
@force_not_colorized_test_class
69977018
class TestProgName(TestCase):
69987019
source = textwrap.dedent('''\
69997020
import argparse

Lib/test/test_clinic.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2792,6 +2792,7 @@ def test_cli_verbose(self):
27922792
out = self.expect_success("-v", fn)
27932793
self.assertEqual(out.strip(), fn)
27942794

2795+
@support.force_not_colorized
27952796
def test_cli_help(self):
27962797
out = self.expect_success("-h")
27972798
self.assertIn("usage: clinic.py", out)
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Enable color help by default in :mod:`argparse`.

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

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

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


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy