Skip to content

Commit 2049496

Browse files
committed
Fixed prog value of subcommands added with as_subcommand_to() decorator.
Fixed missing settings in subcommand parsers created with as_subcommand_to() decorator.
1 parent 47568c0 commit 2049496

File tree

2 files changed

+32
-11
lines changed

2 files changed

+32
-11
lines changed

cmd2/decorators.py

Lines changed: 30 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -326,36 +326,57 @@ def as_subcommand_to(command: str,
326326
subcommand: str,
327327
parser: argparse.ArgumentParser,
328328
*,
329-
help_text: Optional[str] = None,
329+
help: Optional[str] = None,
330330
aliases: Iterable[str] = None) -> Callable[[argparse.Namespace], Optional[bool]]:
331331
"""
332332
Tag this method as a subcommand to an existing argparse decorated command.
333333
334334
:param command: Command Name. Space-delimited subcommands may optionally be specified
335335
:param subcommand: Subcommand name
336336
:param parser: argparse Parser for this subcommand
337-
:param help_text: Help message for this subcommand
338-
:param aliases: Alternative names for this subcommand
337+
:param help: Help message for this subcommand which displays in the list of subcommands of the command we are adding to.
338+
This is passed as the help argument to ArgumentParser.add_subparser().
339+
:param aliases: Alternative names for this subcommand. This is passed as the alias argument to
340+
ArgumentParser.add_subparser().
339341
:return: Wrapper function that can receive an argparse.Namespace
340342
"""
341343
def arg_decorator(func: Callable):
342-
_set_parser_prog(parser, subcommand)
344+
_set_parser_prog(parser, command + ' ' + subcommand)
343345

344346
# If the description has not been set, then use the method docstring if one exists
345347
if parser.description is None and func.__doc__:
346348
parser.description = func.__doc__
347349

348-
parser.set_defaults(func=func)
349-
350350
# Set some custom attributes for this command
351351
setattr(func, constants.SUBCMD_ATTR_COMMAND, command)
352352
setattr(func, constants.CMD_ATTR_ARGPARSER, parser)
353353
setattr(func, constants.SUBCMD_ATTR_NAME, subcommand)
354-
parser_args = {}
355-
if help_text is not None:
356-
parser_args['help'] = help_text
354+
355+
# Dictionary of arguments which will be passed to ArgumentParser.add_subparser()
356+
parser_args = dict()
357+
358+
# parser is set as the parent to the one being created by ArgumentParser.add_parser().
359+
# argparse only copies actions (arguments) from a parent and not the following settings.
360+
# To retain these settings, we will copy them from parser and pass them as ArgumentParser
361+
# constructor arguments to add_parser().
362+
parser_args['prog'] = parser.prog
363+
parser_args['usage'] = parser.usage
364+
parser_args['description'] = parser.description
365+
parser_args['epilog'] = parser.epilog
366+
parser_args['formatter_class'] = parser.formatter_class
367+
parser_args['prefix_chars'] = parser.prefix_chars
368+
parser_args['fromfile_prefix_chars'] = parser.fromfile_prefix_chars
369+
parser_args['argument_default'] = parser.argument_default
370+
parser_args['conflict_handler'] = parser.conflict_handler
371+
parser_args['add_help'] = parser.add_help
372+
parser_args['allow_abbrev'] = parser.allow_abbrev
373+
374+
# Add remaining arguments specific to add_parser()
375+
if help is not None:
376+
parser_args['help'] = help
357377
if aliases is not None:
358378
parser_args['aliases'] = aliases[:]
379+
359380
setattr(func, constants.SUBCMD_ATTR_PARSER_ARGS, parser_args)
360381

361382
return func

tests_isolated/test_commandset/test_commandset.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -330,7 +330,7 @@ def do_apple(self, cmd: cmd2.Cmd, _: cmd2.Statement):
330330
banana_parser = cmd2.Cmd2ArgumentParser(add_help=False)
331331
banana_parser.add_argument('direction', choices=['discs', 'lengthwise'])
332332

333-
@cmd2.as_subcommand_to('cut', 'banana', banana_parser, help_text='Cut banana', aliases=['bananer'])
333+
@cmd2.as_subcommand_to('cut', 'banana', banana_parser, help='Cut banana', aliases=['bananer'])
334334
def cut_banana(self, cmd: cmd2.Cmd, ns: argparse.Namespace):
335335
"""Cut banana"""
336336
cmd.poutput('cutting banana: ' + ns.direction)
@@ -545,7 +545,7 @@ def do_cut(self, ns: argparse.Namespace):
545545
banana_parser = cmd2.Cmd2ArgumentParser(add_help=False)
546546
banana_parser.add_argument('direction', choices=['discs', 'lengthwise'])
547547

548-
@cmd2.as_subcommand_to('cut', 'banana', banana_parser, help_text='Cut banana', aliases=['bananer'])
548+
@cmd2.as_subcommand_to('cut', 'banana', banana_parser, help='Cut banana', aliases=['bananer'])
549549
def cut_banana(self, ns: argparse.Namespace):
550550
"""Cut banana"""
551551
self.poutput('cutting banana: ' + ns.direction)

0 commit comments

Comments
 (0)