Skip to content

Commit 7d3a012

Browse files
authored
Merge branch 'main' into small_int_immortal
2 parents 4dc97c9 + 615abb9 commit 7d3a012

File tree

5 files changed

+62
-5
lines changed

5 files changed

+62
-5
lines changed

Doc/library/argparse.rst

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,12 @@ arguments it contains. The default message can be overridden with the
192192
The ``%(prog)s`` format specifier is available to fill in the program name in
193193
your usage messages.
194194

195+
When a custom usage message is specified for the main parser, you may also want to
196+
consider passing the ``prog`` argument to :meth:`~ArgumentParser.add_subparsers`
197+
or the ``prog`` and the ``usage`` arguments to
198+
:meth:`~_SubParsersAction.add_parser`, to ensure consistent command prefixes and
199+
usage information across subparsers.
200+
195201

196202
.. _description:
197203

@@ -1810,6 +1816,10 @@ Sub-commands
18101816
.. versionchanged:: 3.7
18111817
New *required* keyword-only parameter.
18121818

1819+
.. versionchanged:: 3.14
1820+
Subparser's *prog* is no longer affected by a custom usage message in
1821+
the main parser.
1822+
18131823

18141824
FileType objects
18151825
^^^^^^^^^^^^^^^^

Lib/argparse.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1889,7 +1889,7 @@ def add_subparsers(self, **kwargs):
18891889
formatter = self._get_formatter()
18901890
positionals = self._get_positional_actions()
18911891
groups = self._mutually_exclusive_groups
1892-
formatter.add_usage(self.usage, positionals, groups, '')
1892+
formatter.add_usage(None, positionals, groups, '')
18931893
kwargs['prog'] = formatter.format_help().strip()
18941894

18951895
# create the parsers action and add it to the positionals list

Lib/test/test_argparse.py

Lines changed: 47 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2409,16 +2409,17 @@ def assertArgumentParserError(self, *args, **kwargs):
24092409
self.assertRaises(ArgumentParserError, *args, **kwargs)
24102410

24112411
def _get_parser(self, subparser_help=False, prefix_chars=None,
2412-
aliases=False):
2412+
aliases=False, usage=None):
24132413
# create a parser with a subparsers argument
24142414
if prefix_chars:
24152415
parser = ErrorRaisingArgumentParser(
2416-
prog='PROG', description='main description', prefix_chars=prefix_chars)
2416+
prog='PROG', description='main description', usage=usage,
2417+
prefix_chars=prefix_chars)
24172418
parser.add_argument(
24182419
prefix_chars[0] * 2 + 'foo', action='store_true', help='foo help')
24192420
else:
24202421
parser = ErrorRaisingArgumentParser(
2421-
prog='PROG', description='main description')
2422+
prog='PROG', description='main description', usage=usage)
24222423
parser.add_argument(
24232424
'--foo', action='store_true', help='foo help')
24242425
parser.add_argument(
@@ -2455,7 +2456,8 @@ def _get_parser(self, subparser_help=False, prefix_chars=None,
24552456
parser2.add_argument('z', type=complex, nargs='*', help='z help')
24562457

24572458
# add third sub-parser
2458-
parser3_kwargs = dict(description='3 description')
2459+
parser3_kwargs = dict(description='3 description',
2460+
usage='PROG --foo bar 3 t ...')
24592461
if subparser_help:
24602462
parser3_kwargs['help'] = '3 help'
24612463
parser3 = subparsers.add_parser('3', **parser3_kwargs)
@@ -2477,6 +2479,47 @@ def test_parse_args_failures(self):
24772479
args = args_str.split()
24782480
self.assertArgumentParserError(self.parser.parse_args, args)
24792481

2482+
def test_parse_args_failures_details(self):
2483+
for args_str, usage_str, error_str in [
2484+
('',
2485+
'usage: PROG [-h] [--foo] bar {1,2,3} ...',
2486+
'PROG: error: the following arguments are required: bar'),
2487+
('0.5 1 -y',
2488+
'usage: PROG bar 1 [-h] [-w W] {a,b,c}',
2489+
'PROG bar 1: error: the following arguments are required: x'),
2490+
('0.5 3',
2491+
'usage: PROG --foo bar 3 t ...',
2492+
'PROG bar 3: error: the following arguments are required: t'),
2493+
]:
2494+
with self.subTest(args_str):
2495+
args = args_str.split()
2496+
with self.assertRaises(ArgumentParserError) as cm:
2497+
self.parser.parse_args(args)
2498+
self.assertEqual(cm.exception.args[0], 'SystemExit')
2499+
self.assertEqual(cm.exception.args[2], f'{usage_str}\n{error_str}\n')
2500+
2501+
def test_parse_args_failures_details_custom_usage(self):
2502+
parser = self._get_parser(usage='PROG [--foo] bar 1 [-w W] {a,b,c}\n'
2503+
' PROG --foo bar 3 t ...')
2504+
for args_str, usage_str, error_str in [
2505+
('',
2506+
'usage: PROG [--foo] bar 1 [-w W] {a,b,c}\n'
2507+
' PROG --foo bar 3 t ...',
2508+
'PROG: error: the following arguments are required: bar'),
2509+
('0.5 1 -y',
2510+
'usage: PROG bar 1 [-h] [-w W] {a,b,c}',
2511+
'PROG bar 1: error: the following arguments are required: x'),
2512+
('0.5 3',
2513+
'usage: PROG --foo bar 3 t ...',
2514+
'PROG bar 3: error: the following arguments are required: t'),
2515+
]:
2516+
with self.subTest(args_str):
2517+
args = args_str.split()
2518+
with self.assertRaises(ArgumentParserError) as cm:
2519+
parser.parse_args(args)
2520+
self.assertEqual(cm.exception.args[0], 'SystemExit')
2521+
self.assertEqual(cm.exception.args[2], f'{usage_str}\n{error_str}\n')
2522+
24802523
def test_parse_args(self):
24812524
# check some non-failure cases:
24822525
self.assertEqual(
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
The ``usage`` parameter of :class:`argparse.ArgumentParser` no longer
2+
affects the default value of the ``prog`` parameter in subparsers.

PCbuild/_freeze_module.vcxproj.filters

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,8 @@
239239
<Filter>Source Files</Filter>
240240
</ClCompile>
241241
<ClCompile Include="..\Python\instruction_sequence.c">
242+
<Filter>Source Files</Filter>
243+
</ClCompile>
242244
<ClCompile Include="..\Python\interpconfig.c">
243245
<Filter>Source Files</Filter>
244246
</ClCompile>

0 commit comments

Comments
 (0)