Skip to content

Commit

Permalink
Merge pull request #1005 from python-cmd2/duplicate_subcommand
Browse files Browse the repository at this point in the history
Fixed duplicate help text of subcommands
  • Loading branch information
kmvanbrunt authored Oct 1, 2020
2 parents ad646aa + 457ee75 commit c36569c
Show file tree
Hide file tree
Showing 3 changed files with 23 additions and 11 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
* Bug Fixes
* Fixed issue where quoted redirectors and terminators in aliases and macros were not being
restored when read from a startup script.
* Fixed issue where instantiating more than one cmd2-based class which uses the `@as_subcommand_to`
decorator resulted in duplicated help text in the base command the subcommands belong to.

## 1.3.10 (September 17, 2020)
* Enhancements
Expand Down
24 changes: 13 additions & 11 deletions cmd2/argparse_custom.py
Original file line number Diff line number Diff line change
Expand Up @@ -550,6 +550,7 @@ def _match_argument_wrapper(self, action, arg_strings_pattern) -> int:
# Patch argparse._SubParsersAction to add remove_parser function
############################################################################################################

# noinspection PyPep8Naming
def _SubParsersAction_remove_parser(self, name: str):
"""
Removes a sub-parser from a sub-parsers group
Expand All @@ -558,23 +559,23 @@ def _SubParsersAction_remove_parser(self, name: str):
class so cmd2 can remove subcommands from a parser.
:param self: instance of the _SubParsersAction being edited
:param name: name of the sub-parser to remove
:param name: name of the subcommand for the sub-parser to remove
"""
# Remove this subcommand from its base command's help text
for choice_action in self._choices_actions:
if choice_action.dest == name:
self._choices_actions.remove(choice_action)
break

subparser = self._name_parser_map[name]
to_remove = []
for name, parser in self._name_parser_map.items():
if parser is subparser:
to_remove.append(name)
for name in to_remove:
del self._name_parser_map[name]

if name in self.choices:
del self.choices[name]
# Remove this subcommand and all its aliases from the base command
subparser = self._name_parser_map.get(name)
if subparser is not None:
to_remove = []
for cur_name, cur_parser in self._name_parser_map.items():
if cur_parser is subparser:
to_remove.append(cur_name)
for cur_name in to_remove:
del self._name_parser_map[cur_name]


# noinspection PyProtectedMember
Expand Down Expand Up @@ -733,6 +734,7 @@ def _format_action_invocation(self, action) -> str:
return ', '.join(action.option_strings) + ' ' + args_string
# End cmd2 customization

# noinspection PyMethodMayBeStatic
def _determine_metavar(self, action, default_metavar) -> Union[str, Tuple]:
"""Custom method to determine what to use as the metavar value of an action"""
if action.metavar is not None:
Expand Down
8 changes: 8 additions & 0 deletions cmd2/cmd2.py
Original file line number Diff line number Diff line change
Expand Up @@ -692,6 +692,14 @@ def find_subcommand(action: argparse.ArgumentParser, subcmd_names: List[str]) ->

for action in target_parser._actions:
if isinstance(action, argparse._SubParsersAction):
# Temporary workaround for avoiding subcommand help text repeatedly getting added to
# action._choices_actions. Until we have instance-specific parser objects, we will remove
# any existing subcommand which has the same name before replacing it. This problem is
# exercised when more than one cmd2.Cmd-based object is created and the same subcommands
# get added each time. Argparse overwrites the previous subcommand but keeps growing the help
# text which is shown by running something like 'alias -h'.
action.remove_parser(subcommand_name)

# Get the kwargs for add_parser()
add_parser_kwargs = getattr(method, constants.SUBCMD_ATTR_ADD_PARSER_KWARGS, {})

Expand Down

0 comments on commit c36569c

Please sign in to comment.