diff options
Diffstat (limited to 'cmd2')
-rw-r--r-- | cmd2/argparse_custom.py | 2 | ||||
-rw-r--r-- | cmd2/cmd2.py | 34 | ||||
-rw-r--r-- | cmd2/constants.py | 3 | ||||
-rw-r--r-- | cmd2/decorators.py | 23 |
4 files changed, 35 insertions, 27 deletions
diff --git a/cmd2/argparse_custom.py b/cmd2/argparse_custom.py index 689c1db7..9dde5347 100644 --- a/cmd2/argparse_custom.py +++ b/cmd2/argparse_custom.py @@ -774,7 +774,7 @@ class Cmd2ArgumentParser(argparse.ArgumentParser): allow_abbrev=allow_abbrev) self.register('action', 'unloadable_parsers', _UnloadableSubParsersAction) - def add_subparsers(self, unloadable=False, **kwargs): + def add_subparsers(self, unloadable: bool = False, **kwargs): """ Custom override. Sets a default title if one was not given. diff --git a/cmd2/cmd2.py b/cmd2/cmd2.py index ea590fac..e15a856e 100644 --- a/cmd2/cmd2.py +++ b/cmd2/cmd2.py @@ -527,14 +527,14 @@ class Cmd(cmd.Cmd): def _register_subcommands(self, cmdset: Union[CommandSet, 'Cmd']) -> None: """ - Register sub-commands with their base command + Register subcommands with their base command - :param cmdset: CommandSet containing sub-commands + :param cmdset: CommandSet containing subcommands """ if not (cmdset is self or cmdset in self._installed_command_sets): - raise ValueError('Adding sub-commands from an unregistered CommandSet') + raise ValueError('Adding subcommands from an unregistered CommandSet') - # find all methods that start with the sub-command prefix + # find all methods that start with the subcommand prefix methods = inspect.getmembers( cmdset, predicate=lambda meth: (inspect.ismethod(meth) or isinstance(meth, Callable)) @@ -548,22 +548,18 @@ class Cmd(cmd.Cmd): subcommand_name = getattr(method, constants.SUBCMD_ATTR_NAME) command_name = getattr(method, constants.SUBCMD_ATTR_COMMAND) subcmd_parser = getattr(method, constants.CMD_ATTR_ARGPARSER) + parser_args = getattr(method, constants.SUBCMD_ATTR_PARSER_ARGS, {}) # Search for the base command function and verify it has an argparser defined command_func = self.cmd_func(command_name) if command_func is None or not hasattr(command_func, constants.CMD_ATTR_ARGPARSER): - raise TypeError('Could not find command "{}" needed by sub-command: {}' + raise TypeError('Could not find command "{}" needed by subcommand: {}' .format(command_name, str(method))) command_parser = getattr(command_func, constants.CMD_ATTR_ARGPARSER) if command_parser is None: - raise TypeError('Could not find argparser for command "{}" needed by sub-command: {}' + raise TypeError('Could not find argparser for command "{}" needed by subcommand: {}' .format(command_name, str(method))) - if hasattr(method, '__doc__') and method.__doc__ is not None: - help_text = method.__doc__.splitlines()[0] - else: - help_text = subcommand_name - if isinstance(cmdset, CommandSet): command_handler = _partial_passthru(method, self) else: @@ -572,18 +568,18 @@ class Cmd(cmd.Cmd): for action in command_parser._actions: if isinstance(action, _UnloadableSubParsersAction): - action.add_parser(subcommand_name, parents=[subcmd_parser], help=help_text) + action.add_parser(subcommand_name, parents=[subcmd_parser], **parser_args) def _unregister_subcommands(self, cmdset: Union[CommandSet, 'Cmd']) -> None: """ - Unregister sub-commands from their base command + Unregister subcommands from their base command - :param cmdset: CommandSet containing sub-commands + :param cmdset: CommandSet containing subcommands """ if not (cmdset is self or cmdset in self._installed_command_sets): - raise ValueError('Removing sub-commands from an unregistered CommandSet') + raise ValueError('Removing subcommands from an unregistered CommandSet') - # find all methods that start with the sub-command prefix + # find all methods that start with the subcommand prefix methods = inspect.getmembers( cmdset, predicate=lambda meth: (inspect.ismethod(meth) or isinstance(meth, Callable)) @@ -600,11 +596,11 @@ class Cmd(cmd.Cmd): # Search for the base command function and verify it has an argparser defined command_func = self.cmd_func(command_name) if command_func is None or not hasattr(command_func, constants.CMD_ATTR_ARGPARSER): - raise TypeError('Could not find command "{}" needed by sub-command: {}' + raise TypeError('Could not find command "{}" needed by subcommand: {}' .format(command_name, str(method))) command_parser = getattr(command_func, constants.CMD_ATTR_ARGPARSER) if command_parser is None: - raise TypeError('Could not find argparser for command "{}" needed by sub-command: {}' + raise TypeError('Could not find argparser for command "{}" needed by subcommand: {}' .format(command_name, str(method))) for action in command_parser._actions: @@ -3387,7 +3383,7 @@ class Cmd(cmd.Cmd): if 'gnureadline' in sys.modules: # Restore what the readline module pointed to if cmd2_env.readline_module is None: - del (sys.modules['readline']) + del sys.modules['readline'] else: sys.modules['readline'] = cmd2_env.readline_module diff --git a/cmd2/constants.py b/cmd2/constants.py index 0135e328..88a1bb82 100644 --- a/cmd2/constants.py +++ b/cmd2/constants.py @@ -50,6 +50,7 @@ CMD_ATTR_ARGPARSER = 'argparser' # Whether or not tokens are unquoted before sending to argparse CMD_ATTR_PRESERVE_QUOTES = 'preserve_quotes' -# sub-command attributes for the base command name and the sub-command name +# subcommand attributes for the base command name and the subcommand name SUBCMD_ATTR_COMMAND = 'parent_command' SUBCMD_ATTR_NAME = 'subcommand_name' +SUBCMD_ATTR_PARSER_ARGS = 'subcommand_parser_args' diff --git a/cmd2/decorators.py b/cmd2/decorators.py index 6e3b7acf..82ad8cd7 100644 --- a/cmd2/decorators.py +++ b/cmd2/decorators.py @@ -1,7 +1,7 @@ # coding=utf-8 """Decorators for ``cmd2`` commands""" import argparse -from typing import TYPE_CHECKING, Any, Callable, Dict, List, Optional, Tuple, Union +from typing import TYPE_CHECKING, Any, Callable, Dict, Iterable, List, Optional, Tuple, Union from . import constants from .exceptions import Cmd2ArgparseError @@ -339,13 +339,18 @@ def with_argparser(parser: argparse.ArgumentParser, *, def as_subcommand_to(command: str, subcommand: str, - parser: argparse.ArgumentParser) -> Callable[[argparse.Namespace], Optional[bool]]: + parser: argparse.ArgumentParser, + *, + help_text: Optional[str] = None, + aliases: Iterable[str] = None) -> Callable[[argparse.Namespace], Optional[bool]]: """ - Tag this method as a sub-command to an existing argparse decorated command. + Tag this method as a subcommand to an existing argparse decorated command. :param command: Command Name - :param subcommand: Sub-command name - :param parser: argparse Parser to for this sub-command + :param subcommand: Subcommand name + :param parser: argparse Parser for this subcommand + :param help_text: Help message for this subcommand + :param aliases: Alternative names for this subcommand :return: Wrapper function that can receive an argparse.Namespace """ def arg_decorator(func: Callable): @@ -357,10 +362,16 @@ def as_subcommand_to(command: str, parser.set_defaults(func=func) - # # Set some custom attributes for this command + # Set some custom attributes for this command setattr(func, constants.SUBCMD_ATTR_COMMAND, command) setattr(func, constants.CMD_ATTR_ARGPARSER, parser) setattr(func, constants.SUBCMD_ATTR_NAME, subcommand) + parser_args = {} + if help_text is not None: + parser_args['help'] = help_text + if aliases is not None: + parser_args['aliases'] = aliases[:] + setattr(func, constants.SUBCMD_ATTR_PARSER_ARGS, parser_args) return func |