diff options
author | Eric Lin <anselor@gmail.com> | 2020-07-30 01:32:29 -0400 |
---|---|---|
committer | anselor <anselor@gmail.com> | 2020-08-04 13:38:08 -0400 |
commit | dac009f17c58df4b8d4dbcd3c621bf6ef2481a96 (patch) | |
tree | 24f2ff3cc3897ac247a290dbdc5a518e734661aa | |
parent | 105369bdd15c2067b3ee6bdd6a737733a34c38ef (diff) | |
download | cmd2-git-dac009f17c58df4b8d4dbcd3c621bf6ef2481a96.tar.gz |
Removed sub-class and instead patch argparse._SubParsersAction
-rw-r--r-- | cmd2/argparse_custom.py | 50 | ||||
-rw-r--r-- | cmd2/cmd2.py | 6 | ||||
-rw-r--r-- | isolated_tests/test_commandset/test_commandset.py | 2 |
3 files changed, 30 insertions, 28 deletions
diff --git a/cmd2/argparse_custom.py b/cmd2/argparse_custom.py index 9dde5347..6cfa66ae 100644 --- a/cmd2/argparse_custom.py +++ b/cmd2/argparse_custom.py @@ -528,6 +528,31 @@ def _match_argument_wrapper(self, action, arg_strings_pattern) -> int: # noinspection PyProtectedMember argparse.ArgumentParser._match_argument = _match_argument_wrapper + +############################################################################################################ +# Patch argparse._SubParsersAction to add remove_parser function +############################################################################################################ + +def _SubParsersAction_remove_parser(self, name): + """Removes a sub-parser from the sub-parsers group""" + 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] + + +# noinspection PyProtectedMember +setattr(argparse._SubParsersAction, 'remove_parser', _SubParsersAction_remove_parser) + + ############################################################################################################ # Unless otherwise noted, everything below this point are copied from Python's # argparse implementation with minor tweaks to adjust output. @@ -724,24 +749,6 @@ class Cmd2HelpFormatter(argparse.RawTextHelpFormatter): return result -class _UnloadableSubParsersAction(argparse._SubParsersAction): - """Extends the argparse internal SubParsers action to allow sub-parsers to be removed dynamically""" - def remove_parser(self, name): - """Removes a sub-parser from the sub-parsers group""" - 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] - - # noinspection PyCompatibility class Cmd2ArgumentParser(argparse.ArgumentParser): """Custom ArgumentParser class that improves error and help output""" @@ -772,22 +779,17 @@ class Cmd2ArgumentParser(argparse.ArgumentParser): conflict_handler=conflict_handler, add_help=add_help, allow_abbrev=allow_abbrev) - self.register('action', 'unloadable_parsers', _UnloadableSubParsersAction) - def add_subparsers(self, unloadable: bool = False, **kwargs): + def add_subparsers(self, **kwargs): """ Custom override. Sets a default title if one was not given. - :param unloadable: Flag whether this sub-parsers group will support unloading parsers :param kwargs: additional keyword arguments :return: argparse Subparser Action """ if 'title' not in kwargs: kwargs['title'] = 'subcommands' - if unloadable: - kwargs['action'] = 'unloadable_parsers' - return super().add_subparsers(**kwargs) def error(self, message: str) -> None: diff --git a/cmd2/cmd2.py b/cmd2/cmd2.py index e15a856e..c933db99 100644 --- a/cmd2/cmd2.py +++ b/cmd2/cmd2.py @@ -43,7 +43,7 @@ from contextlib import redirect_stdout from typing import Any, Callable, Dict, Iterable, List, Mapping, Optional, Tuple, Type, Union from . import ansi, constants, plugin, utils -from .argparse_custom import DEFAULT_ARGUMENT_PARSER, CompletionItem, _UnloadableSubParsersAction +from .argparse_custom import DEFAULT_ARGUMENT_PARSER, CompletionItem from .clipboard import can_clip, get_paste_buffer, write_to_paste_buffer from .command_definition import CommandSet, _partial_passthru from .constants import COMMAND_FUNC_PREFIX, COMPLETER_FUNC_PREFIX, HELP_FUNC_PREFIX @@ -567,7 +567,7 @@ class Cmd(cmd.Cmd): subcmd_parser.set_defaults(handler=command_handler) for action in command_parser._actions: - if isinstance(action, _UnloadableSubParsersAction): + if isinstance(action, argparse._SubParsersAction): action.add_parser(subcommand_name, parents=[subcmd_parser], **parser_args) def _unregister_subcommands(self, cmdset: Union[CommandSet, 'Cmd']) -> None: @@ -604,7 +604,7 @@ class Cmd(cmd.Cmd): .format(command_name, str(method))) for action in command_parser._actions: - if isinstance(action, _UnloadableSubParsersAction): + if isinstance(action, argparse._SubParsersAction): action.remove_parser(subcommand_name) def add_settable(self, settable: Settable) -> None: diff --git a/isolated_tests/test_commandset/test_commandset.py b/isolated_tests/test_commandset/test_commandset.py index 98385772..f16a6ff4 100644 --- a/isolated_tests/test_commandset/test_commandset.py +++ b/isolated_tests/test_commandset/test_commandset.py @@ -272,7 +272,7 @@ class LoadableBase(cmd2.CommandSet): self._dummy = dummy # prevents autoload cut_parser = cmd2.Cmd2ArgumentParser('cut') - cut_subparsers = cut_parser.add_subparsers(title='item', help='item to cut', unloadable=True) + cut_subparsers = cut_parser.add_subparsers(title='item', help='item to cut') @cmd2.with_argparser(cut_parser) def do_cut(self, ns: argparse.Namespace): |