From 09985f668ecdbad87f9fc725e82b3c99cbd2ef5d Mon Sep 17 00:00:00 2001 From: Kevin Van Brunt Date: Thu, 13 Feb 2020 13:47:39 -0500 Subject: Start of new argparse completion example --- examples/argparse_completion.py | 73 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 examples/argparse_completion.py (limited to 'examples/argparse_completion.py') diff --git a/examples/argparse_completion.py b/examples/argparse_completion.py new file mode 100644 index 00000000..e24fc72e --- /dev/null +++ b/examples/argparse_completion.py @@ -0,0 +1,73 @@ +#!/usr/bin/env python +# coding=utf-8 +""" +A simple example demonstrating how to integrate tab completion with argparse-based commands. +""" +import argparse +from typing import List + +from cmd2 import Cmd, Cmd2ArgumentParser, with_argparser +from cmd2.utils import basic_complete + +food_item_strs = ['Pizza', 'Ham', 'Ham Sandwich', 'Potato'] + +# 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 choices_function() -> List[str]: + """Choices functions are useful when the choice list is dynamically generated (e.g. from data in a database)""" + return ['a', 'dynamic', 'list'] + + +def completer_function(text: str, line: str, begidx: int, endidx: int) -> List[str]: + """ + A tab completion function not dependent on instance data. Since custom tab completion operations commonly + need to modify cmd2's instance variables related to tab completion, it will be rare to need a completer + function. completer_method should be used in those cases. + """ + return basic_complete(text, line, begidx, endidx, food_item_strs) + + +class ArgparseCompletion(Cmd): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.sport_item_strs = ['Bat', 'Basket', 'Basketball', 'Football', 'Space Ball'] + + def choices_method(self) -> List[str]: + """Choices methods are useful when the choice list is based on instance data of your application""" + return self.sport_item_strs + + # Parser for complete command + complete_parser = Cmd2ArgumentParser(description="Command demonstrating tab completion with argparse\n" + "Notice even the flags of this command tab complete") + + # Tab complete from a list using argparse choices. Set metavar if you don't + # want the entire choices list showing in the usage text for this command. + complete_parser.add_argument('--choices', choices=food_item_strs, metavar="CHOICE") + + # Tab complete from choices provided by a choices function and choices method + complete_parser.add_argument('--choices_function', choices_function=choices_function) + complete_parser.add_argument('--choices_method', choices_method=choices_method) + + # Tab complete using a completer function and completer method + complete_parser.add_argument('--completer_function', completer_function=completer_function) + complete_parser.add_argument('--completer_method', completer_method=Cmd.path_complete) + + @with_argparser(complete_parser) + def do_complete(self, _: argparse.Namespace) -> None: + """The complete command""" + self.poutput("I do nothing") + + +if __name__ == '__main__': + import sys + app = ArgparseCompletion() + sys.exit(app.cmdloop()) -- cgit v1.2.1 From ee93add8d49210da554958e70006db52dde88d1e Mon Sep 17 00:00:00 2001 From: Kevin Van Brunt Date: Thu, 13 Feb 2020 15:04:00 -0500 Subject: Wrote examples for CompletionError and CompletionItem --- examples/argparse_completion.py | 47 +++++++++++++++++++++++++++++------------ 1 file changed, 34 insertions(+), 13 deletions(-) (limited to 'examples/argparse_completion.py') diff --git a/examples/argparse_completion.py b/examples/argparse_completion.py index e24fc72e..a089f285 100644 --- a/examples/argparse_completion.py +++ b/examples/argparse_completion.py @@ -6,25 +6,16 @@ A simple example demonstrating how to integrate tab completion with argparse-bas import argparse from typing import List -from cmd2 import Cmd, Cmd2ArgumentParser, with_argparser +from cmd2 import Cmd, Cmd2ArgumentParser, with_argparser, CompletionError, CompletionItem from cmd2.utils import basic_complete +# Data source for argparse.choices food_item_strs = ['Pizza', 'Ham', 'Ham Sandwich', 'Potato'] -# 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 choices_function() -> List[str]: """Choices functions are useful when the choice list is dynamically generated (e.g. from data in a database)""" - return ['a', 'dynamic', 'list'] + return ['a', 'dynamic', 'list', 'goes', 'here'] def completer_function(text: str, line: str, begidx: int, endidx: int) -> List[str]: @@ -33,7 +24,18 @@ def completer_function(text: str, line: str, begidx: int, endidx: int) -> List[s need to modify cmd2's instance variables related to tab completion, it will be rare to need a completer function. completer_method should be used in those cases. """ - return basic_complete(text, line, begidx, endidx, food_item_strs) + match_against = ['a', 'dynamic', 'list', 'goes', 'here'] + return basic_complete(text, line, begidx, endidx, match_against) + + +def choices_completion_item() -> List[CompletionItem]: + """Return CompletionItem instead of strings. These give more context to what's being tab completed.""" + items = { + 1: "My item", + 2: "Another item", + 3: "Yet another item" + } + return [CompletionItem(item_id, description) for item_id, description in items.items()] class ArgparseCompletion(Cmd): @@ -45,6 +47,18 @@ class ArgparseCompletion(Cmd): """Choices methods are useful when the choice list is based on instance data of your application""" return self.sport_item_strs + def choices_completion_error(self) -> 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 + """ + if self.debug: + return self.sport_item_strs + raise CompletionError("Debug must be true") + # Parser for complete command complete_parser = Cmd2ArgumentParser(description="Command demonstrating tab completion with argparse\n" "Notice even the flags of this command tab complete") @@ -61,6 +75,13 @@ class ArgparseCompletion(Cmd): complete_parser.add_argument('--completer_function', completer_function=completer_function) complete_parser.add_argument('--completer_method', completer_method=Cmd.path_complete) + # Demonstrate raising a CompletionError while tab completing + complete_parser.add_argument('--completion_error', choices_method=choices_completion_error) + + # Demonstrate returning CompletionItems instead of strings + complete_parser.add_argument('--completion_item', choices_function=choices_completion_item, metavar="ITEM_ID", + descriptive_header="Description") + @with_argparser(complete_parser) def do_complete(self, _: argparse.Namespace) -> None: """The complete command""" -- cgit v1.2.1 From 8cfc02d4fe7f33549ce190aec30535800651e705 Mon Sep 17 00:00:00 2001 From: Kevin Van Brunt Date: Thu, 13 Feb 2020 15:28:45 -0500 Subject: Finished argparse completion example --- examples/argparse_completion.py | 70 ++++++++++++++++++++++++++++------------- 1 file changed, 49 insertions(+), 21 deletions(-) (limited to 'examples/argparse_completion.py') diff --git a/examples/argparse_completion.py b/examples/argparse_completion.py index a089f285..90975d3f 100644 --- a/examples/argparse_completion.py +++ b/examples/argparse_completion.py @@ -4,7 +4,7 @@ A simple example demonstrating how to integrate tab completion with argparse-based commands. """ import argparse -from typing import List +from typing import Dict, List from cmd2 import Cmd, Cmd2ArgumentParser, with_argparser, CompletionError, CompletionItem from cmd2.utils import basic_complete @@ -30,14 +30,31 @@ def completer_function(text: str, line: str, begidx: int, endidx: int) -> List[s def choices_completion_item() -> List[CompletionItem]: """Return CompletionItem instead of strings. These give more context to what's being tab completed.""" - items = { - 1: "My item", - 2: "Another item", - 3: "Yet another item" - } + items = \ + { + 1: "My item", + 2: "Another item", + 3: "Yet another item" + } return [CompletionItem(item_id, description) for item_id, description in items.items()] +def choices_arg_tokens(arg_tokens: Dict[str, List[str]]) -> List[str]: + """ + If a choices or completer function/method takes a value called arg_tokens, then it will be + passed a dictionary that maps the command line tokens up through the one being completed + to their argparse argument name. All values of the arg_tokens dictionary are lists, even if + a particular argument expects only 1 token. + """ + # Check if choices_function flag has appeared + values = ['choices_function', 'flag'] + if 'choices_function' in arg_tokens: + values.append('is {}'.format(arg_tokens['choices_function'][0])) + else: + values.append('not supplied') + return values + + class ArgparseCompletion(Cmd): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) @@ -57,34 +74,45 @@ class ArgparseCompletion(Cmd): """ if self.debug: return self.sport_item_strs - raise CompletionError("Debug must be true") + raise CompletionError("debug must be true") - # Parser for complete command - complete_parser = Cmd2ArgumentParser(description="Command demonstrating tab completion with argparse\n" - "Notice even the flags of this command tab complete") + # Parser for example command + example_parser = Cmd2ArgumentParser(description="Command demonstrating tab completion with argparse\n" + "Notice even the flags of this command tab complete") # Tab complete from a list using argparse choices. Set metavar if you don't # want the entire choices list showing in the usage text for this command. - complete_parser.add_argument('--choices', choices=food_item_strs, metavar="CHOICE") + example_parser.add_argument('--choices', choices=food_item_strs, metavar="CHOICE", + help="tab complete using choices") # Tab complete from choices provided by a choices function and choices method - complete_parser.add_argument('--choices_function', choices_function=choices_function) - complete_parser.add_argument('--choices_method', choices_method=choices_method) + example_parser.add_argument('--choices_function', choices_function=choices_function, + help="tab complete using a choices_function") + example_parser.add_argument('--choices_method', choices_method=choices_method, + help="tab complete using a choices_method") # Tab complete using a completer function and completer method - complete_parser.add_argument('--completer_function', completer_function=completer_function) - complete_parser.add_argument('--completer_method', completer_method=Cmd.path_complete) + example_parser.add_argument('--completer_function', completer_function=completer_function, + help="tab complete using a completer_function") + example_parser.add_argument('--completer_method', completer_method=Cmd.path_complete, + help="tab complete using a completer_method") # Demonstrate raising a CompletionError while tab completing - complete_parser.add_argument('--completion_error', choices_method=choices_completion_error) + example_parser.add_argument('--completion_error', choices_method=choices_completion_error, + help="raise a CompletionError while tab completing if debug is False") # Demonstrate returning CompletionItems instead of strings - complete_parser.add_argument('--completion_item', choices_function=choices_completion_item, metavar="ITEM_ID", - descriptive_header="Description") + example_parser.add_argument('--completion_item', choices_function=choices_completion_item, metavar="ITEM_ID", + descriptive_header="Description", + help="demonstrate use of CompletionItems") + + # Demonstrate use of arg_tokens dictionary + example_parser.add_argument('--arg_tokens', choices_function=choices_arg_tokens, + help="demonstrate use of arg_tokens dictionary") - @with_argparser(complete_parser) - def do_complete(self, _: argparse.Namespace) -> None: - """The complete command""" + @with_argparser(example_parser) + def do_example(self, _: argparse.Namespace) -> None: + """The example command""" self.poutput("I do nothing") -- cgit v1.2.1