From e1087b8f29341397b09e9a0722a77c025ab20d23 Mon Sep 17 00:00:00 2001 From: Eric Lin Date: Thu, 11 Jun 2020 18:00:07 -0400 Subject: Initial implementation of modular command loading Issue #943 New class CommandSet can be used to tag a class as a command class. If the constructor is simple, the object will automatically be instantiated and loaded. New register_command decorator to tag any arbitrary function as a command. --- examples/modular_commands/__init__.py | 0 examples/modular_commands/commandset_basic.py | 105 +++++++++++++++++++++ examples/modular_commands/commandset_custominit.py | 33 +++++++ 3 files changed, 138 insertions(+) create mode 100644 examples/modular_commands/__init__.py create mode 100644 examples/modular_commands/commandset_basic.py create mode 100644 examples/modular_commands/commandset_custominit.py (limited to 'examples/modular_commands') diff --git a/examples/modular_commands/__init__.py b/examples/modular_commands/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/examples/modular_commands/commandset_basic.py b/examples/modular_commands/commandset_basic.py new file mode 100644 index 00000000..5ad26d97 --- /dev/null +++ b/examples/modular_commands/commandset_basic.py @@ -0,0 +1,105 @@ +# coding=utf-8 +""" +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.utils import CompletionError + + +@register_command +@with_category("AAA") +def do_unbound(cmd: Cmd, statement: Statement): + """ + This is an example of registering an unbound function + :param cmd: + :param statement: + :return: + """ + cmd.poutput('Unbound Command: {}'.format(statement.args)) + + +@with_default_category('Basic Completion') +class BasicCompletionCommandSet(CommandSet): + # List of strings used with completion functions + food_item_strs = ['Pizza', 'Ham', 'Ham Sandwich', 'Potato'] + sport_item_strs = ['Bat', 'Basket', 'Basketball', 'Football', 'Space Ball'] + + # This data is used to demonstrate delimiter_complete + file_strs = \ + [ + '/home/user/file.db', + '/home/user/file space.db', + '/home/user/another.db', + '/home/other user/maps.db', + '/home/other user/tests.db' + ] + + def do_flag_based(self, cmd: Cmd, statement: Statement): + """Tab completes arguments based on a preceding flag using flag_based_complete + -f, --food [completes food items] + -s, --sport [completes sports] + -p, --path [completes local file system paths] + """ + 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""" + flag_dict = \ + { + # Tab complete food items after -f and --food flags in command line + '-f': self.food_item_strs, + '--food': self.food_item_strs, + + # Tab complete sport items after -s and --sport flags in command line + '-s': self.sport_item_strs, + '--sport': self.sport_item_strs, + + # Tab complete using path_complete function after -p and --path flags in command line + '-p': cmd.path_complete, + '--path': cmd.path_complete, + } + + return cmd.flag_based_complete(text, line, begidx, endidx, flag_dict=flag_dict) + + def do_index_based(self, cmd: Cmd, statement: Statement): + """Tab completes first 3 arguments using index_based_complete""" + 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""" + index_dict = \ + { + 1: self.food_item_strs, # Tab complete food items at index 1 in command line + 2: self.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) + + def do_delimiter_complete(self, cmd: Cmd, statement: Statement): + """Tab completes files from a list using delimiter_complete""" + 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)) + + def complete_raise_error(self, cmd: Cmd, text: str, line: str, begidx: int, endidx: int) -> List[str]: + """ + CompletionErrors can be raised if an error occurs while tab completing. + + Example use cases + - Reading a database to retrieve a tab completion data set failed + - A previous command line argument that determines the data set being completed is invalid + """ + raise CompletionError("This is how a CompletionError behaves") + + @with_category('Not Basic Completion') + def do_custom_category(self, cmd: Cmd, statement: Statement): + cmd.poutput('Demonstrates a command that bypasses the default category') diff --git a/examples/modular_commands/commandset_custominit.py b/examples/modular_commands/commandset_custominit.py new file mode 100644 index 00000000..440db850 --- /dev/null +++ b/examples/modular_commands/commandset_custominit.py @@ -0,0 +1,33 @@ +# coding=utf-8 +""" +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 + + +@register_command +@with_category("AAA") +def do_another_command(cmd: Cmd, statement: Statement): + """ + This is an example of registering an unbound function + :param cmd: + :param statement: + :return: + """ + cmd.poutput('Another Unbound Command: {}'.format(statement.args)) + + +@with_default_category('Custom Init') +class CustomInitCommandSet(CommandSet): + def __init__(self, arg1, arg2): + super().__init__() + + self._arg1 = arg1 + self._arg2 = arg2 + + def do_show_arg1(self, cmd: Cmd, _: Statement): + cmd.poutput('Arg1: ' + self._arg1) + + def do_show_arg2(self, cmd: Cmd, _: Statement): + cmd.poutput('Arg2: ' + self._arg2) -- cgit v1.2.1