Skip to content

Fixed duplicate help text of subcommands #1005

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Oct 1, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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