summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric Lin <anselor@gmail.com>2020-06-12 20:44:10 -0400
committeranselor <anselor@gmail.com>2020-08-04 13:38:08 -0400
commit6da2cf30311f97d23a7121f8c02f9123674194b4 (patch)
tree9d6780afcb0742b94f86b6f8f775220691896cd3
parente1087b8f29341397b09e9a0722a77c025ab20d23 (diff)
downloadcmd2-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__.py1
-rw-r--r--cmd2/cmd2.py8
-rw-r--r--cmd2/command_definition.py21
-rw-r--r--examples/modular_commands/commandset_basic.py3
-rw-r--r--examples/modular_commands/commandset_custominit.py3
-rw-r--r--tests/conftest.py12
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