Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit734e15b

Browse files
gh-133653: Fix argparse.ArgumentParser with the formatter_class argument (GH-133813)
* Fix TypeError when formatter_class is a custom subclass of HelpFormatter.* Fix TypeError when formatter_class is not a subclass of HelpFormatter and non-standard prefix_char is used.* Fix support of colorizing when formatter_class is not a subclass of HelpFormatter.* Remove the prefix_chars parameter of HelpFormatter.
1 parent14305a8 commit734e15b

File tree

3 files changed

+154
-43
lines changed

3 files changed

+154
-43
lines changed

‎Lib/argparse.py

Lines changed: 21 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,6 @@ def __init__(
167167
indent_increment=2,
168168
max_help_position=24,
169169
width=None,
170-
prefix_chars='-',
171170
color=False,
172171
):
173172
# default setting for width
@@ -176,16 +175,7 @@ def __init__(
176175
width=shutil.get_terminal_size().columns
177176
width-=2
178177

179-
from_colorizeimportcan_colorize,decolor,get_theme
180-
181-
ifcolorandcan_colorize():
182-
self._theme=get_theme(force_color=True).argparse
183-
self._decolor=decolor
184-
else:
185-
self._theme=get_theme(force_no_color=True).argparse
186-
self._decolor=lambdatext:text
187-
188-
self._prefix_chars=prefix_chars
178+
self._set_color(color)
189179
self._prog=prog
190180
self._indent_increment=indent_increment
191181
self._max_help_position=min(max_help_position,
@@ -202,6 +192,16 @@ def __init__(
202192
self._whitespace_matcher=_re.compile(r'\s+',_re.ASCII)
203193
self._long_break_matcher=_re.compile(r'\n\n\n+')
204194

195+
def_set_color(self,color):
196+
from_colorizeimportcan_colorize,decolor,get_theme
197+
198+
ifcolorandcan_colorize():
199+
self._theme=get_theme(force_color=True).argparse
200+
self._decolor=decolor
201+
else:
202+
self._theme=get_theme(force_no_color=True).argparse
203+
self._decolor=lambdatext:text
204+
205205
# ===============================
206206
# Section and indentation methods
207207
# ===============================
@@ -415,14 +415,7 @@ def _format_actions_usage(self, actions, groups):
415415
return' '.join(self._get_actions_usage_parts(actions,groups))
416416

417417
def_is_long_option(self,string):
418-
returnlen(string)>=2andstring[1]inself._prefix_chars
419-
420-
def_is_short_option(self,string):
421-
return (
422-
notself._is_long_option(string)
423-
andlen(string)>=1
424-
andstring[0]inself._prefix_chars
425-
)
418+
returnlen(string)>2
426419

427420
def_get_actions_usage_parts(self,actions,groups):
428421
# find group indices and identify actions in groups
@@ -471,25 +464,22 @@ def _get_actions_usage_parts(self, actions, groups):
471464
# produce the first way to invoke the option in brackets
472465
else:
473466
option_string=action.option_strings[0]
467+
ifself._is_long_option(option_string):
468+
option_color=t.summary_long_option
469+
else:
470+
option_color=t.summary_short_option
474471

475472
# if the Optional doesn't take a value, format is:
476473
# -s or --long
477474
ifaction.nargs==0:
478475
part=action.format_usage()
479-
ifself._is_long_option(part):
480-
part=f"{t.summary_long_option}{part}{t.reset}"
481-
elifself._is_short_option(part):
482-
part=f"{t.summary_short_option}{part}{t.reset}"
476+
part=f"{option_color}{part}{t.reset}"
483477

484478
# if the Optional takes a value, format is:
485479
# -s ARGS or --long ARGS
486480
else:
487481
default=self._get_default_metavar_for_optional(action)
488482
args_string=self._format_args(action,default)
489-
ifself._is_long_option(option_string):
490-
option_color=t.summary_long_option
491-
elifself._is_short_option(option_string):
492-
option_color=t.summary_short_option
493483
part= (
494484
f"{option_color}{option_string} "
495485
f"{t.summary_label}{args_string}{t.reset}"
@@ -606,10 +596,8 @@ def color_option_strings(strings):
606596
forsinstrings:
607597
ifself._is_long_option(s):
608598
parts.append(f"{t.long_option}{s}{t.reset}")
609-
elifself._is_short_option(s):
610-
parts.append(f"{t.short_option}{s}{t.reset}")
611599
else:
612-
parts.append(s)
600+
parts.append(f"{t.short_option}{s}{t.reset}")
613601
returnparts
614602

615603
# if the Optional doesn't take a value, format is:
@@ -2723,16 +2711,9 @@ def format_help(self):
27232711
returnformatter.format_help()
27242712

27252713
def_get_formatter(self):
2726-
ifisinstance(self.formatter_class,type)andissubclass(
2727-
self.formatter_class,HelpFormatter
2728-
):
2729-
returnself.formatter_class(
2730-
prog=self.prog,
2731-
prefix_chars=self.prefix_chars,
2732-
color=self.color,
2733-
)
2734-
else:
2735-
returnself.formatter_class(prog=self.prog)
2714+
formatter=self.formatter_class(prog=self.prog)
2715+
formatter._set_color(self.color)
2716+
returnformatter
27362717

27372718
# =====================
27382719
# Help-printing methods

‎Lib/test/test_argparse.py

Lines changed: 126 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5469,11 +5469,60 @@ def custom_type(string):
54695469
version=''
54705470

54715471

5472-
classTestHelpUsageLongSubparserCommand(TestCase):
5473-
"""Test that subparser commands are formatted correctly in help"""
5472+
classTestHelpCustomHelpFormatter(TestCase):
54745473
maxDiff=None
54755474

5476-
deftest_parent_help(self):
5475+
deftest_custom_formatter_function(self):
5476+
defcustom_formatter(prog):
5477+
returnargparse.RawTextHelpFormatter(prog,indent_increment=5)
5478+
5479+
parser=argparse.ArgumentParser(
5480+
prog='PROG',
5481+
prefix_chars='-+',
5482+
formatter_class=custom_formatter
5483+
)
5484+
parser.add_argument('+f','++foo',help="foo help")
5485+
parser.add_argument('spam',help="spam help")
5486+
5487+
parser_help=parser.format_help()
5488+
self.assertEqual(parser_help,textwrap.dedent('''\
5489+
usage: PROG [-h] [+f FOO] spam
5490+
5491+
positional arguments:
5492+
spam spam help
5493+
5494+
options:
5495+
-h, --help show this help message and exit
5496+
+f, ++foo FOO foo help
5497+
'''))
5498+
5499+
deftest_custom_formatter_class(self):
5500+
classCustomFormatter(argparse.RawTextHelpFormatter):
5501+
def__init__(self,prog):
5502+
super().__init__(prog,indent_increment=5)
5503+
5504+
parser=argparse.ArgumentParser(
5505+
prog='PROG',
5506+
prefix_chars='-+',
5507+
formatter_class=CustomFormatter
5508+
)
5509+
parser.add_argument('+f','++foo',help="foo help")
5510+
parser.add_argument('spam',help="spam help")
5511+
5512+
parser_help=parser.format_help()
5513+
self.assertEqual(parser_help,textwrap.dedent('''\
5514+
usage: PROG [-h] [+f FOO] spam
5515+
5516+
positional arguments:
5517+
spam spam help
5518+
5519+
options:
5520+
-h, --help show this help message and exit
5521+
+f, ++foo FOO foo help
5522+
'''))
5523+
5524+
deftest_usage_long_subparser_command(self):
5525+
"""Test that subparser commands are formatted correctly in help"""
54775526
defcustom_formatter(prog):
54785527
returnargparse.RawTextHelpFormatter(prog,max_help_position=50)
54795528

@@ -7053,6 +7102,7 @@ def test_translations(self):
70537102

70547103

70557104
classTestColorized(TestCase):
7105+
maxDiff=None
70567106

70577107
defsetUp(self):
70587108
super().setUp()
@@ -7211,6 +7261,79 @@ def test_argparse_color_usage(self):
72117261
),
72127262
)
72137263

7264+
deftest_custom_formatter_function(self):
7265+
defcustom_formatter(prog):
7266+
returnargparse.RawTextHelpFormatter(prog,indent_increment=5)
7267+
7268+
parser=argparse.ArgumentParser(
7269+
prog="PROG",
7270+
prefix_chars="-+",
7271+
formatter_class=custom_formatter,
7272+
color=True,
7273+
)
7274+
parser.add_argument('+f','++foo',help="foo help")
7275+
parser.add_argument('spam',help="spam help")
7276+
7277+
prog=self.theme.prog
7278+
heading=self.theme.heading
7279+
short=self.theme.summary_short_option
7280+
label=self.theme.summary_label
7281+
pos=self.theme.summary_action
7282+
long_b=self.theme.long_option
7283+
short_b=self.theme.short_option
7284+
label_b=self.theme.label
7285+
pos_b=self.theme.action
7286+
reset=self.theme.reset
7287+
7288+
parser_help=parser.format_help()
7289+
self.assertEqual(parser_help,textwrap.dedent(f'''\
7290+
{heading}usage:{reset}{prog}PROG{reset} [{short}-h{reset}] [{short}+f{label}FOO{reset}]{pos}spam{reset}
7291+
7292+
{heading}positional arguments:{reset}
7293+
{pos_b}spam{reset} spam help
7294+
7295+
{heading}options:{reset}
7296+
{short_b}-h{reset},{long_b}--help{reset} show this help message and exit
7297+
{short_b}+f{reset},{long_b}++foo{reset}{label_b}FOO{reset} foo help
7298+
'''))
7299+
7300+
deftest_custom_formatter_class(self):
7301+
classCustomFormatter(argparse.RawTextHelpFormatter):
7302+
def__init__(self,prog):
7303+
super().__init__(prog,indent_increment=5)
7304+
7305+
parser=argparse.ArgumentParser(
7306+
prog="PROG",
7307+
prefix_chars="-+",
7308+
formatter_class=CustomFormatter,
7309+
color=True,
7310+
)
7311+
parser.add_argument('+f','++foo',help="foo help")
7312+
parser.add_argument('spam',help="spam help")
7313+
7314+
prog=self.theme.prog
7315+
heading=self.theme.heading
7316+
short=self.theme.summary_short_option
7317+
label=self.theme.summary_label
7318+
pos=self.theme.summary_action
7319+
long_b=self.theme.long_option
7320+
short_b=self.theme.short_option
7321+
label_b=self.theme.label
7322+
pos_b=self.theme.action
7323+
reset=self.theme.reset
7324+
7325+
parser_help=parser.format_help()
7326+
self.assertEqual(parser_help,textwrap.dedent(f'''\
7327+
{heading}usage:{reset}{prog}PROG{reset} [{short}-h{reset}] [{short}+f{label}FOO{reset}]{pos}spam{reset}
7328+
7329+
{heading}positional arguments:{reset}
7330+
{pos_b}spam{reset} spam help
7331+
7332+
{heading}options:{reset}
7333+
{short_b}-h{reset},{long_b}--help{reset} show this help message and exit
7334+
{short_b}+f{reset},{long_b}++foo{reset}{label_b}FOO{reset} foo help
7335+
'''))
7336+
72147337

72157338
deftearDownModule():
72167339
# Remove global references to avoid looking like we have refleaks.
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
Fix:class:`argparse.ArgumentParser` with the *formatter_class* argument.
2+
Fix TypeError when *formatter_class* is a custom subclass of
3+
:class:`!HelpFormatter`.
4+
Fix TypeError when *formatter_class* is not a subclass of
5+
:class:`!HelpFormatter` and non-standard *prefix_char* is used.
6+
Fix support of colorizing when *formatter_class* is not a subclass of
7+
:class:`!HelpFormatter`.

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp