Skip to content

Commit bd95a11

Browse files
committed
Add argparse stuff to api
1 parent f5806d0 commit bd95a11

File tree

6 files changed

+191
-153
lines changed

6 files changed

+191
-153
lines changed

cmd2/argparse_custom.py

Lines changed: 173 additions & 142 deletions
Original file line numberDiff line numberDiff line change
@@ -1,127 +1,150 @@
11
# coding=utf-8
22
"""
3-
This module adds capabilities to argparse by patching a few of its functions. It also defines a parser
4-
class called Cmd2ArgumentParser which improves error and help output over normal argparse. All cmd2 code uses
5-
this parser and it is recommended that developers of cmd2-based apps either use it or write their own parser
6-
that inherits from it. This will give a consistent look-and-feel between the help/error output of built-in
7-
cmd2 commands and the app-specific commands. If you wish to override the parser used by cmd2's built-in
8-
commands, see override_parser.py example.
3+
This module adds capabilities to argparse by patching a few of its functions.
4+
It also defines a parser class called Cmd2ArgumentParser which improves error
5+
and help output over normal argparse. All cmd2 code uses this parser and it is
6+
recommended that developers of cmd2-based apps either use it or write their own
7+
parser that inherits from it. This will give a consistent look-and-feel between
8+
the help/error output of built-in cmd2 commands and the app-specific commands.
9+
If you wish to override the parser used by cmd2's built-in commands, see
10+
override_parser.py example.
911
10-
Since the new capabilities are added by patching at the argparse API level, they are available whether or not
11-
Cmd2ArgumentParser is used. However, the help and error output of Cmd2ArgumentParser is customized to notate
12-
nargs ranges whereas any other parser class won't be as explicit in their output.
12+
Since the new capabilities are added by patching at the argparse API level,
13+
they are available whether or not Cmd2ArgumentParser is used. However, the help
14+
and error output of Cmd2ArgumentParser is customized to notate nargs ranges
15+
whereas any other parser class won't be as explicit in their output.
1316
14-
############################################################################################################
15-
# Added capabilities
16-
############################################################################################################
1717
18-
Extends argparse nargs functionality by allowing tuples which specify a range (min, max). To specify a max
19-
value with no upper bound, use a 1-item tuple (min,)
20-
21-
Example:
22-
# -f argument expects at least 3 values
23-
parser.add_argument('-f', nargs=(3,))
24-
25-
# -f argument expects 3 to 5 values
26-
parser.add_argument('-f', nargs=(3, 5))
27-
28-
Tab Completion:
29-
cmd2 uses its ArgparseCompleter class to enable argparse-based tab completion on all commands that use the
30-
@with_argparse wrappers. Out of the box you get tab completion of commands, subcommands, and flag names,
31-
as well as instructive hints about the current argument that print when tab is pressed. In addition,
32-
you can add tab completion for each argument's values using parameters passed to add_argument().
33-
34-
Below are the 5 add_argument() parameters for enabling tab completion of an argument's value. Only one
35-
can be used at a time.
36-
37-
choices
38-
Pass a list of values to the choices parameter.
39-
Example:
40-
parser.add_argument('-o', '--options', choices=['An Option', 'SomeOtherOption'])
41-
parser.add_argument('-o', '--options', choices=my_list)
42-
43-
choices_function
44-
Pass a function that returns choices. This is good in cases where the choice list is dynamically
45-
generated when the user hits tab.
46-
47-
Example:
48-
def my_choices_function():
49-
...
50-
return my_generated_list
51-
52-
parser.add_argument('-o', '--options', choices_function=my_choices_function)
53-
54-
choices_method
55-
This is exactly like choices_function, but the function needs to be an instance method of a cmd2-based class.
56-
When ArgparseCompleter calls the method, it will pass the app instance as the self argument. This is good in
57-
cases where the list of choices being generated relies on state data of the cmd2-based app
58-
59-
Example:
60-
def my_choices_method(self):
61-
...
62-
return my_generated_list
63-
64-
completer_function
65-
Pass a tab completion function that does custom completion. Since custom tab completion operations commonly
66-
need to modify cmd2's instance variables related to tab completion, it will be rare to need a completer
67-
function. completer_method should be used in those cases.
68-
69-
Example:
70-
def my_completer_function(text, line, begidx, endidx):
71-
...
72-
return completions
73-
parser.add_argument('-o', '--options', completer_function=my_completer_function)
74-
75-
completer_method
76-
This is exactly like completer_function, but the function needs to be an instance method of a cmd2-based class.
77-
When ArgparseCompleter calls the method, it will pass the app instance as the self argument. cmd2 provides
78-
a few completer methods for convenience (e.g., path_complete, delimiter_complete)
79-
80-
Example:
81-
This adds file-path completion to an argument
82-
parser.add_argument('-o', '--options', completer_method=cmd2.Cmd.path_complete)
83-
84-
85-
You can use functools.partial() to prepopulate values of the underlying choices and completer functions/methods.
86-
87-
Example:
88-
This says to call path_complete with a preset value for its path_filter argument.
89-
completer_method = functools.partial(path_complete,
90-
path_filter=lambda path: os.path.isdir(path))
91-
parser.add_argument('-o', '--options', choices_method=completer_method)
92-
93-
Of the 5 tab completion parameters, choices is the only one where argparse validates user input against items
94-
in the choices list. This is because the other 4 parameters are meant to tab complete data sets that are viewed
95-
as dynamic. Therefore it is up to the developer to validate if the user has typed an acceptable value for these
96-
arguments.
97-
98-
The following functions exist in cases where you may want to manually add a choice-providing function/method to
99-
an existing argparse action. For instance, in __init__() of a custom action class.
100-
101-
set_choices_function(action, func)
102-
set_choices_method(action, method)
103-
set_completer_function(action, func)
104-
set_completer_method(action, method)
105-
106-
There are times when what's being tab completed is determined by a previous argument on the command line.
107-
In theses cases, Autocompleter can pass a dictionary that maps the command line tokens up through the one
108-
being completed to their argparse argument name. To receive this dictionary, your choices/completer function
109-
should have an argument called arg_tokens.
110-
111-
Example:
112-
def my_choices_method(self, arg_tokens)
113-
def my_completer_method(self, text, line, begidx, endidx, arg_tokens)
114-
115-
All values of the arg_tokens dictionary are lists, even if a particular argument expects only 1 token. Since
116-
ArgparseCompleter is for tab completion, it does not convert the tokens to their actual argument types or validate
117-
their values. All tokens are stored in the dictionary as the raw strings provided on the command line. It is up to
118-
the developer to determine if the user entered the correct argument type (e.g. int) and validate their values.
119-
120-
CompletionItem Class:
121-
This class was added to help in cases where uninformative data is being tab completed. For instance,
122-
tab completing ID numbers isn't very helpful to a user without context. Returning a list of CompletionItems
123-
instead of a regular string for completion results will signal the ArgparseCompleter to output the completion
124-
results in a table of completion tokens with descriptions instead of just a table of tokens.
18+
**Added capabilities**
19+
20+
Extends argparse nargs functionality by allowing tuples which specify a range
21+
(min, max). To specify a max value with no upper bound, use a 1-item tuple
22+
(min,)
23+
24+
Example::
25+
26+
# -f argument expects at least 3 values
27+
parser.add_argument('-f', nargs=(3,))
28+
29+
# -f argument expects 3 to 5 values
30+
parser.add_argument('-f', nargs=(3, 5))
31+
32+
33+
**Tab Completion**
34+
35+
cmd2 uses its ArgparseCompleter class to enable argparse-based tab completion
36+
on all commands that use the @with_argparse wrappers. Out of the box you get
37+
tab completion of commands, subcommands, and flag names, as well as instructive
38+
hints about the current argument that print when tab is pressed. In addition,
39+
you can add tab completion for each argument's values using parameters passed
40+
to add_argument().
41+
42+
Below are the 5 add_argument() parameters for enabling tab completion of an
43+
argument's value. Only one can be used at a time.
44+
45+
``choices`` - pass a list of values to the choices parameter.
46+
47+
Example::
48+
49+
parser.add_argument('-o', '--options', choices=['An Option', 'SomeOtherOption'])
50+
parser.add_argument('-o', '--options', choices=my_list)
51+
52+
``choices_function`` - pass a function that returns choices. This is good in
53+
cases where the choice list is dynamically generated when the user hits tab.
54+
55+
Example::
56+
57+
def my_choices_function():
58+
...
59+
return my_generated_list
60+
61+
parser.add_argument('-o', '--options', choices_function=my_choices_function)
62+
63+
``choices_method`` - this is exactly like choices_function, but the function
64+
needs to be an instance method of a cmd2-based class. When ArgparseCompleter
65+
calls the method, it will pass the app instance as the self argument. This is
66+
good in cases where the list of choices being generated relies on state data of
67+
the cmd2-based app
68+
69+
Example::
70+
71+
def my_choices_method(self):
72+
...
73+
return my_generated_list
74+
75+
``completer_function`` - pass a tab completion function that does custom
76+
completion. Since custom tab completion operations commonly need to modify
77+
cmd2's instance variables related to tab completion, it will be rare to need a
78+
completer function. completer_method should be used in those cases.
79+
80+
Example::
81+
82+
def my_completer_function(text, line, begidx, endidx):
83+
...
84+
return completions
85+
parser.add_argument('-o', '--options', completer_function=my_completer_function)
86+
87+
``completer_method`` - this is exactly like completer_function, but the
88+
function needs to be an instance method of a cmd2-based class. When
89+
ArgparseCompleter calls the method, it will pass the app instance as the self
90+
argument. cmd2 provides a few completer methods for convenience (e.g.,
91+
path_complete, delimiter_complete)
92+
93+
Example::
94+
95+
# this adds file-path completion to an argument
96+
parser.add_argument('-o', '--options', completer_method=cmd2.Cmd.path_complete)
97+
98+
99+
You can use functools.partial() to prepopulate values of the underlying
100+
choices and completer functions/methods.
101+
102+
Example::
103+
104+
# this says to call path_complete with a preset value for its path_filter argument.
105+
completer_method = functools.partial(path_complete,
106+
path_filter=lambda path: os.path.isdir(path))
107+
parser.add_argument('-o', '--options', choices_method=completer_method)
108+
109+
Of the 5 tab completion parameters, choices is the only one where argparse
110+
validates user input against items in the choices list. This is because the
111+
other 4 parameters are meant to tab complete data sets that are viewed as
112+
dynamic. Therefore it is up to the developer to validate if the user has typed
113+
an acceptable value for these arguments.
114+
115+
The following functions exist in cases where you may want to manually add a
116+
choice-providing function/method to an existing argparse action. For instance,
117+
in __init__() of a custom action class.
118+
119+
- set_choices_function(action, func)
120+
- set_choices_method(action, method)
121+
- set_completer_function(action, func)
122+
- set_completer_method(action, method)
123+
124+
There are times when what's being tab completed is determined by a previous
125+
argument on the command line. In theses cases, Autocompleter can pass a
126+
dictionary that maps the command line tokens up through the one being completed
127+
to their argparse argument name. To receive this dictionary, your
128+
choices/completer function should have an argument called arg_tokens.
129+
130+
Example::
131+
132+
def my_choices_method(self, arg_tokens)
133+
def my_completer_method(self, text, line, begidx, endidx, arg_tokens)
134+
135+
All values of the arg_tokens dictionary are lists, even if a particular
136+
argument expects only 1 token. Since ArgparseCompleter is for tab completion,
137+
it does not convert the tokens to their actual argument types or validate their
138+
values. All tokens are stored in the dictionary as the raw strings provided on
139+
the command line. It is up to the developer to determine if the user entered
140+
the correct argument type (e.g. int) and validate their values.
141+
142+
CompletionItem Class - This class was added to help in cases where
143+
uninformative data is being tab completed. For instance, tab completing ID
144+
numbers isn't very helpful to a user without context. Returning a list of
145+
CompletionItems instead of a regular string for completion results will signal
146+
the ArgparseCompleter to output the completion results in a table of completion
147+
tokens with descriptions instead of just a table of tokens::
125148
126149
Instead of this:
127150
1 2 3
@@ -133,42 +156,50 @@ def my_completer_method(self, text, line, begidx, endidx, arg_tokens)
133156
3 Yet another item
134157
135158
136-
The left-most column is the actual value being tab completed and its header is that value's name.
137-
The right column header is defined using the descriptive_header parameter of add_argument(). The right
138-
column values come from the CompletionItem.description value.
159+
The left-most column is the actual value being tab completed and its header is
160+
that value's name. The right column header is defined using the
161+
descriptive_header parameter of add_argument(). The right column values come
162+
from the CompletionItem.description value.
163+
164+
Example::
139165
140-
Example:
141-
token = 1
142-
token_description = "My Item"
143-
completion_item = CompletionItem(token, token_description)
166+
token = 1
167+
token_description = "My Item"
168+
completion_item = CompletionItem(token, token_description)
144169
145-
Since descriptive_header and CompletionItem.description are just strings, you can format them in
146-
such a way to have multiple columns.
170+
Since descriptive_header and CompletionItem.description are just strings, you
171+
can format them in such a way to have multiple columns::
147172
148173
ITEM_ID Item Name Checked Out Due Date
149174
1 My item True 02/02/2022
150175
2 Another item False
151176
3 Yet another item False
152177
153-
To use CompletionItems, just return them from your choices or completer functions.
178+
To use CompletionItems, just return them from your choices or completer
179+
functions.
154180
155-
To avoid printing a ton of information to the screen at once when a user presses tab, there is
156-
a maximum threshold for the number of CompletionItems that will be shown. Its value is defined
157-
in cmd2.Cmd.max_completion_items. It defaults to 50, but can be changed. If the number of completion
158-
suggestions exceeds this number, they will be displayed in the typical columnized format and will
159-
not include the description value of the CompletionItems.
181+
To avoid printing a ton of information to the screen at once when a user
182+
presses tab, there is a maximum threshold for the number of CompletionItems
183+
that will be shown. Its value is defined in cmd2.Cmd.max_completion_items. It
184+
defaults to 50, but can be changed. If the number of completion suggestions
185+
exceeds this number, they will be displayed in the typical columnized format
186+
and will not include the description value of the CompletionItems.
160187
161-
############################################################################################################
162-
# Patched argparse functions:
163-
###########################################################################################################
164-
argparse._ActionsContainer.add_argument - adds arguments related to tab completion and enables nargs range parsing
165-
See _add_argument_wrapper for more details on these argument
188+
189+
**Patched argparse functions**
190+
191+
argparse._ActionsContainer.add_argument - adds arguments related to tab
192+
completion and enables nargs range
193+
parsing See _add_argument_wrapper for
194+
more details on these argument
166195
167196
argparse.ArgumentParser._get_nargs_pattern - adds support to for nargs ranges
168-
See _get_nargs_pattern_wrapper for more details
197+
See _get_nargs_pattern_wrapper for
198+
more details
169199
170-
argparse.ArgumentParser._match_argument - adds support to for nargs ranges
171-
See _match_argument_wrapper for more details
200+
argparse.ArgumentParser._match_argument - adds support to for nargs ranges See
201+
_match_argument_wrapper for more
202+
details
172203
"""
173204

174205
import argparse

docs/api/argparse_completer.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
cmd2.argparse_completer
2+
=======================
3+
4+
.. automodule:: cmd2.argparse_completer
5+
:members:

docs/api/argparse_custom.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
cmd2.argparse_custom
2+
====================
3+
4+
.. automodule:: cmd2.argparse_custom
5+
:members:

docs/api/index.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ API Reference
88
parsing
99
decorators
1010
history
11+
argparse_completer
12+
argparse_custom
1113
ansi
1214
utils
1315
plugin

docs/features/argument_processing.rst

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -342,10 +342,8 @@ Argparse Extensions
342342
- ``nargs=(5,)`` - accept 5 or more items
343343
- ``nargs=(8, 12)`` - accept 8 to 12 items
344344

345-
``cmd2`` also provides the ``Cmd2ArgumentParser`` class which inherits from
346-
``argparse.ArgumentParser`` and improves error and help output:
347-
348-
.. autoclass:: cmd2.argparse_custom.Cmd2ArgumentParser
349-
:members:
345+
``cmd2`` also provides the :class:`cmd2.argparse_custom.Cmd2ArgumentParser`
346+
class which inherits from ``argparse.ArgumentParser`` and improves error and
347+
help output.
350348

351349

docs/features/completion.rst

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -69,12 +69,9 @@ CompletionItem For Providing Extra Context
6969
When tab completing things like a unique ID from a database, it can often be
7070
beneficial to provide the user with some extra context about the item being
7171
completed, such as a description. To facilitate this, ``cmd2`` defines the
72-
``CompletionItem`` class which can be returned from any of the 4 completion
73-
functions: ``choices_function``, ``choices_method``, ``completion_function``,
74-
or ``completion_method``.
75-
76-
.. autoclass:: cmd2.argparse_custom.CompletionItem
77-
:members:
72+
:class:`cmd2.argparse_custom.CompletionItem` class which can be returned from
73+
any of the 4 completion functions: ``choices_function``, ``choices_method``,
74+
``completion_function``, or ``completion_method``.
7875

7976
See the argparse_completion_ example or the implementation of the built-in
8077
**set** command for demonstration of how this is used.

0 commit comments

Comments
 (0)