diff options
author | Eric Lin <anselor@gmail.com> | 2020-06-12 20:44:10 -0400 |
---|---|---|
committer | anselor <anselor@gmail.com> | 2020-08-04 13:38:08 -0400 |
commit | 6da2cf30311f97d23a7121f8c02f9123674194b4 (patch) | |
tree | 9d6780afcb0742b94f86b6f8f775220691896cd3 | |
parent | e1087b8f29341397b09e9a0722a77c025ab20d23 (diff) | |
download | cmd2-git-6da2cf30311f97d23a7121f8c02f9123674194b4.tar.gz |
Some minor cleanup of how imports work. Fixed issue with help documentation for CommandSet commands.
Issue #943
-rw-r--r-- | cmd2/__init__.py | 1 | ||||
-rw-r--r-- | cmd2/cmd2.py | 8 | ||||
-rw-r--r-- | cmd2/command_definition.py | 21 | ||||
-rw-r--r-- | examples/modular_commands/commandset_basic.py | 3 | ||||
-rw-r--r-- | examples/modular_commands/commandset_custominit.py | 3 | ||||
-rw-r--r-- | tests/conftest.py | 12 |
6 files changed, 34 insertions, 14 deletions
diff --git a/cmd2/__init__.py b/cmd2/__init__.py index c3c1f87e..70a52f70 100644 --- a/cmd2/__init__.py +++ b/cmd2/__init__.py @@ -28,6 +28,7 @@ if cmd2_parser_module is not None: # Get the current value for argparse_custom.DEFAULT_ARGUMENT_PARSER from .argparse_custom import DEFAULT_ARGUMENT_PARSER from .cmd2 import Cmd +from .command_definition import CommandSet, with_default_category, register_command from .constants import COMMAND_NAME, DEFAULT_SHORTCUTS from .decorators import with_argument_list, with_argparser, with_argparser_and_unknown_args, with_category from .exceptions import Cmd2ArgparseError, SkipPostcommandHooks diff --git a/cmd2/cmd2.py b/cmd2/cmd2.py index 9a98b550..4100ec08 100644 --- a/cmd2/cmd2.py +++ b/cmd2/cmd2.py @@ -46,7 +46,7 @@ from typing import Any, AnyStr, Callable, Dict, Iterable, List, Mapping, Optiona 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 _UNBOUND_COMMANDS, CommandSet, _PartialPassthru +from .command_definition import _UNBOUND_COMMANDS, CommandSet, _partial_passthru from .constants import COMMAND_FUNC_PREFIX, COMPLETER_FUNC_PREFIX, HELP_FUNC_PREFIX from .decorators import with_argparser from .exceptions import Cmd2ShlexError, EmbeddedConsoleExit, EmptyStatement, RedirectionError, SkipPostcommandHooks @@ -428,7 +428,7 @@ class Cmd(cmd.Cmd): assert getattr(self, method[0], None) is None, \ 'In {}: Duplicate command function: {}'.format(cmdset_type.__name__, method[0]) - command_wrapper = _PartialPassthru(method[1], self) + command_wrapper = _partial_passthru(method[1], self) setattr(self, method[0], command_wrapper) command = method[0][len(COMMAND_FUNC_PREFIX):] @@ -436,11 +436,11 @@ class Cmd(cmd.Cmd): completer_func_name = COMPLETER_FUNC_PREFIX + command cmd_completer = getattr(cmdset, completer_func_name, None) if cmd_completer and not getattr(self, completer_func_name, None): - completer_wrapper = _PartialPassthru(cmd_completer, self) + completer_wrapper = _partial_passthru(cmd_completer, self) setattr(self, completer_func_name, completer_wrapper) cmd_help = getattr(cmdset, HELP_FUNC_PREFIX + command, None) if cmd_help and not getattr(self, HELP_FUNC_PREFIX + command, None): - help_wrapper = _PartialPassthru(cmd_help, self) + help_wrapper = _partial_passthru(cmd_help, self) setattr(self, HELP_FUNC_PREFIX + command, help_wrapper) def add_settable(self, settable: Settable) -> None: diff --git a/cmd2/command_definition.py b/cmd2/command_definition.py index f08040bb..a235525d 100644 --- a/cmd2/command_definition.py +++ b/cmd2/command_definition.py @@ -29,10 +29,15 @@ Registered command tuples. (command, do_ function, complete_ function, help_ fun """ -class _PartialPassthru(functools.partial): +def _partial_passthru(func: Callable, *args, **kwargs) -> functools.partial: """ - Wrapper around partial function that passes through getattr, setattr, and dir to the wrapped function. - This allows for CommandSet functions to be wrapped while maintaining the decorated properties + 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) @@ -43,6 +48,16 @@ class _PartialPassthru(functools.partial): 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 register_command(cmd_func: Callable[['Cmd', Union['Statement', 'argparse.Namespace']], None]): """ diff --git a/examples/modular_commands/commandset_basic.py b/examples/modular_commands/commandset_basic.py index 5ad26d97..8b51b7e4 100644 --- a/examples/modular_commands/commandset_basic.py +++ b/examples/modular_commands/commandset_basic.py @@ -4,8 +4,7 @@ A simple example demonstrating a loadable command set """ from typing import List -from cmd2 import Cmd, Statement, with_category -from cmd2.command_definition import CommandSet, with_default_category, register_command +from cmd2 import Cmd, Statement, with_category, CommandSet, with_default_category, register_command from cmd2.utils import CompletionError diff --git a/examples/modular_commands/commandset_custominit.py b/examples/modular_commands/commandset_custominit.py index 440db850..ce49876a 100644 --- a/examples/modular_commands/commandset_custominit.py +++ b/examples/modular_commands/commandset_custominit.py @@ -2,8 +2,7 @@ """ A simple example demonstrating a loadable command set """ -from cmd2 import Cmd, Statement, with_category -from cmd2.command_definition import CommandSet, with_default_category, register_command +from cmd2 import Cmd, Statement, with_category, CommandSet, with_default_category, register_command @register_command diff --git a/tests/conftest.py b/tests/conftest.py index 60074f5c..c07f7083 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -4,13 +4,14 @@ Cmd2 unit/functional testing """ import sys from contextlib import redirect_stderr, redirect_stdout -from typing import List, Optional, Union +from typing import Dict, List, Optional, Union from unittest import mock from pytest import fixture import cmd2 from cmd2.utils import StdSim +from cmd2.constants import COMMAND_FUNC_PREFIX, CMD_ATTR_HELP_CATEGORY # Prefer statically linked gnureadline if available (for macOS compatibility due to issues with libedit) try: @@ -25,11 +26,14 @@ except ImportError: pass -def verify_help_text(cmd2_app: cmd2.Cmd, help_output: Union[str, List[str]]) -> None: +def verify_help_text(cmd2_app: cmd2.Cmd, + help_output: Union[str, List[str]], + verbose_strings: Optional[List[str]] = None) -> None: """This function verifies that all expected commands are present in the help text. :param cmd2_app: instance of cmd2.Cmd :param help_output: output of help, either as a string or list of strings + :param verbose_strings: optional list of verbose strings to search for """ if isinstance(help_output, str): help_text = help_output @@ -39,7 +43,9 @@ def verify_help_text(cmd2_app: cmd2.Cmd, help_output: Union[str, List[str]]) -> for command in commands: assert command in help_text - # TODO: Consider adding checks for categories and for verbose history + if verbose_strings: + for verbose_string in verbose_strings: + assert verbose_string in help_text # Help text for the history command |