1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
|
#!/usr/bin/env python
# coding=utf-8
"""A simple example demonstrating how to use flag and index based tab-completion functions
"""
import argparse
import AutoCompleter
import cmd2
from cmd2 import with_argparser
# List of strings used with flag and index based completion functions
food_item_strs = ['Pizza', 'Hamburger', 'Ham', 'Potato']
sport_item_strs = ['Bat', 'Basket', 'Basketball', 'Football']
class TabCompleteExample(cmd2.Cmd):
""" Example cmd2 application where we a base command which has a couple subcommands."""
def __init__(self):
super().__init__()
# This demonstrates a number of customizations of the AutoCompleter version of ArgumentParser
# - The help output will separately group required vs optional flags
# - The help output for arguments with multiple flags or with append=True is more concise
# - ACArgumentParser adds the ability to specify ranges of argument counts in 'nargs'
suggest_parser = AutoCompleter.ACArgumentParser()
suggest_parser.add_argument('-t', '--type', choices=['movie', 'show'], required=True)
suggest_parser.add_argument('-d', '--duration', nargs=(1, 2), action='append',
help='Duration constraint in minutes.\n'
'\tsingle value - maximum duration\n'
'\t[a, b] - duration range')
@with_argparser(suggest_parser)
def do_suggest(self, args):
"""Suggest command demonstrates argparse customizations
See hybrid_suggest and orig_suggest to compare the help output.
"""
if not args.type:
self.do_help('suggest')
def complete_suggest(self, text, line, begidx, endidx):
""" Adds tab completion to media"""
completer = AutoCompleter.AutoCompleter(TabCompleteExample.suggest_parser, 1)
tokens, _ = self.tokens_for_completion(line, begidx, endidx)
results = completer.complete_command(tokens, text, line, begidx, endidx)
return results
# If you prefer the original argparse help output but would like narg ranges, it's possible
# to enable narg ranges without the help changes using this method
suggest_parser_hybrid = argparse.ArgumentParser()
# This registers the custom narg range handling
AutoCompleter.register_custom_actions(suggest_parser_hybrid)
suggest_parser_hybrid.add_argument('-t', '--type', choices=['movie', 'show'], required=True)
suggest_parser_hybrid.add_argument('-d', '--duration', nargs=(1, 2), action='append',
help='Duration constraint in minutes.\n'
'\tsingle value - maximum duration\n'
'\t[a, b] - duration range')
@with_argparser(suggest_parser_hybrid)
def do_hybrid_suggest(self, args):
if not args.type:
self.do_help('orig_suggest')
def complete_hybrid_suggest(self, text, line, begidx, endidx):
""" Adds tab completion to media"""
completer = AutoCompleter.AutoCompleter(TabCompleteExample.suggest_parser_hybrid)
tokens, _ = self.tokens_for_completion(line, begidx, endidx)
results = completer.complete_command(tokens, text, line, begidx, endidx)
return results
# This variant demonstrates the AutoCompleter working with the orginial argparse.
# Base argparse is unable to specify narg ranges. Autocompleter will keep expecting additional arguments
# for the -d/--duration flag until you specify a new flaw or end the list it with '--'
suggest_parser_orig = argparse.ArgumentParser()
suggest_parser_orig.add_argument('-t', '--type', choices=['movie', 'show'], required=True)
suggest_parser_orig.add_argument('-d', '--duration', nargs='+', action='append',
help='Duration constraint in minutes.\n'
'\tsingle value - maximum duration\n'
'\t[a, b] - duration range')
@with_argparser(suggest_parser_orig)
def do_orig_suggest(self, args):
if not args.type:
self.do_help('orig_suggest')
def complete_orig_suggest(self, text, line, begidx, endidx):
""" Adds tab completion to media"""
completer = AutoCompleter.AutoCompleter(TabCompleteExample.suggest_parser_orig)
tokens, _ = self.tokens_for_completion(line, begidx, endidx)
results = completer.complete_command(tokens, text, line, begidx, endidx)
return results
###################################################################################
# The media command demonstrates a completer with multiple layers of subcommands
#
def query_actors(self):
"""Simulating a function that queries and returns a completion values"""
return ['Mark Hamill', 'Harrison Ford', 'Carrie Fisher', 'Alec Guinness', 'Peter Mayhew', 'Anthony Daniels',
'Adam Driver', 'Daisy Ridley', 'John Boyega', 'Oscar Isaac', 'Lupita Nyong\'o', 'Andy Serkis']
def _do_media_movies(self, args):
if not args.command:
self.do_help('media movies')
def _do_media_shows(self, args):
if not args.command:
self.do_help('media shows')
# example choices list
ratings_types = ['G', 'PG', 'PG-13', 'R', 'NC-17']
media_parser = AutoCompleter.ACArgumentParser()
media_types_subparsers = media_parser.add_subparsers(title='Media Types', dest='type')
movies_parser = media_types_subparsers.add_parser('movies')
movies_parser.set_defaults(func=_do_media_movies)
movies_commands_subparsers = movies_parser.add_subparsers(title='Commands', dest='command')
movies_list_parser = movies_commands_subparsers.add_parser('list')
movies_list_parser.add_argument('-t', '--title', help='Title Filter')
movies_list_parser.add_argument('-r', '--rating', help='Rating Filter', nargs='+',
choices=ratings_types)
movies_list_parser.add_argument('-d', '--director', help='Director Filter')
movies_list_parser.add_argument('-a', '--actor', help='Actor Filter', action='append')
movies_add_parser = movies_commands_subparsers.add_parser('add')
movies_add_parser.add_argument('-t', '--title', help='Movie Title', required=True)
movies_add_parser.add_argument('-r', '--rating', help='Movie Rating', choices=ratings_types, required=True)
movies_add_parser.add_argument('-d', '--director', help='Director', action='append', required=True)
movies_add_parser.add_argument('-a', '--actor', help='Actors', action='append', required=True)
movies_delete_parser = movies_commands_subparsers.add_parser('delete')
shows_parser = media_types_subparsers.add_parser('shows')
shows_parser.set_defaults(func=_do_media_shows)
@with_argparser(media_parser)
def do_media(self, args):
"""Media management command demonstrates multiple layers of subcommands being handled by AutoCompleter"""
func = getattr(args, 'func', None)
if func is not None:
# Call whatever subcommand function was selected
func(self, args)
else:
# No subcommand was provided, so call help
self.do_help('media')
# This completer is implemented using a single dictionary to look up completion lists for all layers of
# subcommands. For each argument, AutoCompleter will search for completion values from the provided
# arg_choices dict. This requires careful naming of argparse arguments so that there are no unintentional
# name collisions.
def complete_media(self, text, line, begidx, endidx):
""" Adds tab completion to media"""
static_list_directors = ['J. J. Abrams', 'Irvin Kershner', 'George Lucas', 'Richard Marquand',
'Rian Johnson', 'Gareth Edwards']
choices = {'actor': self.query_actors,
'director': static_list_directors}
completer = AutoCompleter.AutoCompleter(TabCompleteExample.media_parser, arg_choices=choices)
tokens, _ = self.tokens_for_completion(line, begidx, endidx)
results = completer.complete_command(tokens, text, line, begidx, endidx)
return results
if __name__ == '__main__':
app = TabCompleteExample()
app.cmdloop()
|