cmd2.argparse_utils
cmd2.argparse_utils
Module adds capabilities to argparse by patching a few of its functions.
It also defines a parser class called Cmd2ArgumentParser which improves error and help output over normal argparse. All cmd2 code uses this parser and it is required that developers of cmd2-based apps either use it or write their own parser that inherits from it. If you wish to override the parser used by cmd2's built-in commands, see custom_parser.py example.
Added capabilities
Extends argparse nargs functionality by allowing tuples which specify a range (min, max). To specify a max value with no upper bound, use a 1-item tuple (min,)
Example::
# -f argument expects at least 3 values
parser.add_argument("-f", nargs=(3,))
# -f argument expects 3 to 5 values
parser.add_argument("-f", nargs=(3, 5))
Completion
cmd2 uses its ArgparseCompleter class to enable argparse-based completion on all commands that use the @with_argparser decorator. Out of the box you get completion of commands, subcommands, and flag names, as well as instructive hints about the current argument that print when tab is pressed. In addition, you can add completion for each argument's values using parameters passed to add_argument().
Below are the 3 add_argument() parameters for enabling completion of an argument's value. Only one can be used at a time.
choices - pass a list of values to the choices parameter.
Example::
my_list = ["An Option", "SomeOtherOption"]
parser.add_argument("-o", "--options", choices=my_list)
choices_provider - pass a function that returns a Choices object. This is good in
cases where the choices are dynamically generated when the user hits tab.
Example::
def my_choices_provider(self) -> Choices:
...
return my_choices
parser.add_argument("arg", choices_provider=my_choices_provider)
completer - pass a function that does custom completion and returns a Completions object.
cmd2 provides a few completer methods for convenience (e.g., path_complete, delimiter_complete)
Example::
# This adds file-path completion to an argument
parser.add_argument("-o", "--options", completer=cmd2.Cmd.path_complete)
You can use functools.partial() to prepopulate values of the underlying
choices and completer functions/methods.
Example::
# This says to call path_complete with a preset value for its path_filter argument
dir_completer = functools.partial(path_complete, path_filter=lambda path: os.path.isdir(path))
parser.add_argument("-o", "--options", completer=dir_completer)
For choices_provider and completer, do not set them to a bound method. This
is because ArgparseCompleter passes the self argument explicitly to these
functions. When ArgparseCompleter calls one, it will detect whether it is bound
to a Cmd subclass or CommandSet. If bound to a cmd2.Cmd subclass, it will
pass the app instance as the self argument. If bound to a cmd2.CommandSet
subclass, it will pass the CommandSet instance as the self argument.
Therefore instead of passing something like self.path_complete, pass
cmd2.Cmd.path_complete.
choices_provider and completer functions can also be implemented as
standalone functions (i.e. not a member of a class). In this case,
ArgparseCompleter will pass its cmd2.Cmd app instance as the first
positional argument.
Of the 3 completion parameters, choices is the only one where argparse
validates user input against items in the choices list. This is because the
other 2 parameters are meant to complete data sets that are viewed as
dynamic. Therefore it is up to the developer to validate if the user has typed
an acceptable value for these arguments.
There are times when what's being completed is determined by a previous argument on the command line. In these cases, ArgparseCompleter can pass a dictionary that maps the command line tokens up through the one being completed to their argparse argument name. To receive this dictionary, your choices/completer function should have an argument called arg_tokens.
Example::
def my_choices_provider(self, arg_tokens) -> Choices
def my_completer(self, text, line, begidx, endidx, arg_tokens) -> Completions
All values of the arg_tokens dictionary are lists, even if a particular argument expects only 1 token. Since ArgparseCompleter is for completion, it does not convert the tokens to their actual argument types or validate their values. All tokens are stored in the dictionary as the raw strings provided on the command line. It is up to the developer to determine if the user entered the correct argument type (e.g. int) and validate their values.
CompletionItem Class
This class represents a single completion result and what the Choices
and Completion classes contain.
CompletionItem provides the following optional metadata fields which enhance
completion results displayed to the screen.
- display - string for displaying the completion differently in the completion menu
- display_meta - meta information about completion which displays in the completion menu
- table_data - supplemental data for completion tables
They can also be used as argparse choices. When a CompletionItem is created, it
stores the original value (e.g. ID number) and makes it accessible through a property
called value. cmd2 has patched argparse so that when evaluating choices, input
is compared to CompletionItem.value instead of the CompletionItem instance.
Completion Tables
These were added to help in cases where uninformative data is being completed. For instance, completing ID numbers isn't very helpful to a user without context.
Providing table_data in your CompletionItem signals ArgparseCompleter
to output the completion results in a table with supplemental data instead of just a table
of tokens::
Instead of this:
1 2 3
The user sees this:
ITEM_ID Description
────────────────────────────
1 My item
2 Another item
3 Yet another item
The left-most column is the actual value being completed and its header is
that value's name. Any additional column headers are defined using the
table_columns parameter of add_argument(), which is a list of header
names. The supplemental column values come from the
table_data argument to CompletionItem. It's a Sequence with the
same number of items as table_columns.
Example::
Add an argument and define its table_columns.
parser.add_argument(
"item_id",
type=int,
choices_provider=get_choices,
table_columns=["Item Name", "Checked Out", "Due Date"],
)
Implement the choices_provider to return Choices.
def get_choices(self) -> Choices:
"""choices_provider which returns CompletionItems"""
# Populate CompletionItem's table_data argument.
# Its item count should match that of table_columns.
items = [
CompletionItem(1, table_data=["My item", True, "02/02/2022"]),
CompletionItem(2, table_data=["Another item", False, ""]),
CompletionItem(3, table_data=["Yet another item", False, ""]),
]
return Choices(items)
This is what the user will see during completion.
ITEM_ID Item Name Checked Out Due Date
───────────────────────────────────────────────────────
1 My item True 02/02/2022
2 Another item False
3 Yet another item False
table_columns can be strings or Rich.table.Columns for more
control over things like alignment.
-
If a header is a string, it will render as a left-aligned column with its overflow behavior set to "fold". This means a long string will wrap within its cell, creating as many new lines as required to fit.
-
If a header is a
Column, it defaults to "ellipsis" overflow behavior. This means a long string which exceeds the width of its column will be truncated with an ellipsis at the end. You can override this and other settings when you create theColumn.
table_data items can include Rich objects, including styled Text and Tables.
To avoid printing excessive information to the screen at once when a user
presses tab, there is a maximum threshold for the number of CompletionItems
that will be shown. Its value is defined in cmd2.Cmd.max_completion_table_items.
It defaults to 50, but can be changed. If the number of completion suggestions
exceeds this number, then a completion table won't be displayed.
Custom Argument Parameters
argparse._ActionsContainer.add_argument has been patched to support several
custom parameters used for tab completion and nargs range parsing. These
parameters are registered using register_argparse_argument_parameter().
See _ActionsContainer_add_argument for more details on these parameters.
Registering a parameter whitelists it for use in add_argument() and
automatically adds getter and setter accessor methods to the argparse.Action
class. For any registered parameter named <name>, the following methods are
available on the resulting Action object to access its underlying attribute:
action.get_<name>()action.set_<name>(value)
NoParamParserFactory
module-attribute
ClassParamParserFactory
module-attribute
ClassParamParserFactory = Union[
Callable[[type[CmdOrSetT]], "Cmd2ArgumentParser"],
"_ClassParserFactory[CmdOrSetT]",
]
ParserSource
module-attribute
ParserSource = Union[
"Cmd2ArgumentParser",
NoParamParserFactory,
ClassParamParserFactory[CmdOrSetT],
]
orig_actions_container_add_argument
module-attribute
orig_actions_container_add_argument = add_argument
ArgparseCommandSpec
dataclass
Metadata for an argparse-based command function.
| PARAMETER | DESCRIPTION |
|---|---|
parser_source
|
an existing Cmd2ArgumentParser instance or a factory (callable, staticmethod, or classmethod) that returns one.
TYPE:
|
preserve_quotes
|
if True, then arguments passed to argparse maintain their quotes
TYPE:
|
SubcommandSpec
dataclass
Bases: _SubcommandBase
Metadata used to build and register a subcommand.
| PARAMETER | DESCRIPTION |
|---|---|
parser_source
|
an existing Cmd2ArgumentParser instance or a factory (callable, staticmethod, or classmethod) that returns one.
TYPE:
|
SubcommandRecord
dataclass
Bases: _SubcommandBase
A record of a subcommand's configuration and parser.
Used primarily for attaching and detaching subcommands.
| PARAMETER | DESCRIPTION |
|---|---|
parser
|
the built Cmd2ArgumentParser instance for this subcommand
TYPE:
|
Cmd2ArgumentParser
Cmd2ArgumentParser(
prog=None,
usage=None,
description=None,
epilog=None,
parents=(),
formatter_class=Cmd2HelpFormatter,
prefix_chars="-",
fromfile_prefix_chars=None,
argument_default=None,
conflict_handler="error",
add_help=True,
allow_abbrev=True,
exit_on_error=True,
suggest_on_error=False,
color=False,
*,
completer_class=None,
)
Bases: ArgumentParser
Custom ArgumentParser class that improves error and help output.
Initialize the Cmd2ArgumentParser instance.
| PARAMETER | DESCRIPTION |
|---|---|
completer_class
|
optional parameter which specifies a subclass of ArgparseCompleter for custom completion behavior on this parser. If this is None, then it will be set to argparse_completer.DEFAULT_ARGPARSE_COMPLETER.
TYPE:
|
Source code in cmd2/argparse_utils.py
output_to
Context manager to temporarily set the output stream during argparse operations.
This is helpful for directing output for functions like parse_args(), which
default to sys.stdout and lack a file argument.
| PARAMETER | DESCRIPTION |
|---|---|
file
|
the file stream to use for output
TYPE:
|
Source code in cmd2/argparse_utils.py
print_usage
Override to ensure the formatter is aware of the target file.
Source code in cmd2/argparse_utils.py
print_help
Override to ensure the formatter is aware of the target file.
Source code in cmd2/argparse_utils.py
get_subparsers_action
Get the _SubParsersAction for this parser if it exists.
| RETURNS | DESCRIPTION |
|---|---|
_SubParsersAction[Cmd2ArgumentParser]
|
the _SubParsersAction for this parser |
| RAISES | DESCRIPTION |
|---|---|
ValueError
|
if this parser does not support subcommands |
Source code in cmd2/argparse_utils.py
update_prog
Recursively update the prog attribute of this parser and all of its subparsers.
| PARAMETER | DESCRIPTION |
|---|---|
prog
|
new value for this parser's prog attribute
TYPE:
|
Source code in cmd2/argparse_utils.py
find_parser
Find a parser in the hierarchy based on a sequence of subcommand names.
| PARAMETER | DESCRIPTION |
|---|---|
subcommand_path
|
sequence of subcommand names leading to the target parser
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
Cmd2ArgumentParser
|
the discovered parser |
| RAISES | DESCRIPTION |
|---|---|
ValueError
|
if any subcommand in the path is not found or a level doesn't support subcommands |
Source code in cmd2/argparse_utils.py
attach_subcommand
Attach a parser as a subcommand to a command at the specified path.
Note: record.command is not used for navigation here. It is assumed you
are attaching relative to self using subcommand_path. However,
record.command will be updated to reflect the final, absolute path
of the parent parser this subcommand is attached to.
| PARAMETER | DESCRIPTION |
|---|---|
record
|
SubcommandRecord object describing the subcommand
TYPE:
|
subcommand_path
|
sequence of subcommand names leading to the parser that will host the new subcommand. An empty sequence indicates this parser.
TYPE:
|
| RAISES | DESCRIPTION |
|---|---|
TypeError
|
if record.parser is not an instance of Cmd2ArgumentParser (or subclass) |
ValueError
|
if the command path is invalid, doesn't support subcommands, or the subcommand already exists |
Source code in cmd2/argparse_utils.py
detach_subcommand
Detach a subcommand from a command at the specified path.
| PARAMETER | DESCRIPTION |
|---|---|
subcommand_path
|
sequence of subcommand names leading to the parser hosting the subcommand to be detached. An empty sequence indicates this parser.
TYPE:
|
subcommand
|
name of the subcommand to detach
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
SubcommandRecord
|
a SubcommandRecord object describing the detached subcommand |
| RAISES | DESCRIPTION |
|---|---|
ValueError
|
if the command path is invalid or the subcommand doesn't exist |
Source code in cmd2/argparse_utils.py
detach_all_subcommands
Detach all subcommands from a command at the specified path.
| PARAMETER | DESCRIPTION |
|---|---|
subcommand_path
|
sequence of subcommand names leading to the parser hosting the subcommands to be detached. An empty sequence indicates this parser.
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
list[SubcommandRecord]
|
a list of SubcommandRecord objects describing the detached subcommands |
| RAISES | DESCRIPTION |
|---|---|
ValueError
|
if the command path is invalid or the command doesn't support subcommands |
Source code in cmd2/argparse_utils.py
error
Override that applies custom formatting to the error message.
Source code in cmd2/argparse_utils.py
format_help
register
set_defaults
Source code in python3.14/argparse.py
get_default
add_argument
add_argument(dest, ..., name=value, ...) add_argument(option_string, option_string, ..., name=value, ...)
Source code in python3.14/argparse.py
add_argument_group
add_mutually_exclusive_group
add_subparsers
Source code in python3.14/argparse.py
parse_args
Source code in python3.14/argparse.py
parse_known_args
convert_arg_line_to_args
parse_intermixed_args
Source code in python3.14/argparse.py
parse_known_intermixed_args
Source code in python3.14/argparse.py
format_usage
build_range_error
Build an error message when the number of arguments provided is not within the expected range.
Source code in cmd2/argparse_utils.py
register_argparse_argument_parameter
Register a custom parameter for argparse.Action and add accessors to the Action class.
| PARAMETER | DESCRIPTION |
|---|---|
param_name
|
Name of the parameter. This must be a valid Python identifier.
TYPE:
|
validator
|
Optional function to validate and/or transform the parameter value. It accepts the Action instance and the value as arguments.
TYPE:
|
| RAISES | DESCRIPTION |
|---|---|
ValueError
|
if the parameter name is invalid |
KeyError
|
if the new parameter collides with any existing attributes |
Source code in cmd2/argparse_utils.py
set_default_argument_parser
Set the default Cmd2ArgumentParser class for cmd2's built-in commands.
Since built-in commands rely on customizations made in Cmd2ArgumentParser, your custom parser class should inherit from Cmd2ArgumentParser.
This should be called prior to instantiating your CLI object.
See examples/custom_parser.py.