summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmd2/__init__.py2
-rw-r--r--cmd2/cmd2.py85
-rw-r--r--cmd2/command_definition.py25
-rw-r--r--isolated_tests/test_commandset/test_commandset.py209
4 files changed, 13 insertions, 308 deletions
diff --git a/cmd2/__init__.py b/cmd2/__init__.py
index 70a52f70..1fb01b16 100644
--- a/cmd2/__init__.py
+++ b/cmd2/__init__.py
@@ -28,7 +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 .command_definition import CommandSet, with_default_category
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 2215f818..affd395f 100644
--- a/cmd2/cmd2.py
+++ b/cmd2/cmd2.py
@@ -46,7 +46,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 _REGISTERED_COMMANDS, CommandSet, _partial_passthru
+from .command_definition import 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
@@ -90,6 +90,7 @@ except ImportError: # pragma: no cover
class _SavedReadlineSettings:
"""readline settings that are backed up when switching between readline environments"""
+
def __init__(self):
self.completer = None
self.delims = ''
@@ -98,6 +99,7 @@ class _SavedReadlineSettings:
class _SavedCmd2Env:
"""cmd2 environment settings that are backed up when entering an interactive Python shell"""
+
def __init__(self):
self.readline_settings = _SavedReadlineSettings()
self.readline_module = None
@@ -397,15 +399,7 @@ class Cmd(cmd.Cmd):
self.matches_sorted = False
def _autoload_commands(self) -> None:
- """
- Load modular command definitions.
- :return: None
- """
-
- # start by loading registered functions as commands
- for cmd_name in _REGISTERED_COMMANDS.keys():
- self.install_registered_command(cmd_name)
-
+ """Load modular command definitions."""
# Search for all subclasses of CommandSet, instantiate them if they weren't provided in the constructor
all_commandset_defs = CommandSet.__subclasses__()
existing_commandset_types = [type(command_set) for command_set in self._installed_command_sets]
@@ -418,12 +412,11 @@ class Cmd(cmd.Cmd):
cmdset = cmdset_type()
self.install_command_set(cmdset)
- def install_command_set(self, cmdset: CommandSet):
+ def install_command_set(self, cmdset: CommandSet) -> None:
"""
Installs a CommandSet, loading all commands defined in the CommandSet
:param cmdset: CommandSet to load
- :return: None
"""
existing_commandset_types = [type(command_set) for command_set in self._installed_command_sets]
if type(cmdset) in existing_commandset_types:
@@ -525,64 +518,6 @@ class Cmd(cmd.Cmd):
cmdset.on_unregister(self)
self._installed_command_sets.remove(cmdset)
- def install_registered_command(self, cmd_name: str):
- cmd_completer = None
- cmd_help = None
-
- if cmd_name not in _REGISTERED_COMMANDS:
- raise KeyError('Command ' + cmd_name + ' has not been registered')
-
- cmd_func = _REGISTERED_COMMANDS[cmd_name]
-
- module = inspect.getmodule(cmd_func)
-
- module_funcs = [mf for mf in inspect.getmembers(module) if inspect.isfunction(mf[1])]
- for mf in module_funcs:
- if mf[0] == COMPLETER_FUNC_PREFIX + cmd_name:
- cmd_completer = mf[1]
- elif mf[0] == HELP_FUNC_PREFIX + cmd_name:
- cmd_help = mf[1]
- if cmd_completer is not None and cmd_help is not None:
- break
-
- self.install_command_function(cmd_name, cmd_func, cmd_completer, cmd_help)
-
- def install_command_function(self,
- cmd_name: str,
- cmd_func: Callable,
- cmd_completer: Optional[Callable],
- cmd_help: Optional[Callable]):
- """
- Installs a command by passing in functions for the command, completion, and help
-
- :param cmd_name: name of the command to install
- :param cmd_func: function to handle the command
- :param cmd_completer: completion function for the command
- :param cmd_help: help generator for the command
- :return: None
- """
- self.__install_command_function(cmd_name, types.MethodType(cmd_func, self))
-
- self._installed_functions.append(cmd_name)
- if cmd_completer is not None:
- self.__install_completer_function(cmd_name, types.MethodType(cmd_completer, self))
- if cmd_help is not None:
- self.__install_help_function(cmd_name, types.MethodType(cmd_help, self))
-
- def uninstall_command(self, cmd_name: str):
- """
- Uninstall an installed command and any associated completer or help functions
- :param cmd_name: Command to uninstall
- """
- if cmd_name in self._installed_functions:
- delattr(self, COMMAND_FUNC_PREFIX + cmd_name)
-
- if hasattr(self, COMPLETER_FUNC_PREFIX + cmd_name):
- delattr(self, COMPLETER_FUNC_PREFIX + cmd_name)
- if hasattr(self, HELP_FUNC_PREFIX + cmd_name):
- delattr(self, HELP_FUNC_PREFIX + cmd_name)
- self._installed_functions.remove(cmd_name)
-
def add_settable(self, settable: Settable) -> None:
"""
Convenience method to add a settable parameter to ``self.settables``
@@ -2156,7 +2091,8 @@ class Cmd(cmd.Cmd):
if proc.returncode is not None:
subproc_stdin.close()
new_stdout.close()
- raise RedirectionError('Pipe process exited with code {} before command could run'.format(proc.returncode))
+ raise RedirectionError(
+ 'Pipe process exited with code {} before command could run'.format(proc.returncode))
else:
redir_saved_state.redirecting = True
cmd_pipe_proc_reader = utils.ProcReader(proc, self.stdout, sys.stderr)
@@ -2165,7 +2101,8 @@ class Cmd(cmd.Cmd):
elif statement.output:
import tempfile
if (not statement.output_to) and (not self._can_clip):
- raise RedirectionError("Cannot redirect to paste buffer; missing 'pyperclip' and/or pyperclip dependencies")
+ raise RedirectionError(
+ "Cannot redirect to paste buffer; missing 'pyperclip' and/or pyperclip dependencies")
# Redirecting to a file
elif statement.output_to:
@@ -2271,7 +2208,6 @@ class Cmd(cmd.Cmd):
# Check to see if this command should be stored in history
if statement.command not in self.exclude_from_history and \
statement.command not in self.disabled_commands and add_to_history:
-
self.history.append(statement)
stop = func(statement)
@@ -3358,7 +3294,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
@@ -3387,6 +3323,7 @@ class Cmd(cmd.Cmd):
other arguments. (Defaults to None)
:return: True if running of commands should stop
"""
+
def py_quit():
"""Function callable from the interactive Python console to exit that environment"""
raise EmbeddedConsoleExit
diff --git a/cmd2/command_definition.py b/cmd2/command_definition.py
index d9925969..0645de2a 100644
--- a/cmd2/command_definition.py
+++ b/cmd2/command_definition.py
@@ -16,11 +16,6 @@ try: # pragma: no cover
except ImportError: # pragma: no cover
pass
-_REGISTERED_COMMANDS = {} # type: Dict[str, Callable]
-"""
-Registered command tuples. (command, ``do_`` function)
-"""
-
def _partial_passthru(func: Callable, *args, **kwargs) -> functools.partial:
"""
@@ -52,26 +47,6 @@ def _partial_passthru(func: Callable, *args, **kwargs) -> functools.partial:
return passthru_type(func, *args, **kwargs)
-def register_command(cmd_func: Callable):
- """
- Decorator that allows an arbitrary function to be automatically registered as a command.
- If there is a ``help_`` or ``complete_`` function that matches this command, that will also be registered.
-
- :param cmd_func: Function to register as a cmd2 command
- :type cmd_func: Callable[[cmd2.Cmd, Union[Statement, argparse.Namespace]], None]
- :return:
- """
- assert cmd_func.__name__.startswith(COMMAND_FUNC_PREFIX), 'Command functions must start with `do_`'
-
- cmd_name = cmd_func.__name__[len(COMMAND_FUNC_PREFIX):]
-
- if cmd_name not in _REGISTERED_COMMANDS:
- _REGISTERED_COMMANDS[cmd_name] = cmd_func
- else:
- raise KeyError('Command ' + cmd_name + ' is already registered')
- return cmd_func
-
-
def with_default_category(category: str):
"""
Decorator that applies a category to all ``do_*`` command methods in a class that do not already
diff --git a/isolated_tests/test_commandset/test_commandset.py b/isolated_tests/test_commandset/test_commandset.py
index eedf51de..8de2d3b0 100644
--- a/isolated_tests/test_commandset/test_commandset.py
+++ b/isolated_tests/test_commandset/test_commandset.py
@@ -14,51 +14,6 @@ from cmd2 import utils
from .conftest import complete_tester, normalize, run_cmd
-@cmd2.register_command
-@cmd2.with_category("AAA")
-def do_unbound(cmd: cmd2.Cmd, statement: cmd2.Statement):
- """
- This is an example of registering an unbound function
-
- :param cmd:
- :param statement:
- :return:
- """
- cmd.poutput('Unbound Command: {}'.format(statement.args))
-
-
-@cmd2.register_command
-@cmd2.with_category("AAA")
-def do_command_with_support(cmd: cmd2.Cmd, statement: cmd2.Statement):
- """
- This is an example of registering an unbound function
-
- :param cmd:
- :param statement:
- :return:
- """
- cmd.poutput('Command with support functions: {}'.format(statement.args))
-
-
-def help_command_with_support(cmd: cmd2.Cmd):
- cmd.poutput('Help for command_with_support')
-
-
-def complete_command_with_support(cmd: cmd2.Cmd, text: str, line: str, begidx: int, endidx: int) -> List[str]:
- """Completion function for do_index_based"""
- food_item_strs = ['Pizza', 'Ham', 'Ham Sandwich', 'Potato']
- sport_item_strs = ['Bat', 'Basket', 'Basketball', 'Football', 'Space Ball']
-
- index_dict = \
- {
- 1: food_item_strs, # Tab complete food items at index 1 in command line
- 2: sport_item_strs, # Tab complete sport items at index 2 in command line
- 3: cmd.path_complete, # Tab complete using path_complete function at index 3 in command line
- }
-
- return cmd.index_based_complete(text, line, begidx, endidx, index_dict=index_dict)
-
-
@cmd2.with_default_category('Command Set')
class CommandSetA(cmd2.CommandSet):
def do_apple(self, cmd: cmd2.Cmd, statement: cmd2.Statement):
@@ -126,9 +81,6 @@ def test_autoload_commands(command_sets_app):
cmds_cats, cmds_doc, cmds_undoc, help_topics = command_sets_app._build_command_info()
- assert 'AAA' in cmds_cats
- assert 'unbound' in cmds_cats['AAA']
-
assert 'Alone' in cmds_cats
assert 'elderberry' in cmds_cats['Alone']
@@ -150,41 +102,6 @@ def test_custom_construct_commandsets():
def test_load_commands(command_sets_manual):
- cmds_cats, cmds_doc, cmds_undoc, help_topics = command_sets_manual._build_command_info()
-
- # start by verifying none of the installable commands are present
- assert 'AAA' not in cmds_cats
- assert 'Alone' not in cmds_cats
- assert 'Command Set' not in cmds_cats
-
- # install the `unbound` command
- command_sets_manual.install_registered_command('unbound')
-
- # verify that the same registered command can't be installed twice
- with pytest.raises(ValueError):
- assert command_sets_manual.install_registered_command('unbound')
-
- # verifies detection of unregistered commands
- with pytest.raises(KeyError):
- assert command_sets_manual.install_registered_command('nonexistent_command')
-
- # verifies that a duplicate function name is detected
- def do_unbound(cmd: cmd2.Cmd, statement: cmd2.Statement):
- """
- This function duplicates an existing command
- """
- cmd.poutput('Unbound Command: {}'.format(statement.args))
-
- with pytest.raises(KeyError):
- assert cmd2.register_command(do_unbound)
-
- # verify only the `unbound` command was installed
- cmds_cats, cmds_doc, cmds_undoc, help_topics = command_sets_manual._build_command_info()
-
- assert 'AAA' in cmds_cats
- assert 'unbound' in cmds_cats['AAA']
- assert 'Alone' not in cmds_cats
- assert 'Command Set' not in cmds_cats
# now install a command set and verify the commands are now present
cmd_set = CommandSetA()
@@ -192,22 +109,6 @@ def test_load_commands(command_sets_manual):
cmds_cats, cmds_doc, cmds_undoc, help_topics = command_sets_manual._build_command_info()
- assert 'AAA' in cmds_cats
- assert 'unbound' in cmds_cats['AAA']
-
- assert 'Alone' in cmds_cats
- assert 'elderberry' in cmds_cats['Alone']
-
- assert 'Command Set' in cmds_cats
- assert 'cranberry' in cmds_cats['Command Set']
-
- # uninstall the `unbound` command and verify only it was uninstalled
- command_sets_manual.uninstall_command('unbound')
-
- cmds_cats, cmds_doc, cmds_undoc, help_topics = command_sets_manual._build_command_info()
-
- assert 'AAA' not in cmds_cats
-
assert 'Alone' in cmds_cats
assert 'elderberry' in cmds_cats['Alone']
@@ -219,17 +120,14 @@ def test_load_commands(command_sets_manual):
cmds_cats, cmds_doc, cmds_undoc, help_topics = command_sets_manual._build_command_info()
- assert 'AAA' not in cmds_cats
assert 'Alone' not in cmds_cats
assert 'Command Set' not in cmds_cats
- # reinstall the command set and verifyt is accessible but the `unbound` command isn't
+ # reinstall the command set and verify it is accessible
command_sets_manual.install_command_set(cmd_set)
cmds_cats, cmds_doc, cmds_undoc, help_topics = command_sets_manual._build_command_info()
- assert 'AAA' not in cmds_cats
-
assert 'Alone' in cmds_cats
assert 'elderberry' in cmds_cats['Alone']
@@ -237,111 +135,6 @@ def test_load_commands(command_sets_manual):
assert 'cranberry' in cmds_cats['Command Set']
-def test_command_functions(command_sets_manual):
- cmds_cats, cmds_doc, cmds_undoc, help_topics = command_sets_manual._build_command_info()
- assert 'AAA' not in cmds_cats
-
- out, err = run_cmd(command_sets_manual, 'command_with_support')
- assert 'is not a recognized command, alias, or macro' in err[0]
-
- out, err = run_cmd(command_sets_manual, 'help command_with_support')
- assert 'No help on command_with_support' in err[0]
-
- text = ''
- line = 'command_with_support'
- endidx = len(line)
- begidx = endidx - len(text)
-
- first_match = complete_tester(text, line, begidx, endidx, command_sets_manual)
- assert first_match is None
-
- # A bad command name gets rejected with an exception
- with pytest.raises(ValueError):
- assert command_sets_manual.install_command_function('>"',
- do_command_with_support,
- complete_command_with_support,
- help_command_with_support)
-
- # create an alias to verify that it gets removed when the command is created
- out, err = run_cmd(command_sets_manual, 'alias create command_with_support run_pyscript')
- assert out == normalize("Alias 'command_with_support' created")
-
- command_sets_manual.install_registered_command('command_with_support')
-
- cmds_cats, cmds_doc, cmds_undoc, help_topics = command_sets_manual._build_command_info()
- assert 'AAA' in cmds_cats
- assert 'command_with_support' in cmds_cats['AAA']
-
- out, err = run_cmd(command_sets_manual, 'command_with_support')
- assert 'Command with support functions' in out[0]
-
- out, err = run_cmd(command_sets_manual, 'help command_with_support')
- assert 'Help for command_with_support' in out[0]
-
- first_match = complete_tester(text, line, begidx, endidx, command_sets_manual)
- assert first_match == 'Ham'
-
- text = ''
- line = 'command_with_support Ham'
- endidx = len(line)
- begidx = endidx - len(text)
-
- first_match = complete_tester(text, line, begidx, endidx, command_sets_manual)
-
- assert first_match == 'Basket'
-
- command_sets_manual.uninstall_command('command_with_support')
-
- cmds_cats, cmds_doc, cmds_undoc, help_topics = command_sets_manual._build_command_info()
- assert 'AAA' not in cmds_cats
-
- out, err = run_cmd(command_sets_manual, 'command_with_support')
- assert 'is not a recognized command, alias, or macro' in err[0]
-
- out, err = run_cmd(command_sets_manual, 'help command_with_support')
- assert 'No help on command_with_support' in err[0]
-
- text = ''
- line = 'command_with_support'
- endidx = len(line)
- begidx = endidx - len(text)
-
- first_match = complete_tester(text, line, begidx, endidx, command_sets_manual)
- assert first_match is None
-
- # create an alias to verify that it gets removed when the command is created
- out, err = run_cmd(command_sets_manual, 'macro create command_with_support run_pyscript')
- assert out == normalize("Macro 'command_with_support' created")
-
- command_sets_manual.install_command_function('command_with_support',
- do_command_with_support,
- complete_command_with_support,
- help_command_with_support)
-
- cmds_cats, cmds_doc, cmds_undoc, help_topics = command_sets_manual._build_command_info()
- assert 'AAA' in cmds_cats
- assert 'command_with_support' in cmds_cats['AAA']
-
- out, err = run_cmd(command_sets_manual, 'command_with_support')
- assert 'Command with support functions' in out[0]
-
- out, err = run_cmd(command_sets_manual, 'help command_with_support')
- assert 'Help for command_with_support' in out[0]
-
- first_match = complete_tester(text, line, begidx, endidx, command_sets_manual)
- assert first_match == 'Ham'
-
- text = ''
- line = 'command_with_support Ham'
- endidx = len(line)
- begidx = endidx - len(text)
-
- first_match = complete_tester(text, line, begidx, endidx, command_sets_manual)
-
- assert first_match == 'Basket'
-
-
-
def test_partial_with_passthru():
def test_func(arg1, arg2):