diff options
-rw-r--r-- | CHANGELOG.md | 5 | ||||
-rw-r--r-- | cmd2/argparse_completer.py | 3 | ||||
-rw-r--r-- | cmd2/argparse_custom.py | 11 | ||||
-rw-r--r-- | cmd2/cmd2.py | 31 | ||||
-rw-r--r-- | cmd2/command_definition.py | 35 | ||||
-rw-r--r-- | cmd2/decorators.py | 14 | ||||
-rw-r--r-- | docs/features/modular_commands.rst | 69 | ||||
-rw-r--r-- | examples/modular_commands/commandset_basic.py | 10 | ||||
-rw-r--r-- | examples/modular_commands/commandset_complex.py | 32 | ||||
-rw-r--r-- | examples/modular_commands/commandset_custominit.py | 4 | ||||
-rw-r--r-- | examples/modular_commands_basic.py | 8 | ||||
-rw-r--r-- | examples/modular_commands_dynamic.py | 24 | ||||
-rw-r--r-- | examples/modular_subcommands.py | 24 | ||||
-rw-r--r-- | tests_isolated/test_commandset/test_argparse_subcommands.py | 16 | ||||
-rw-r--r-- | tests_isolated/test_commandset/test_commandset.py | 231 |
15 files changed, 229 insertions, 288 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index ef2745d3..6c835259 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,9 @@ ## 1.3.3 (TBD) +* Breaking changes + * CommandSet command functions (do_, complete_, help_) will no longer have the cmd2 app + passed in as the first parameter after `self` since this is already a class member. + * Renamed `install_command_set()` and `uninstall_command_set()` to `register_command_set()` and + `unregister_command_set()` for better name consistency. * Bug Fixes * Added explicit testing against python 3.5.2 for Ubuntu 16.04, and 3.5.3 for Debian 9 * Added fallback definition of typing.Deque (taken from 3.5.4) diff --git a/cmd2/argparse_completer.py b/cmd2/argparse_completer.py index f14e83fd..77fa41b8 100644 --- a/cmd2/argparse_completer.py +++ b/cmd2/argparse_completer.py @@ -606,7 +606,8 @@ class ArgparseCompleter: # No cases matched, raise an error raise CompletionError('Could not find CommandSet instance matching defining type for completer') args.append(cmd_set) - args.append(self._cmd2_app) + else: + args.append(self._cmd2_app) # Check if arg_choices.to_call expects arg_tokens to_call_params = inspect.signature(arg_choices.to_call).parameters diff --git a/cmd2/argparse_custom.py b/cmd2/argparse_custom.py index 5dbb9f66..d724cb88 100644 --- a/cmd2/argparse_custom.py +++ b/cmd2/argparse_custom.py @@ -68,9 +68,9 @@ If bound to a cmd2.Cmd subclass, it will pass the app instance as the `self` argument. This is good in cases where the list of choices being generated relies on state data of the cmd2-based app. If bound to a cmd2.CommandSet subclass, it will pass the CommandSet instance -as the `self` argument, and the app instance as the positional argument. +as the `self` argument. - Example bound to cmd2.Cmd:: + Example:: def my_choices_method(self): ... @@ -78,13 +78,6 @@ as the `self` argument, and the app instance as the positional argument. parser.add_argument("arg", choices_method=my_choices_method) - Example bound to cmd2.CommandSEt:: - - def my_choices_method(self, app: cmd2.Cmd): - ... - return my_generated_list - - parser.add_argument("arg", choices_method=my_choices_method) ``completer_function`` - pass a tab completion function that does custom completion. Since custom tab completion operations commonly need to modify diff --git a/cmd2/cmd2.py b/cmd2/cmd2.py index 621228db..30dcb6e8 100644 --- a/cmd2/cmd2.py +++ b/cmd2/cmd2.py @@ -45,7 +45,7 @@ from typing import Any, Callable, Dict, Iterable, List, Mapping, Optional, Tuple from . import ansi, constants, plugin, utils 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 .command_definition import CommandSet from .constants import COMMAND_FUNC_PREFIX, COMPLETER_FUNC_PREFIX, HELP_FUNC_PREFIX from .decorators import with_argparser, as_subcommand_to from .exceptions import ( @@ -186,7 +186,7 @@ class Cmd(cmd.Cmd): :param auto_load_commands: If True, cmd2 will check for all subclasses of `CommandSet` that are currently loaded by Python and automatically instantiate and register all commands. If False, CommandSets - must be manually installed with `install_command_set`. + must be manually installed with `register_command_set`. """ # If use_ipython is False, make sure the ipy command isn't available in this instance if not use_ipython: @@ -264,7 +264,7 @@ class Cmd(cmd.Cmd): self._cmd_to_command_sets = {} # type: Dict[str, CommandSet] if command_sets: for command_set in command_sets: - self.install_command_set(command_set) + self.register_command_set(command_set) if auto_load_commands: self._autoload_commands() @@ -452,11 +452,11 @@ class Cmd(cmd.Cmd): or len(init_sig.parameters) != 1 or 'self' not in init_sig.parameters): cmdset = cmdset_type() - self.install_command_set(cmdset) + self.register_command_set(cmdset) load_commandset_by_type(all_commandset_defs) - def install_command_set(self, cmdset: CommandSet) -> None: + def register_command_set(self, cmdset: CommandSet) -> None: """ Installs a CommandSet, loading all commands defined in the CommandSet @@ -476,23 +476,20 @@ class Cmd(cmd.Cmd): try: for method_name, method in methods: command = method_name[len(COMMAND_FUNC_PREFIX):] - command_wrapper = _partial_passthru(method, self) - self._install_command_function(command, command_wrapper, type(cmdset).__name__) + self._install_command_function(command, method, type(cmdset).__name__) installed_attributes.append(method_name) completer_func_name = COMPLETER_FUNC_PREFIX + command cmd_completer = getattr(cmdset, completer_func_name, None) if cmd_completer is not None: - completer_wrapper = _partial_passthru(cmd_completer, self) - self._install_completer_function(command, completer_wrapper) + self._install_completer_function(command, cmd_completer) installed_attributes.append(completer_func_name) help_func_name = HELP_FUNC_PREFIX + command cmd_help = getattr(cmdset, help_func_name, None) if cmd_help is not None: - help_wrapper = _partial_passthru(cmd_help, self) - self._install_help_function(command, help_wrapper) + self._install_help_function(command, cmd_help) installed_attributes.append(help_func_name) self._cmd_to_command_sets[command] = cmdset @@ -508,7 +505,7 @@ class Cmd(cmd.Cmd): if cmdset in self._cmd_to_command_sets.values(): self._cmd_to_command_sets = \ {key: val for key, val in self._cmd_to_command_sets.items() if val is not cmdset} - cmdset.on_unregister(self) + cmdset.on_unregister() raise def _install_command_function(self, command: str, command_wrapper: Callable, context=''): @@ -549,7 +546,7 @@ class Cmd(cmd.Cmd): raise CommandSetRegistrationError('Attribute already exists: {}'.format(help_func_name)) setattr(self, help_func_name, cmd_help) - def uninstall_command_set(self, cmdset: CommandSet): + def unregister_command_set(self, cmdset: CommandSet): """ Uninstalls a CommandSet and unloads all associated commands :param cmdset: CommandSet to uninstall @@ -581,7 +578,7 @@ class Cmd(cmd.Cmd): if hasattr(self, HELP_FUNC_PREFIX + cmd_name): delattr(self, HELP_FUNC_PREFIX + cmd_name) - cmdset.on_unregister(self) + cmdset.on_unregister() self._installed_command_sets.remove(cmdset) def _check_uninstallable(self, cmdset: CommandSet): @@ -656,11 +653,7 @@ class Cmd(cmd.Cmd): raise CommandSetRegistrationError('Could not find argparser for command "{}" needed by subcommand: {}' .format(command_name, str(method))) - if isinstance(cmdset, CommandSet): - command_handler = _partial_passthru(method, self) - else: - command_handler = method - subcmd_parser.set_defaults(cmd2_handler=command_handler) + subcmd_parser.set_defaults(cmd2_handler=method) def find_subcommand(action: argparse.ArgumentParser, subcmd_names: List[str]) -> argparse.ArgumentParser: if not subcmd_names: diff --git a/cmd2/command_definition.py b/cmd2/command_definition.py index 22d8915e..86f1151a 100644 --- a/cmd2/command_definition.py +++ b/cmd2/command_definition.py @@ -18,36 +18,6 @@ except ImportError: # pragma: no cover pass -def _partial_passthru(func: Callable, *args, **kwargs) -> functools.partial: - """ - Constructs a partial function that passes arguments through to the wrapped function. - Must construct a new type every time so that each wrapped function's __doc__ can be copied correctly. - - :param func: wrapped function - :param args: positional arguments - :param kwargs: keyword arguments - :return: partial function that exposes attributes of wrapped function - """ - def __getattr__(self, item): - return getattr(self.func, item) - - def __setattr__(self, key, value): - return setattr(self.func, key, value) - - def __dir__(self) -> Iterable[str]: - return dir(self.func) - - passthru_type = type('PassthruPartial' + func.__name__, - (functools.partial,), - { - '__getattr__': __getattr__, - '__setattr__': __setattr__, - '__dir__': __dir__, - }) - passthru_type.__doc__ = func.__doc__ - return passthru_type(func, *args, **kwargs) - - def with_default_category(category: str): """ Decorator that applies a category to all ``do_*`` command methods in a class that do not already @@ -78,8 +48,7 @@ class CommandSet(object): ``with_default_category`` can be used to apply a default category to all commands in the CommandSet. - ``do_``, ``help_``, and ``complete_`` functions differ only in that they're now required to accept - a reference to ``cmd2.Cmd`` as the first argument after self. + ``do_``, ``help_``, and ``complete_`` functions differ only in that self is the CommandSet instead of the cmd2 app """ def __init__(self): @@ -98,7 +67,7 @@ class CommandSet(object): else: raise CommandSetRegistrationError('This CommandSet has already been registered') - def on_unregister(self, cmd): + def on_unregister(self): """ Called by ``cmd2.Cmd`` when a CommandSet is unregistered and removed. diff --git a/cmd2/decorators.py b/cmd2/decorators.py index 0dda3485..7c20af68 100644 --- a/cmd2/decorators.py +++ b/cmd2/decorators.py @@ -41,7 +41,7 @@ def with_category(category: str) -> Callable: ########################## -def _parse_positionals(args: Tuple) -> Tuple['cmd2.Cmd', Union[Statement, str]]: +def _parse_positionals(args: Tuple) -> Tuple[Union['cmd2.Cmd', 'cmd2.CommandSet'], Union[Statement, str]]: """ Helper function for cmd2 decorators to inspect the positional arguments until the cmd2.Cmd argument is found Assumes that we will find cmd2.Cmd followed by the command statement object or string. @@ -49,8 +49,10 @@ def _parse_positionals(args: Tuple) -> Tuple['cmd2.Cmd', Union[Statement, str]]: :return: The cmd2.Cmd reference and the command line statement """ for pos, arg in enumerate(args): - from cmd2 import Cmd - if isinstance(arg, Cmd) and len(args) > pos: + from cmd2 import Cmd, CommandSet + if (isinstance(arg, Cmd) or isinstance(arg, CommandSet)) and len(args) > pos: + if isinstance(arg, CommandSet): + arg = arg._cmd next_arg = args[pos + 1] if isinstance(next_arg, (Statement, str)): return arg, args[pos + 1] @@ -92,7 +94,7 @@ def with_argument_list(*args: List[Callable], preserve_quotes: bool = False) -> >>> def do_echo(self, arglist): >>> self.poutput(' '.join(arglist) """ - import functools + import functools, cmd2 def arg_decorator(func: Callable): @functools.wraps(func) @@ -293,8 +295,8 @@ def with_argparser(parser: argparse.ArgumentParser, *, else: setattr(ns, '__statement__', statement) - def get_handler(self: argparse.Namespace) -> Optional[Callable]: - return getattr(self, constants.SUBCMD_HANDLER, None) + def get_handler(ns_self: argparse.Namespace) -> Optional[Callable]: + return getattr(ns_self, constants.SUBCMD_HANDLER, None) setattr(ns, 'get_handler', types.MethodType(get_handler, ns)) diff --git a/docs/features/modular_commands.rst b/docs/features/modular_commands.rst index d19c3b45..dddd996e 100644 --- a/docs/features/modular_commands.rst +++ b/docs/features/modular_commands.rst @@ -42,8 +42,9 @@ A new decorator ``with_default_category`` is provided to categorize all commands same command category. Individual commands in a CommandSet may be override the default category by specifying a specific category with ``cmd.with_category``. -CommandSet methods will always expect ``self``, and ``cmd2.Cmd`` as the first two parameters. The parameters that -follow will depend on the specific command decorator being used. +CommandSet command methods will always expect the same parameters as when defined in a ``cmd2.Cmd`` sub-class, +except that ``self`` will now refer to the ``CommandSet`` instead of the cmd2 instance. The cmd2 instance can +be accessed through ``self._cmd`` that is populated when the ``CommandSet`` is registered. CommandSets will only be auto-loaded if the constructor takes no arguments. If you need to provide constructor arguments, see :ref:`features/modular_commands:Manual CommandSet Construction` @@ -58,11 +59,11 @@ If you need to provide constructor arguments, see :ref:`features/modular_command def __init__(self): super().__init__() - def do_hello(self, cmd: cmd2.Cmd, _: cmd2.Statement): - cmd.poutput('Hello') + def do_hello(self, _: cmd2.Statement): + self._cmd.poutput('Hello') - def do_world(self, cmd: cmd2.Cmd, _: cmd2.Statement): - cmd.poutput('World') + def do_world(self, _: cmd2.Statement): + self._cmd.poutput('World') class ExampleApp(cmd2.Cmd): """ @@ -94,11 +95,11 @@ CommandSets and pass in the constructor to Cmd2. self._arg1 = arg1 self._arg2 = arg2 - def do_show_arg1(self, cmd: cmd2.Cmd, _: cmd2.Statement): - cmd.poutput('Arg1: ' + self._arg1) + def do_show_arg1(self, _: cmd2.Statement): + self._cmd.poutput('Arg1: ' + self._arg1) - def do_show_arg2(self, cmd: cmd2.Cmd, _: cmd2.Statement): - cmd.poutput('Arg2: ' + self._arg2) + def do_show_arg2(self, _: cmd2.Statement): + self._cmd.poutput('Arg2: ' + self._arg2) class ExampleApp(cmd2.Cmd): """ @@ -139,11 +140,11 @@ You may need to disable command auto-loading if you need dynamically load comman def __init__(self): super().__init__() - def do_apple(self, cmd: cmd2.Cmd, _: cmd2.Statement): - cmd.poutput('Apple') + def do_apple(self, _: cmd2.Statement): + self._cmd.poutput('Apple') - def do_banana(self, cmd: cmd2.Cmd, _: cmd2.Statement): - cmd.poutput('Banana') + def do_banana(self, _: cmd2.Statement): + self._cmd.poutput('Banana') @with_default_category('Vegetables') @@ -151,11 +152,11 @@ You may need to disable command auto-loading if you need dynamically load comman def __init__(self): super().__init__() - def do_arugula(self, cmd: cmd2.Cmd, _: cmd2.Statement): - cmd.poutput('Arugula') + def do_arugula(self, _: cmd2.Statement): + self._cmd.poutput('Arugula') - def do_bokchoy(self, cmd: cmd2.Cmd, _: cmd2.Statement): - cmd.poutput('Bok Choy') + def do_bokchoy(self, _: cmd2.Statement): + self._cmd.poutput('Bok Choy') class ExampleApp(cmd2.Cmd): @@ -178,14 +179,14 @@ You may need to disable command auto-loading if you need dynamically load comman def do_load(self, ns: argparse.Namespace): if ns.cmds == 'fruits': try: - self.install_command_set(self._fruits) + self.register_command_set(self._fruits) self.poutput('Fruits loaded') except ValueError: self.poutput('Fruits already loaded') if ns.cmds == 'vegetables': try: - self.install_command_set(self._vegetables) + self.register_command_set(self._vegetables) self.poutput('Vegetables loaded') except ValueError: self.poutput('Vegetables already loaded') @@ -193,11 +194,11 @@ You may need to disable command auto-loading if you need dynamically load comman @with_argparser(load_parser) def do_unload(self, ns: argparse.Namespace): if ns.cmds == 'fruits': - self.uninstall_command_set(self._fruits) + self.unregister_command_set(self._fruits) self.poutput('Fruits unloaded') if ns.cmds == 'vegetables': - self.uninstall_command_set(self._vegetables) + self.unregister_command_set(self._vegetables) self.poutput('Vegetables unloaded') @@ -240,16 +241,16 @@ command and each CommandSet def __init__(self): super().__init__() - def do_apple(self, cmd: cmd2.Cmd, _: cmd2.Statement): - cmd.poutput('Apple') + def do_apple(self, _: cmd2.Statement): + self._cmd.poutput('Apple') banana_parser = cmd2.Cmd2ArgumentParser(add_help=False) banana_parser.add_argument('direction', choices=['discs', 'lengthwise']) @cmd2.as_subcommand_to('cut', 'banana', banana_parser) - def cut_banana(self, cmd: cmd2.Cmd, ns: argparse.Namespace): + def cut_banana(self, ns: argparse.Namespace): """Cut banana""" - cmd.poutput('cutting banana: ' + ns.direction) + self._cmd.poutput('cutting banana: ' + ns.direction) @with_default_category('Vegetables') @@ -257,15 +258,15 @@ command and each CommandSet def __init__(self): super().__init__() - def do_arugula(self, cmd: cmd2.Cmd, _: cmd2.Statement): - cmd.poutput('Arugula') + def do_arugula(self, _: cmd2.Statement): + self._cmd.poutput('Arugula') bokchoy_parser = cmd2.Cmd2ArgumentParser(add_help=False) bokchoy_parser.add_argument('style', choices=['quartered', 'diced']) @cmd2.as_subcommand_to('cut', 'bokchoy', bokchoy_parser) - def cut_bokchoy(self, cmd: cmd2.Cmd, _: cmd2.Statement): - cmd.poutput('Bok Choy') + def cut_bokchoy(self, _: cmd2.Statement): + self._cmd.poutput('Bok Choy') class ExampleApp(cmd2.Cmd): @@ -288,14 +289,14 @@ command and each CommandSet def do_load(self, ns: argparse.Namespace): if ns.cmds == 'fruits': try: - self.install_command_set(self._fruits) + self.register_command_set(self._fruits) self.poutput('Fruits loaded') except ValueError: self.poutput('Fruits already loaded') if ns.cmds == 'vegetables': try: - self.install_command_set(self._vegetables) + self.register_command_set(self._vegetables) self.poutput('Vegetables loaded') except ValueError: self.poutput('Vegetables already loaded') @@ -303,11 +304,11 @@ command and each CommandSet @with_argparser(load_parser) def do_unload(self, ns: argparse.Namespace): if ns.cmds == 'fruits': - self.uninstall_command_set(self._fruits) + self.unregister_command_set(self._fruits) self.poutput('Fruits unloaded') if ns.cmds == 'vegetables': - self.uninstall_command_set(self._vegetables) + self.unregister_command_set(self._vegetables) self.poutput('Vegetables unloaded') cut_parser = cmd2.Cmd2ArgumentParser('cut') diff --git a/examples/modular_commands/commandset_basic.py b/examples/modular_commands/commandset_basic.py index 105530e8..2ceda439 100644 --- a/examples/modular_commands/commandset_basic.py +++ b/examples/modular_commands/commandset_basic.py @@ -30,7 +30,7 @@ class BasicCompletionCommandSet(CommandSet): -s, --sport [completes sports] -p, --path [completes local file system paths] """ - cmd.poutput("Args: {}".format(statement.args)) + self._cmd.poutput("Args: {}".format(statement.args)) def complete_flag_based(self, cmd: Cmd, text: str, line: str, begidx: int, endidx: int) -> List[str]: """Completion function for do_flag_based""" @@ -53,7 +53,7 @@ class BasicCompletionCommandSet(CommandSet): def do_index_based(self, cmd: Cmd, statement: Statement): """Tab completes first 3 arguments using index_based_complete""" - cmd.poutput("Args: {}".format(statement.args)) + self._cmd.poutput("Args: {}".format(statement.args)) def complete_index_based(self, cmd: Cmd, text: str, line: str, begidx: int, endidx: int) -> List[str]: """Completion function for do_index_based""" @@ -68,14 +68,14 @@ class BasicCompletionCommandSet(CommandSet): def do_delimiter_complete(self, cmd: Cmd, statement: Statement): """Tab completes files from a list using delimiter_complete""" - cmd.poutput("Args: {}".format(statement.args)) + self._cmd.poutput("Args: {}".format(statement.args)) def complete_delimiter_complete(self, cmd: Cmd, text: str, line: str, begidx: int, endidx: int) -> List[str]: return cmd.delimiter_complete(text, line, begidx, endidx, match_against=self.file_strs, delimiter='/') def do_raise_error(self, cmd: Cmd, statement: Statement): """Demonstrates effect of raising CompletionError""" - cmd.poutput("Args: {}".format(statement.args)) + self._cmd.poutput("Args: {}".format(statement.args)) def complete_raise_error(self, cmd: Cmd, text: str, line: str, begidx: int, endidx: int) -> List[str]: """ @@ -89,4 +89,4 @@ class BasicCompletionCommandSet(CommandSet): @with_category('Not Basic Completion') def do_custom_category(self, cmd: Cmd, statement: Statement): - cmd.poutput('Demonstrates a command that bypasses the default category') + self._cmd.poutput('Demonstrates a command that bypasses the default category') diff --git a/examples/modular_commands/commandset_complex.py b/examples/modular_commands/commandset_complex.py index ec5a9e13..7c6b1300 100644 --- a/examples/modular_commands/commandset_complex.py +++ b/examples/modular_commands/commandset_complex.py @@ -13,35 +13,35 @@ from cmd2 import utils @cmd2.with_default_category('Fruits') class CommandSetA(cmd2.CommandSet): - def do_apple(self, cmd: cmd2.Cmd, statement: cmd2.Statement): - cmd.poutput('Apple!') + def do_apple(self, statement: cmd2.Statement): + self._cmd.poutput('Apple!') - def do_banana(self, cmd: cmd2.Cmd, statement: cmd2.Statement): + def do_banana(self, statement: cmd2.Statement): """Banana Command""" - cmd.poutput('Banana!!') + self._cmd.poutput('Banana!!') cranberry_parser = cmd2.Cmd2ArgumentParser('cranberry') cranberry_parser.add_argument('arg1', choices=['lemonade', 'juice', 'sauce']) @cmd2.with_argparser(cranberry_parser, with_unknown_args=True) - def do_cranberry(self, cmd: cmd2.Cmd, ns: argparse.Namespace, unknown: List[str]): - cmd.poutput('Cranberry {}!!'.format(ns.arg1)) + def do_cranberry(self, ns: argparse.Namespace, unknown: List[str]): + self._cmd.poutput('Cranberry {}!!'.format(ns.arg1)) if unknown and len(unknown): - cmd.poutput('Unknown: ' + ', '.join(['{}']*len(unknown)).format(*unknown)) - cmd.last_result = {'arg1': ns.arg1, + self._cmd.poutput('Unknown: ' + ', '.join(['{}']*len(unknown)).format(*unknown)) + self._cmd.last_result = {'arg1': ns.arg1, 'unknown': unknown} - def help_cranberry(self, cmd: cmd2.Cmd): - cmd.stdout.write('This command does diddly squat...\n') + def help_cranberry(self): + self._cmd.stdout.write('This command does diddly squat...\n') @cmd2.with_argument_list @cmd2.with_category('Also Alone') - def do_durian(self, cmd: cmd2.Cmd, args: List[str]): + def do_durian(self, args: List[str]): """Durian Command""" - cmd.poutput('{} Arguments: '.format(len(args))) - cmd.poutput(', '.join(['{}']*len(args)).format(*args)) + self._cmd.poutput('{} Arguments: '.format(len(args))) + self._cmd.poutput(', '.join(['{}']*len(args)).format(*args)) - def complete_durian(self, cmd: cmd2.Cmd, text: str, line: str, begidx: int, endidx: int) -> List[str]: + def complete_durian(self, text: str, line: str, begidx: int, endidx: int) -> List[str]: return utils.basic_complete(text, line, begidx, endidx, ['stinks', 'smells', 'disgusting']) elderberry_parser = cmd2.Cmd2ArgumentParser('elderberry') @@ -49,5 +49,5 @@ class CommandSetA(cmd2.CommandSet): @cmd2.with_category('Alone') @cmd2.with_argparser(elderberry_parser) - def do_elderberry(self, cmd: cmd2.Cmd, ns: argparse.Namespace): - cmd.poutput('Elderberry {}!!'.format(ns.arg1)) + def do_elderberry(self, ns: argparse.Namespace): + self._cmd.poutput('Elderberry {}!!'.format(ns.arg1)) diff --git a/examples/modular_commands/commandset_custominit.py b/examples/modular_commands/commandset_custominit.py index 5a574a59..2ef94a75 100644 --- a/examples/modular_commands/commandset_custominit.py +++ b/examples/modular_commands/commandset_custominit.py @@ -14,7 +14,7 @@ class CustomInitCommandSet(CommandSet): self._arg2 = arg2 def do_show_arg1(self, cmd: Cmd, _: Statement): - cmd.poutput('Arg1: ' + self._arg1) + self._cmd.poutput('Arg1: ' + self._arg1) def do_show_arg2(self, cmd: Cmd, _: Statement): - cmd.poutput('Arg2: ' + self._arg2) + self._cmd.poutput('Arg2: ' + self._arg2) diff --git a/examples/modular_commands_basic.py b/examples/modular_commands_basic.py index 9f4a0bd2..b9d4c4a2 100644 --- a/examples/modular_commands_basic.py +++ b/examples/modular_commands_basic.py @@ -13,11 +13,11 @@ class AutoLoadCommandSet(CommandSet): def __init__(self): super().__init__() - def do_hello(self, cmd: cmd2.Cmd, _: cmd2.Statement): - cmd.poutput('Hello') + def do_hello(self, _: cmd2.Statement): + self._cmd.poutput('Hello') - def do_world(self, cmd: cmd2.Cmd, _: cmd2.Statement): - cmd.poutput('World') + def do_world(self, _: cmd2.Statement): + self._cmd.poutput('World') class ExampleApp(cmd2.Cmd): diff --git a/examples/modular_commands_dynamic.py b/examples/modular_commands_dynamic.py index 81dbad82..eb6283a7 100644 --- a/examples/modular_commands_dynamic.py +++ b/examples/modular_commands_dynamic.py @@ -19,11 +19,11 @@ class LoadableFruits(CommandSet): def __init__(self): super().__init__() - def do_apple(self, cmd: cmd2.Cmd, _: cmd2.Statement): - cmd.poutput('Apple') + def do_apple(self, _: cmd2.Statement): + self._cmd.poutput('Apple') - def do_banana(self, cmd: cmd2.Cmd, _: cmd2.Statement): - cmd.poutput('Banana') + def do_banana(self, _: cmd2.Statement): + self._cmd.poutput('Banana') @with_default_category('Vegetables') @@ -31,11 +31,11 @@ class LoadableVegetables(CommandSet): def __init__(self): super().__init__() - def do_arugula(self, cmd: cmd2.Cmd, _: cmd2.Statement): - cmd.poutput('Arugula') + def do_arugula(self, _: cmd2.Statement): + self._cmd.poutput('Arugula') - def do_bokchoy(self, cmd: cmd2.Cmd, _: cmd2.Statement): - cmd.poutput('Bok Choy') + def do_bokchoy(self, _: cmd2.Statement): + self._cmd.poutput('Bok Choy') class ExampleApp(cmd2.Cmd): @@ -58,14 +58,14 @@ class ExampleApp(cmd2.Cmd): def do_load(self, ns: argparse.Namespace): if ns.cmds == 'fruits': try: - self.install_command_set(self._fruits) + self.register_command_set(self._fruits) self.poutput('Fruits loaded') except ValueError: self.poutput('Fruits already loaded') if ns.cmds == 'vegetables': try: - self.install_command_set(self._vegetables) + self.register_command_set(self._vegetables) self.poutput('Vegetables loaded') except ValueError: self.poutput('Vegetables already loaded') @@ -73,11 +73,11 @@ class ExampleApp(cmd2.Cmd): @with_argparser(load_parser) def do_unload(self, ns: argparse.Namespace): if ns.cmds == 'fruits': - self.uninstall_command_set(self._fruits) + self.unregister_command_set(self._fruits) self.poutput('Fruits unloaded') if ns.cmds == 'vegetables': - self.uninstall_command_set(self._vegetables) + self.unregister_command_set(self._vegetables) self.poutput('Vegetables unloaded') diff --git a/examples/modular_subcommands.py b/examples/modular_subcommands.py index 945fd54d..44d4edd8 100644 --- a/examples/modular_subcommands.py +++ b/examples/modular_subcommands.py @@ -20,17 +20,17 @@ class LoadableFruits(CommandSet): def __init__(self): super().__init__() - def do_apple(self, cmd: cmd2.Cmd, _: cmd2.Statement): - cmd.poutput('Apple') + def do_apple(self, _: cmd2.Statement): + self._cmd.poutput('Apple') banana_description = "Cut a banana" banana_parser = cmd2.Cmd2ArgumentParser(add_help=False, description=banana_description) banana_parser.add_argument('direction', choices=['discs', 'lengthwise']) @cmd2.as_subcommand_to('cut', 'banana', banana_parser, help=banana_description.lower()) - def cut_banana(self, cmd: cmd2.Cmd, ns: argparse.Namespace): + def cut_banana(self, ns: argparse.Namespace): """Cut banana""" - cmd.poutput('cutting banana: ' + ns.direction) + self._cmd.poutput('cutting banana: ' + ns.direction) @with_default_category('Vegetables') @@ -38,16 +38,16 @@ class LoadableVegetables(CommandSet): def __init__(self): super().__init__() - def do_arugula(self, cmd: cmd2.Cmd, _: cmd2.Statement): - cmd.poutput('Arugula') + def do_arugula(self, _: cmd2.Statement): + self._cmd.poutput('Arugula') bokchoy_description = "Cut some bokchoy" bokchoy_parser = cmd2.Cmd2ArgumentParser(add_help=False, description=bokchoy_description) bokchoy_parser.add_argument('style', choices=['quartered', 'diced']) @cmd2.as_subcommand_to('cut', 'bokchoy', bokchoy_parser, help=bokchoy_description.lower()) - def cut_bokchoy(self, cmd: cmd2.Cmd, _: cmd2.Statement): - cmd.poutput('Bok Choy') + def cut_bokchoy(self, _: cmd2.Statement): + self._cmd.poutput('Bok Choy') class ExampleApp(cmd2.Cmd): @@ -70,14 +70,14 @@ class ExampleApp(cmd2.Cmd): def do_load(self, ns: argparse.Namespace): if ns.cmds == 'fruits': try: - self.install_command_set(self._fruits) + self.register_command_set(self._fruits) self.poutput('Fruits loaded') except ValueError: self.poutput('Fruits already loaded') if ns.cmds == 'vegetables': try: - self.install_command_set(self._vegetables) + self.register_command_set(self._vegetables) self.poutput('Vegetables loaded') except ValueError: self.poutput('Vegetables already loaded') @@ -85,11 +85,11 @@ class ExampleApp(cmd2.Cmd): @with_argparser(load_parser) def do_unload(self, ns: argparse.Namespace): if ns.cmds == 'fruits': - self.uninstall_command_set(self._fruits) + self.unregister_command_set(self._fruits) self.poutput('Fruits unloaded') if ns.cmds == 'vegetables': - self.uninstall_command_set(self._vegetables) + self.unregister_command_set(self._vegetables) self.poutput('Vegetables unloaded') cut_parser = cmd2.Cmd2ArgumentParser('cut') diff --git a/tests_isolated/test_commandset/test_argparse_subcommands.py b/tests_isolated/test_commandset/test_argparse_subcommands.py index 69a53447..bd2bed42 100644 --- a/tests_isolated/test_commandset/test_argparse_subcommands.py +++ b/tests_isolated/test_commandset/test_argparse_subcommands.py @@ -19,17 +19,17 @@ class SubcommandSet(cmd2.CommandSet): super(SubcommandSet, self).__init__() # subcommand functions for the base command - def base_foo(self, cmd: cmd2.Cmd, args): + def base_foo(self, args): """foo subcommand of base command""" - cmd.poutput(args.x * args.y) + self._cmd.poutput(args.x * args.y) - def base_bar(self, cmd: cmd2.Cmd, args): + def base_bar(self, args): """bar subcommand of base command""" - cmd.poutput('((%s))' % args.z) + self._cmd.poutput('((%s))' % args.z) - def base_helpless(self, cmd: cmd2.Cmd, args): + def base_helpless(self, args): """helpless subcommand of base command""" - cmd.poutput('((%s))' % args.z) + self._cmd.poutput('((%s))' % args.z) # create the top-level parser for the base command base_parser = argparse.ArgumentParser() @@ -56,11 +56,11 @@ class SubcommandSet(cmd2.CommandSet): parser_bar.set_defaults(func=base_bar) @cmd2.with_argparser(base_parser) - def do_base(self, cmd: cmd2.Cmd, args): + def do_base(self, args): """Base command help""" # Call whatever subcommand function was selected func = getattr(args, 'func') - func(self, cmd, args) + func(self, args) @pytest.fixture diff --git a/tests_isolated/test_commandset/test_commandset.py b/tests_isolated/test_commandset/test_commandset.py index 813f9183..e1441fe4 100644 --- a/tests_isolated/test_commandset/test_commandset.py +++ b/tests_isolated/test_commandset/test_commandset.py @@ -21,36 +21,36 @@ class CommandSetBase(cmd2.CommandSet): @cmd2.with_default_category('Fruits') class CommandSetA(CommandSetBase): - def do_apple(self, cmd: cmd2.Cmd, statement: cmd2.Statement): - cmd.poutput('Apple!') + def do_apple(self, statement: cmd2.Statement): + self._cmd.poutput('Apple!') - def do_banana(self, cmd: cmd2.Cmd, statement: cmd2.Statement): + def do_banana(self, statement: cmd2.Statement): """Banana Command""" - cmd.poutput('Banana!!') + self._cmd.poutput('Banana!!') cranberry_parser = cmd2.Cmd2ArgumentParser('cranberry') cranberry_parser.add_argument('arg1', choices=['lemonade', 'juice', 'sauce']) @cmd2.with_argparser(cranberry_parser, with_unknown_args=True) - def do_cranberry(self, cmd: cmd2.Cmd, ns: argparse.Namespace, unknown: List[str]): - cmd.poutput('Cranberry {}!!'.format(ns.arg1)) + def do_cranberry(self, ns: argparse.Namespace, unknown: List[str]): + self._cmd.poutput('Cranberry {}!!'.format(ns.arg1)) if unknown and len(unknown): - cmd.poutput('Unknown: ' + ', '.join(['{}']*len(unknown)).format(*unknown)) - cmd.last_result = {'arg1': ns.arg1, + self._cmd.poutput('Unknown: ' + ', '.join(['{}']*len(unknown)).format(*unknown)) + self._cmd.last_result = {'arg1': ns.arg1, 'unknown': unknown} - def help_cranberry(self, cmd: cmd2.Cmd): - cmd.stdout.write('This command does diddly squat...\n') + def help_cranberry(self): + self._cmd.stdout.write('This command does diddly squat...\n') @cmd2.with_argument_list @cmd2.with_category('Also Alone') - def do_durian(self, cmd: cmd2.Cmd, args: List[str]): + def do_durian(self, args: List[str]): """Durian Command""" - cmd.poutput('{} Arguments: '.format(len(args))) - cmd.poutput(', '.join(['{}']*len(args)).format(*args)) - cmd.last_result = {'args': args} + self._cmd.poutput('{} Arguments: '.format(len(args))) + self._cmd.poutput(', '.join(['{}']*len(args)).format(*args)) + self._cmd.last_result = {'args': args} - def complete_durian(self, cmd: cmd2.Cmd, text: str, line: str, begidx: int, endidx: int) -> List[str]: + def complete_durian(self, text: str, line: str, begidx: int, endidx: int) -> List[str]: return utils.basic_complete(text, line, begidx, endidx, ['stinks', 'smells', 'disgusting']) elderberry_parser = cmd2.Cmd2ArgumentParser('elderberry') @@ -58,9 +58,9 @@ class CommandSetA(CommandSetBase): @cmd2.with_category('Alone') @cmd2.with_argparser(elderberry_parser) - def do_elderberry(self, cmd: cmd2.Cmd, ns: argparse.Namespace): - cmd.poutput('Elderberry {}!!'.format(ns.arg1)) - cmd.last_result = {'arg1': ns.arg1} + def do_elderberry(self, ns: argparse.Namespace): + self._cmd.poutput('Elderberry {}!!'.format(ns.arg1)) + self._cmd.last_result = {'arg1': ns.arg1} @cmd2.with_default_category('Command Set B') @@ -69,15 +69,15 @@ class CommandSetB(CommandSetBase): super().__init__() self._arg1 = arg1 - def do_aardvark(self, cmd: cmd2.Cmd, statement: cmd2.Statement): - cmd.poutput('Aardvark!') + def do_aardvark(self, statement: cmd2.Statement): + self._cmd.poutput('Aardvark!') - def do_bat(self, cmd: cmd2.Cmd, statement: cmd2.Statement): + def do_bat(self, statement: cmd2.Statement): """Banana Command""" - cmd.poutput('Bat!!') + self._cmd.poutput('Bat!!') - def do_crocodile(self, cmd: cmd2.Cmd, statement: cmd2.Statement): - cmd.poutput('Crocodile!!') + def do_crocodile(self, statement: cmd2.Statement): + self._cmd.poutput('Crocodile!!') def test_autoload_commands(command_sets_app): @@ -108,18 +108,18 @@ def test_custom_construct_commandsets(): # Verifies that the same CommandSet can not be loaded twice command_set_2 = CommandSetB('bar') with pytest.raises(CommandSetRegistrationError): - assert app.install_command_set(command_set_2) + assert app.register_command_set(command_set_2) # Verify that autoload doesn't conflict with a manually loaded CommandSet that could be autoloaded. command_set_a = CommandSetA() app2 = WithCommandSets(command_sets=[command_set_a]) with pytest.raises(CommandSetRegistrationError): - app2.install_command_set(command_set_b) + app2.register_command_set(command_set_b) - app.uninstall_command_set(command_set_b) + app.unregister_command_set(command_set_b) - app2.install_command_set(command_set_b) + app2.register_command_set(command_set_b) assert hasattr(app2, 'do_apple') assert hasattr(app2, 'do_aardvark') @@ -141,7 +141,7 @@ def test_load_commands(command_sets_manual): assert command_sets_manual.find_commandset_for_command('elderberry') is None assert not command_sets_manual.find_commandsets(CommandSetA) - command_sets_manual.install_command_set(cmd_set) + command_sets_manual.register_command_set(cmd_set) assert command_sets_manual.find_commandsets(CommandSetA)[0] is cmd_set assert command_sets_manual.find_commandset_for_command('elderberry') is cmd_set @@ -155,7 +155,7 @@ def test_load_commands(command_sets_manual): assert 'cranberry' in cmds_cats['Fruits'] # uninstall the command set and verify it is now also no longer accessible - command_sets_manual.uninstall_command_set(cmd_set) + command_sets_manual.unregister_command_set(cmd_set) cmds_cats, cmds_doc, cmds_undoc, help_topics = command_sets_manual._build_command_info() @@ -163,10 +163,10 @@ def test_load_commands(command_sets_manual): assert 'Fruits' not in cmds_cats # uninstall a second time and verify no errors happen - command_sets_manual.uninstall_command_set(cmd_set) + command_sets_manual.unregister_command_set(cmd_set) # reinstall the command set and verify it is accessible - command_sets_manual.install_command_set(cmd_set) + command_sets_manual.register_command_set(cmd_set) cmds_cats, cmds_doc, cmds_undoc, help_topics = command_sets_manual._build_command_info() @@ -177,33 +177,10 @@ def test_load_commands(command_sets_manual): assert 'cranberry' in cmds_cats['Fruits'] -def test_partial_with_passthru(): - - def test_func(arg1, arg2): - """Documentation Comment""" - print('Do stuff {} - {}'.format(arg1, arg2)) - - my_partial = cmd2.command_definition._partial_passthru(test_func, 1) - - setattr(test_func, 'Foo', 5) - - assert hasattr(my_partial, 'Foo') - - assert getattr(my_partial, 'Foo', None) == 5 - - a = dir(test_func) - b = dir(my_partial) - assert a == b - - assert not hasattr(test_func, 'Bar') - setattr(my_partial, 'Bar', 6) - assert hasattr(test_func, 'Bar') - - assert getattr(test_func, 'Bar', None) == 6 - - def test_commandset_decorators(command_sets_app): result = command_sets_app.app_cmd('cranberry juice extra1 extra2') + assert result is not None + assert result.data is not None assert len(result.data['unknown']) == 2 assert 'extra1' in result.data['unknown'] assert 'extra2' in result.data['unknown'] @@ -240,7 +217,7 @@ def test_load_commandset_errors(command_sets_manual, capsys): # create a conflicting command before installing CommandSet to verify rollback behavior command_sets_manual._install_command_function('durian', cmd_set.do_durian) with pytest.raises(CommandSetRegistrationError): - command_sets_manual.install_command_set(cmd_set) + command_sets_manual.register_command_set(cmd_set) # verify that the commands weren't installed cmds_cats, cmds_doc, cmds_undoc, help_topics = command_sets_manual._build_command_info() @@ -256,7 +233,7 @@ def test_load_commandset_errors(command_sets_manual, capsys): command_sets_manual.app_cmd('alias create banana run_pyscript') # now install a command set and verify the commands are now present - command_sets_manual.install_command_set(cmd_set) + command_sets_manual.register_command_set(cmd_set) out, err = capsys.readouterr() # verify aliases and macros are deleted with warning if they conflict with a command @@ -289,7 +266,7 @@ class LoadableBase(cmd2.CommandSet): cut_subparsers = cut_parser.add_subparsers(title='item', help='item to cut') @cmd2.with_argparser(cut_parser) - def do_cut(self, cmd: cmd2.Cmd, ns: argparse.Namespace): + def do_cut(self, ns: argparse.Namespace): """Cut something""" handler = ns.get_handler() if handler is not None: @@ -297,15 +274,15 @@ class LoadableBase(cmd2.CommandSet): handler(ns) else: # No subcommand was provided, so call help - cmd.pwarning('This command does nothing without sub-parsers registered') - cmd.do_help('cut') + self._cmd.pwarning('This command does nothing without sub-parsers registered') + self._cmd.do_help('cut') stir_parser = cmd2.Cmd2ArgumentParser('stir') stir_subparsers = stir_parser.add_subparsers(title='item', help='what to stir') @cmd2.with_argparser(stir_parser) - def do_stir(self, cmd: cmd2.Cmd, ns: argparse.Namespace): + def do_stir(self, ns: argparse.Namespace): """Stir something""" handler = ns.get_handler() if handler is not None: @@ -313,21 +290,21 @@ class LoadableBase(cmd2.CommandSet): handler(ns) else: # No subcommand was provided, so call help - cmd.pwarning('This command does nothing without sub-parsers registered') - cmd.do_help('stir') + self._cmd.pwarning('This command does nothing without sub-parsers registered') + self._cmd.do_help('stir') stir_pasta_parser = cmd2.Cmd2ArgumentParser('pasta', add_help=False) stir_pasta_parser.add_argument('--option', '-o') stir_pasta_parser.add_subparsers(title='style', help='Stir style') @cmd2.as_subcommand_to('stir', 'pasta', stir_pasta_parser) - def stir_pasta(self, cmd: cmd2.Cmd, ns: argparse.Namespace): + def stir_pasta(self, ns: argparse.Namespace): handler = ns.get_handler() if handler is not None: # Call whatever subcommand function was selected handler(ns) else: - cmd.poutput('Stir pasta haphazardly') + self._cmd.poutput('Stir pasta haphazardly') class LoadableBadBase(cmd2.CommandSet): @@ -335,7 +312,7 @@ class LoadableBadBase(cmd2.CommandSet): super(LoadableBadBase, self).__init__() self._dummy = dummy # prevents autoload - def do_cut(self, cmd: cmd2.Cmd, ns: argparse.Namespace): + def do_cut(self, ns: argparse.Namespace): """Cut something""" handler = ns.get_handler() if handler is not None: @@ -343,8 +320,8 @@ class LoadableBadBase(cmd2.CommandSet): handler(ns) else: # No subcommand was provided, so call help - cmd.poutput('This command does nothing without sub-parsers registered') - cmd.do_help('cut') + self._cmd.poutput('This command does nothing without sub-parsers registered') + self._cmd.do_help('cut') @cmd2.with_default_category('Fruits') @@ -353,16 +330,16 @@ class LoadableFruits(cmd2.CommandSet): super(LoadableFruits, self).__init__() self._dummy = dummy # prevents autoload - def do_apple(self, cmd: cmd2.Cmd, _: cmd2.Statement): - cmd.poutput('Apple') + def do_apple(self, _: cmd2.Statement): + self._cmd.poutput('Apple') banana_parser = cmd2.Cmd2ArgumentParser(add_help=False) banana_parser.add_argument('direction', choices=['discs', 'lengthwise']) @cmd2.as_subcommand_to('cut', 'banana', banana_parser, help='Cut banana', aliases=['bananer']) - def cut_banana(self, cmd: cmd2.Cmd, ns: argparse.Namespace): + def cut_banana(self, ns: argparse.Namespace): """Cut banana""" - cmd.poutput('cutting banana: ' + ns.direction) + self._cmd.poutput('cutting banana: ' + ns.direction) class LoadablePastaStir(cmd2.CommandSet): @@ -374,8 +351,8 @@ class LoadablePastaStir(cmd2.CommandSet): stir_pasta_vigor_parser.add_argument('frequency') @cmd2.as_subcommand_to('stir pasta', 'vigorously', stir_pasta_vigor_parser) - def stir_pasta_vigorously(self, cmd: cmd2.Cmd, ns: argparse.Namespace): - cmd.poutput('stir the pasta vigorously') + def stir_pasta_vigorously(self, ns: argparse.Namespace): + self._cmd.poutput('stir the pasta vigorously') @cmd2.with_default_category('Vegetables') @@ -384,18 +361,18 @@ class LoadableVegetables(cmd2.CommandSet): super(LoadableVegetables, self).__init__() self._dummy = dummy # prevents autoload - def do_arugula(self, cmd: cmd2.Cmd, _: cmd2.Statement): - cmd.poutput('Arugula') + def do_arugula(self, _: cmd2.Statement): + self._cmd.poutput('Arugula') - def complete_style_arg(self, cmd: cmd2.Cmd, text: str, line: str, begidx: int, endidx: int) -> List[str]: + def complete_style_arg(self, text: str, line: str, begidx: int, endidx: int) -> List[str]: return ['quartered', 'diced'] bokchoy_parser = cmd2.Cmd2ArgumentParser(add_help=False) bokchoy_parser.add_argument('style', completer_method=complete_style_arg) @cmd2.as_subcommand_to('cut', 'bokchoy', bokchoy_parser) - def cut_bokchoy(self, cmd: cmd2.Cmd, _: cmd2.Statement): - cmd.poutput('Bok Choy') + def cut_bokchoy(self, _: cmd2.Statement): + self._cmd.poutput('Bok Choy') def test_subcommands(command_sets_manual): @@ -407,12 +384,12 @@ def test_subcommands(command_sets_manual): # installing subcommands without base command present raises exception with pytest.raises(CommandSetRegistrationError): - command_sets_manual.install_command_set(fruit_cmds) + command_sets_manual.register_command_set(fruit_cmds) # if the base command is present but isn't an argparse command, expect exception - command_sets_manual.install_command_set(badbase_cmds) + command_sets_manual.register_command_set(badbase_cmds) with pytest.raises(CommandSetRegistrationError): - command_sets_manual.install_command_set(fruit_cmds) + command_sets_manual.register_command_set(fruit_cmds) # verify that the commands weren't installed cmds_cats, cmds_doc, cmds_undoc, help_topics = command_sets_manual._build_command_info() @@ -420,8 +397,8 @@ def test_subcommands(command_sets_manual): assert 'Fruits' not in cmds_cats # Now install the good base commands - command_sets_manual.uninstall_command_set(badbase_cmds) - command_sets_manual.install_command_set(base_cmds) + command_sets_manual.unregister_command_set(badbase_cmds) + command_sets_manual.register_command_set(base_cmds) # verify that we catch an attempt to register subcommands when the commandset isn't installed with pytest.raises(CommandSetRegistrationError): @@ -431,8 +408,8 @@ def test_subcommands(command_sets_manual): assert 'This command does nothing without sub-parsers registered' in cmd_result.stderr # verify that command set install without problems - command_sets_manual.install_command_set(fruit_cmds) - command_sets_manual.install_command_set(veg_cmds) + command_sets_manual.register_command_set(fruit_cmds) + command_sets_manual.register_command_set(veg_cmds) cmds_cats, cmds_doc, cmds_undoc, help_topics = command_sets_manual._build_command_info() assert 'Fruits' in cmds_cats @@ -460,21 +437,21 @@ def test_subcommands(command_sets_manual): assert ['diced', 'quartered'] == command_sets_manual.completion_matches # verify that command set uninstalls without problems - command_sets_manual.uninstall_command_set(fruit_cmds) + command_sets_manual.unregister_command_set(fruit_cmds) cmds_cats, cmds_doc, cmds_undoc, help_topics = command_sets_manual._build_command_info() assert 'Fruits' not in cmds_cats # verify a double-unregister raises exception with pytest.raises(CommandSetRegistrationError): command_sets_manual._unregister_subcommands(fruit_cmds) - command_sets_manual.uninstall_command_set(veg_cmds) + command_sets_manual.unregister_command_set(veg_cmds) # Disable command and verify subcommands still load and unload command_sets_manual.disable_command('cut', 'disabled for test') # verify that command set install without problems - command_sets_manual.install_command_set(fruit_cmds) - command_sets_manual.install_command_set(veg_cmds) + command_sets_manual.register_command_set(fruit_cmds) + command_sets_manual.register_command_set(veg_cmds) command_sets_manual.enable_command('cut') @@ -505,7 +482,7 @@ def test_subcommands(command_sets_manual): command_sets_manual.disable_command('cut', 'disabled for test') # verify that command set uninstalls without problems - command_sets_manual.uninstall_command_set(fruit_cmds) + command_sets_manual.unregister_command_set(fruit_cmds) cmds_cats, cmds_doc, cmds_undoc, help_topics = command_sets_manual._build_command_info() assert 'Fruits' not in cmds_cats @@ -514,10 +491,10 @@ def test_subcommands(command_sets_manual): command_sets_manual._unregister_subcommands(fruit_cmds) with pytest.raises(CommandSetRegistrationError): - command_sets_manual.uninstall_command_set(base_cmds) + command_sets_manual.unregister_command_set(base_cmds) - command_sets_manual.uninstall_command_set(veg_cmds) - command_sets_manual.uninstall_command_set(base_cmds) + command_sets_manual.unregister_command_set(veg_cmds) + command_sets_manual.unregister_command_set(base_cmds) def test_nested_subcommands(command_sets_manual): base_cmds = LoadableBase(1) @@ -526,14 +503,14 @@ def test_nested_subcommands(command_sets_manual): pasta_cmds = LoadablePastaStir(1) with pytest.raises(CommandSetRegistrationError): - command_sets_manual.install_command_set(pasta_cmds) + command_sets_manual.register_command_set(pasta_cmds) - command_sets_manual.install_command_set(base_cmds) + command_sets_manual.register_command_set(base_cmds) - command_sets_manual.install_command_set(pasta_cmds) + command_sets_manual.register_command_set(pasta_cmds) with pytest.raises(CommandSetRegistrationError): - command_sets_manual.uninstall_command_set(base_cmds) + command_sets_manual.unregister_command_set(base_cmds) class BadNestedSubcommands(cmd2.CommandSet): def __init__(self, dummy): @@ -544,11 +521,11 @@ def test_nested_subcommands(command_sets_manual): stir_pasta_vigor_parser.add_argument('frequency') @cmd2.as_subcommand_to('stir sauce', 'vigorously', stir_pasta_vigor_parser) - def stir_pasta_vigorously(self, cmd: cmd2.Cmd, ns: argparse.Namespace): - cmd.poutput('stir the pasta vigorously') + def stir_pasta_vigorously(self, ns: argparse.Namespace): + self._cmd.poutput('stir the pasta vigorously') with pytest.raises(CommandSetRegistrationError): - command_sets_manual.install_command_set(BadNestedSubcommands(1)) + command_sets_manual.register_command_set(BadNestedSubcommands(1)) class AppWithSubCommands(cmd2.Cmd): @@ -631,7 +608,7 @@ class WithCompleterCommandSet(cmd2.CommandSet): """dummy variable prevents this from being autoloaded in other tests""" super(WithCompleterCommandSet, self).__init__() - def complete_states(self, cmd: cmd2.Cmd, text: str, line: str, begidx: int, endidx: int) -> List[str]: + def complete_states(self, text: str, line: str, begidx: int, endidx: int) -> List[str]: assert self is complete_states_expected_self return utils.basic_complete(text, line, begidx, endidx, self.states) @@ -641,8 +618,8 @@ class SubclassCommandSetCase1(WithCompleterCommandSet): parser.add_argument('state', type=str, completer_method=WithCompleterCommandSet.complete_states) @cmd2.with_argparser(parser) - def do_case1(self, cmd: cmd2.Cmd, ns: argparse.Namespace): - cmd.poutput('something {}'.format(ns.state)) + def do_case1(self, ns: argparse.Namespace): + self._cmd.poutput('something {}'.format(ns.state)) class SubclassCommandSetErrorCase2(WithCompleterCommandSet): @@ -650,8 +627,8 @@ class SubclassCommandSetErrorCase2(WithCompleterCommandSet): parser.add_argument('state', type=str, completer_method=WithCompleterCommandSet.complete_states) @cmd2.with_argparser(parser) - def do_error2(self, cmd: cmd2.Cmd, ns: argparse.Namespace): - cmd.poutput('something {}'.format(ns.state)) + def do_error2(self, ns: argparse.Namespace): + self._cmd.poutput('something {}'.format(ns.state)) class SubclassCommandSetCase2(cmd2.CommandSet): @@ -663,8 +640,8 @@ class SubclassCommandSetCase2(cmd2.CommandSet): parser.add_argument('state', type=str, completer_method=WithCompleterCommandSet.complete_states) @cmd2.with_argparser(parser) - def do_case2(self, cmd: cmd2.Cmd, ns: argparse.Namespace): - cmd.poutput('something {}'.format(ns.state)) + def do_case2(self, ns: argparse.Namespace): + self._cmd.poutput('something {}'.format(ns.state)) def test_cross_commandset_completer(command_sets_manual): @@ -678,7 +655,7 @@ def test_cross_commandset_completer(command_sets_manual): # CommandSet instance as self when calling the completer case1_set = SubclassCommandSetCase1(1) - command_sets_manual.install_command_set(case1_set) + command_sets_manual.register_command_set(case1_set) text = '' line = 'case1 {}'.format(text) @@ -691,7 +668,7 @@ def test_cross_commandset_completer(command_sets_manual): assert first_match == 'alabama' assert command_sets_manual.completion_matches == WithCompleterCommandSet.states - command_sets_manual.uninstall_command_set(case1_set) + command_sets_manual.unregister_command_set(case1_set) #################################################################################################################### # This exercises Case 2 @@ -701,8 +678,8 @@ def test_cross_commandset_completer(command_sets_manual): # First verify that, without the correct command set base_set = WithCompleterCommandSet(1) case2_set = SubclassCommandSetCase2(2) - command_sets_manual.install_command_set(base_set) - command_sets_manual.install_command_set(case2_set) + command_sets_manual.register_command_set(base_set) + command_sets_manual.register_command_set(case2_set) text = '' line = 'case2 {}'.format(text) @@ -715,8 +692,8 @@ def test_cross_commandset_completer(command_sets_manual): assert first_match == 'alabama' assert command_sets_manual.completion_matches == WithCompleterCommandSet.states - command_sets_manual.uninstall_command_set(case2_set) - command_sets_manual.uninstall_command_set(base_set) + command_sets_manual.unregister_command_set(case2_set) + command_sets_manual.unregister_command_set(base_set) #################################################################################################################### # This exercises Case 3 @@ -724,8 +701,8 @@ def test_cross_commandset_completer(command_sets_manual): # and no exact type match can be found, but sub-class matches can be found and there is only a single # subclass match, then use the lone subclass match as the parent CommandSet. - command_sets_manual.install_command_set(case1_set) - command_sets_manual.install_command_set(case2_set) + command_sets_manual.register_command_set(case1_set) + command_sets_manual.register_command_set(case2_set) text = '' line = 'case2 {}'.format(text) @@ -738,8 +715,8 @@ def test_cross_commandset_completer(command_sets_manual): assert first_match == 'alabama' assert command_sets_manual.completion_matches == WithCompleterCommandSet.states - command_sets_manual.uninstall_command_set(case2_set) - command_sets_manual.uninstall_command_set(case1_set) + command_sets_manual.unregister_command_set(case2_set) + command_sets_manual.unregister_command_set(case1_set) #################################################################################################################### # Error Case 1 @@ -747,7 +724,7 @@ def test_cross_commandset_completer(command_sets_manual): # all installed CommandSet instances for one that is an exact type match, none are found # search for sub-class matches, also none are found. - command_sets_manual.install_command_set(case2_set) + command_sets_manual.register_command_set(case2_set) text = '' line = 'case2 {}'.format(text) @@ -758,7 +735,7 @@ def test_cross_commandset_completer(command_sets_manual): assert first_match is None assert command_sets_manual.completion_matches == [] - command_sets_manual.uninstall_command_set(case2_set) + command_sets_manual.unregister_command_set(case2_set) #################################################################################################################### # Error Case 2 @@ -767,9 +744,9 @@ def test_cross_commandset_completer(command_sets_manual): # search for sub-class matches, more than 1 is found error_case2_set = SubclassCommandSetErrorCase2(4) - command_sets_manual.install_command_set(case1_set) - command_sets_manual.install_command_set(case2_set) - command_sets_manual.install_command_set(error_case2_set) + command_sets_manual.register_command_set(case1_set) + command_sets_manual.register_command_set(case2_set) + command_sets_manual.register_command_set(error_case2_set) text = '' line = 'case2 {}'.format(text) @@ -780,7 +757,7 @@ def test_cross_commandset_completer(command_sets_manual): assert first_match is None assert command_sets_manual.completion_matches == [] - command_sets_manual.uninstall_command_set(case2_set) + command_sets_manual.unregister_command_set(case2_set) class CommandSetWithPathComplete(cmd2.CommandSet): @@ -799,7 +776,7 @@ class CommandSetWithPathComplete(cmd2.CommandSet): def test_path_complete(command_sets_manual): test_set = CommandSetWithPathComplete(1) - command_sets_manual.install_command_set(test_set) + command_sets_manual.register_command_set(test_set) text = '' line = 'path {}'.format(text) |