Skip to content

cmd2.argparse_custom

cmd2.argparse_custom

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 recommended that developers of cmd2-based apps either use it or write their own parser that inherits from it. This will give a consistent look-and-feel between the help/error output of built-in cmd2 commands and the app-specific commands. If you wish to override the parser used by cmd2's built-in commands, see custom_parser.py example.

Since the new capabilities are added by patching at the argparse API level, they are available whether or not Cmd2ArgumentParser is used. However, the help and error output of Cmd2ArgumentParser is customized to notate nargs ranges whereas any other parser class won't be as explicit in their output.

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))

Tab Completion

cmd2 uses its ArgparseCompleter class to enable argparse-based tab completion on all commands that use the @with_argparse wrappers. Out of the box you get tab 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 tab completion for each argument's values using parameters passed to add_argument().

Below are the 3 add_argument() parameters for enabling tab 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 choices. This is good in cases where the choice list is dynamically generated when the user hits tab.

Example::

    def my_choices_provider(self):
        ...
        return my_generated_list

    parser.add_argument("arg", choices_provider=my_choices_provider)

completer - pass a tab completion function that does custom completion.

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 tab 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 tab 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 tab 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)
    def my_completer(self, text, line, begidx, endidx, arg_tokens)

All values of the arg_tokens dictionary are lists, even if a particular argument expects only 1 token. Since ArgparseCompleter is for tab 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 was added to help in cases where uninformative data is being tab completed. For instance, tab completing ID numbers isn't very helpful to a user without context. Returning a list of CompletionItems instead of a regular string for completion results will signal the ArgparseCompleter to output the completion results in a table of completion tokens with descriptive 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 tab completed and its header is that value's name. The right column header is defined using the descriptive_headers parameter of add_argument(), which is a list of header names that defaults to ["Description"]. The right column values come from the CompletionItem.descriptive_data member, which is a list with the same number of items as columns defined in descriptive_headers.

To use CompletionItems, just return them from your choices_provider or completer functions. 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 orig_value. cmd2 has patched argparse so that when evaluating choices, input is compared to CompletionItem.orig_value instead of the CompletionItem instance.

Example::

Add an argument and define its descriptive_headers.

    parser.add_argument(
        add_argument(
        "item_id",
        type=int,
        choices_provider=get_items,
        descriptive_headers=["Item Name", "Checked Out", "Due Date"],
    )

Implement the choices_provider to return CompletionItems.

    def get_items(self) -> list[CompletionItems]:
        """choices_provider which returns CompletionItems"""

        # CompletionItem's second argument is descriptive_data.
        # Its item count should match that of descriptive_headers.
        return [
            CompletionItem(1, ["My item", True, "02/02/2022"]),
            CompletionItem(2, ["Another item", False, ""]),
            CompletionItem(3, ["Yet another item", False, ""]),
        ]

This is what the user will see during tab 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

descriptive_headers 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 the Column.

descriptive_data items can include Rich objects, including styled Text and Tables.

To avoid printing a 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_items. It defaults to 50, but can be changed. If the number of completion suggestions exceeds this number, they will be displayed in the typical columnized format and will not include the descriptive_data of the CompletionItems.

Patched argparse functions

argparse._ActionsContainer.add_argument - adds arguments related to tab completion and enables nargs range parsing. See _add_argument_wrapper for more details on these arguments.

argparse.ArgumentParser._check_value - adds support for using CompletionItems as argparse choices. When evaluating choices, input is compared to CompletionItem.orig_value instead of the CompletionItem instance. See _ArgumentParser_check_value for more details.

argparse.ArgumentParser._get_nargs_pattern - adds support for nargs ranges. See _get_nargs_pattern_wrapper for more details.

argparse.ArgumentParser._match_argument - adds support for nargs ranges. See _match_argument_wrapper for more details.

argparse._SubParsersAction.remove_parser - new function which removes a sub-parser from a sub-parsers group. See _SubParsersAction_remove_parser for more details.

Added accessor methods

cmd2 has patched argparse.Action to include the following accessor methods for cases in which you need to manually access the cmd2-specific attributes.

  • argparse.Action.get_choices_callable() - See action_get_choices_callable for more details.
  • argparse.Action.set_choices_provider() - See _action_set_choices_provider for more details.
  • argparse.Action.set_completer() - See _action_set_completer for more details.
  • argparse.Action.get_descriptive_headers() - See _action_get_descriptive_headers for more details.
  • argparse.Action.set_descriptive_headers() - See _action_set_descriptive_headers for more details.
  • argparse.Action.get_nargs_range() - See _action_get_nargs_range for more details.
  • argparse.Action.set_nargs_range() - See _action_set_nargs_range for more details.
  • argparse.Action.get_suppress_tab_hint() - See _action_get_suppress_tab_hint for more details.
  • argparse.Action.set_suppress_tab_hint() - See _action_set_suppress_tab_hint for more details.

cmd2 has patched argparse.ArgumentParser to include the following accessor methods

  • argparse.ArgumentParser.get_ap_completer_type() - See _ArgumentParser_get_ap_completer_type for more details.
  • argparse.Action.set_ap_completer_type() - See _ArgumentParser_set_ap_completer_type for more details.

Subcommand removal

cmd2 has patched argparse._SubParsersAction to include a remove_parser() method which can be used to remove a subcommand.

argparse._SubParsersAction.remove_parser - new function which removes a sub-parser from a sub-parsers group. See _SubParsersAction_remove_parser` for more details.

ChoicesProviderFunc module-attribute

CompleterFunc module-attribute

ATTR_CHOICES_CALLABLE module-attribute

ATTR_CHOICES_CALLABLE = 'choices_callable'

ATTR_DESCRIPTIVE_HEADERS module-attribute

ATTR_DESCRIPTIVE_HEADERS = 'descriptive_headers'

ATTR_NARGS_RANGE module-attribute

ATTR_NARGS_RANGE = 'nargs_range'

ATTR_SUPPRESS_TAB_HINT module-attribute

ATTR_SUPPRESS_TAB_HINT = 'suppress_tab_hint'

CUSTOM_ACTION_ATTRIBS module-attribute

CUSTOM_ACTION_ATTRIBS = set()

orig_actions_container_add_argument module-attribute

orig_actions_container_add_argument = add_argument

orig_argument_parser_get_nargs_pattern module-attribute

orig_argument_parser_get_nargs_pattern = _get_nargs_pattern

orig_argument_parser_match_argument module-attribute

orig_argument_parser_match_argument = _match_argument

ATTR_AP_COMPLETER_TYPE module-attribute

ATTR_AP_COMPLETER_TYPE = 'ap_completer_type'

DEFAULT_ARGUMENT_PARSER module-attribute

DEFAULT_ARGUMENT_PARSER = Cmd2ArgumentParser

CompletionItem

CompletionItem(value, descriptive_data, *args)

Bases: str

Completion item with descriptive text attached.

See header of this file for more information

CompletionItem Initializer.

PARAMETER DESCRIPTION
value

the value being tab completed

TYPE: object

descriptive_data

a list of descriptive data to display in the columns that follow the completion value. The number of items in this list must equal the number of descriptive headers defined for the argument.

TYPE: Sequence[Any]

args

args for str init

TYPE: Any DEFAULT: ()

Source code in cmd2/argparse_custom.py
def __init__(self, value: object, descriptive_data: Sequence[Any], *args: Any) -> None:
    """CompletionItem Initializer.

    :param value: the value being tab completed
    :param descriptive_data: a list of descriptive data to display in the columns that follow
                             the completion value. The number of items in this list must equal
                             the number of descriptive headers defined for the argument.
    :param args: args for str __init__
    """
    super().__init__(*args)

    # Make sure all objects are renderable by a Rich table.
    renderable_data = [obj if is_renderable(obj) else str(obj) for obj in descriptive_data]

    # Convert strings containing ANSI style sequences to Rich Text objects for correct display width.
    self.descriptive_data = ru.prepare_objects_for_rendering(*renderable_data)

    # Save the original value to support CompletionItems as argparse choices.
    # cmd2 has patched argparse so input is compared to this value instead of the CompletionItem instance.
    self._orig_value = value

descriptive_data instance-attribute

descriptive_data = prepare_objects_for_rendering(*renderable_data)

orig_value property

orig_value

Read-only property for _orig_value.

ChoicesProviderFuncBase

Bases: Protocol

Function that returns a list of choices in support of tab completion.

ChoicesProviderFuncWithTokens

Bases: Protocol

Function that returns a list of choices in support of tab completion and accepts a dictionary of prior arguments.

CompleterFuncBase

Bases: Protocol

Function to support tab completion with the provided state of the user prompt.

CompleterFuncWithTokens

Bases: Protocol

Function to support tab completion with the provided state of the user prompt, accepts a dictionary of prior args.

ChoicesCallable

ChoicesCallable(is_completer, to_call)

Enables using a callable as the choices provider for an argparse argument.

While argparse has the built-in choices attribute, it is limited to an iterable.

Initialize the ChoiceCallable instance.

PARAMETER DESCRIPTION
is_completer

True if to_call is a tab completion routine which expects the args: text, line, begidx, endidx

TYPE: bool

to_call

the callable object that will be called to provide choices for the argument.

TYPE: CompleterFunc | ChoicesProviderFunc

Source code in cmd2/argparse_custom.py
def __init__(
    self,
    is_completer: bool,
    to_call: CompleterFunc | ChoicesProviderFunc,
) -> None:
    """Initialize the ChoiceCallable instance.

    :param is_completer: True if to_call is a tab completion routine which expects
                         the args: text, line, begidx, endidx
    :param to_call: the callable object that will be called to provide choices for the argument.
    """
    self.is_completer = is_completer
    if is_completer:
        if not isinstance(to_call, (CompleterFuncBase, CompleterFuncWithTokens)):  # pragma: no cover
            # runtime checking of Protocols do not currently check the parameters of a function.
            raise ValueError(
                'With is_completer set to true, to_call must be either CompleterFunc, CompleterFuncWithTokens'
            )
    elif not isinstance(to_call, (ChoicesProviderFuncBase, ChoicesProviderFuncWithTokens)):  # pragma: no cover
        # runtime checking of Protocols do not currently check the parameters of a function.
        raise ValueError(
            'With is_completer set to false, to_call must be either: '
            'ChoicesProviderFuncBase, ChoicesProviderFuncWithTokens'
        )
    self.to_call = to_call

is_completer instance-attribute

is_completer = is_completer

to_call instance-attribute

to_call = to_call

completer property

completer

Retreive the internal Completer function, first type checking to ensure it is the right type.

choices_provider property

choices_provider

Retreive the internal ChoicesProvider function, first type checking to ensure it is the right type.

Cmd2HelpFormatter

Cmd2HelpFormatter(prog, indent_increment=2, max_help_position=24, width=None, *, console=None, **kwargs)

Bases: RichHelpFormatter

Custom help formatter to configure ordering of help text.

Initialize Cmd2HelpFormatter.

Source code in cmd2/argparse_custom.py
def __init__(
    self,
    prog: str,
    indent_increment: int = 2,
    max_help_position: int = 24,
    width: int | None = None,
    *,
    console: Cmd2RichArgparseConsole | None = None,
    **kwargs: Any,
) -> None:
    """Initialize Cmd2HelpFormatter."""
    super().__init__(prog, indent_increment, max_help_position, width, console=console, **kwargs)

    # Recast to assist type checkers
    self._console: Cmd2RichArgparseConsole | None

highlights class-attribute

highlights = []

usage_markup class-attribute

usage_markup = False

help_markup class-attribute

help_markup = False

text_markup class-attribute

text_markup = False

console property writable

console

Return our console instance.

RawDescriptionCmd2HelpFormatter

RawDescriptionCmd2HelpFormatter(prog, indent_increment=2, max_help_position=24, width=None, *, console=None, **kwargs)

Bases: RawDescriptionRichHelpFormatter, Cmd2HelpFormatter

Cmd2 help message formatter which retains any formatting in descriptions and epilogs.

Initialize Cmd2HelpFormatter.

Source code in cmd2/argparse_custom.py
def __init__(
    self,
    prog: str,
    indent_increment: int = 2,
    max_help_position: int = 24,
    width: int | None = None,
    *,
    console: Cmd2RichArgparseConsole | None = None,
    **kwargs: Any,
) -> None:
    """Initialize Cmd2HelpFormatter."""
    super().__init__(prog, indent_increment, max_help_position, width, console=console, **kwargs)

    # Recast to assist type checkers
    self._console: Cmd2RichArgparseConsole | None

highlights class-attribute

highlights = []

usage_markup class-attribute

usage_markup = False

help_markup class-attribute

help_markup = False

text_markup class-attribute

text_markup = False

console property writable

console

Return our console instance.

RawTextCmd2HelpFormatter

RawTextCmd2HelpFormatter(prog, indent_increment=2, max_help_position=24, width=None, *, console=None, **kwargs)

Bases: RawTextRichHelpFormatter, Cmd2HelpFormatter

Cmd2 help message formatter which retains formatting of all help text.

Initialize Cmd2HelpFormatter.

Source code in cmd2/argparse_custom.py
def __init__(
    self,
    prog: str,
    indent_increment: int = 2,
    max_help_position: int = 24,
    width: int | None = None,
    *,
    console: Cmd2RichArgparseConsole | None = None,
    **kwargs: Any,
) -> None:
    """Initialize Cmd2HelpFormatter."""
    super().__init__(prog, indent_increment, max_help_position, width, console=console, **kwargs)

    # Recast to assist type checkers
    self._console: Cmd2RichArgparseConsole | None

highlights class-attribute

highlights = []

usage_markup class-attribute

usage_markup = False

help_markup class-attribute

help_markup = False

text_markup class-attribute

text_markup = False

console property writable

console

Return our console instance.

ArgumentDefaultsCmd2HelpFormatter

ArgumentDefaultsCmd2HelpFormatter(prog, indent_increment=2, max_help_position=24, width=None, *, console=None, **kwargs)

Bases: ArgumentDefaultsRichHelpFormatter, Cmd2HelpFormatter

Cmd2 help message formatter which adds default values to argument help.

Initialize Cmd2HelpFormatter.

Source code in cmd2/argparse_custom.py
def __init__(
    self,
    prog: str,
    indent_increment: int = 2,
    max_help_position: int = 24,
    width: int | None = None,
    *,
    console: Cmd2RichArgparseConsole | None = None,
    **kwargs: Any,
) -> None:
    """Initialize Cmd2HelpFormatter."""
    super().__init__(prog, indent_increment, max_help_position, width, console=console, **kwargs)

    # Recast to assist type checkers
    self._console: Cmd2RichArgparseConsole | None

highlights class-attribute

highlights = []

usage_markup class-attribute

usage_markup = False

help_markup class-attribute

help_markup = False

text_markup class-attribute

text_markup = False

console property writable

console

Return our console instance.

MetavarTypeCmd2HelpFormatter

MetavarTypeCmd2HelpFormatter(prog, indent_increment=2, max_help_position=24, width=None, *, console=None, **kwargs)

Bases: MetavarTypeRichHelpFormatter, Cmd2HelpFormatter

Cmd2 help message formatter which uses the argument 'type' as the default metavar value (instead of the argument 'dest').

Initialize Cmd2HelpFormatter.

Source code in cmd2/argparse_custom.py
def __init__(
    self,
    prog: str,
    indent_increment: int = 2,
    max_help_position: int = 24,
    width: int | None = None,
    *,
    console: Cmd2RichArgparseConsole | None = None,
    **kwargs: Any,
) -> None:
    """Initialize Cmd2HelpFormatter."""
    super().__init__(prog, indent_increment, max_help_position, width, console=console, **kwargs)

    # Recast to assist type checkers
    self._console: Cmd2RichArgparseConsole | None

highlights class-attribute

highlights = []

usage_markup class-attribute

usage_markup = False

help_markup class-attribute

help_markup = False

text_markup class-attribute

text_markup = False

console property writable

console

Return our console instance.

TextGroup

TextGroup(title, text, formatter_creator)

A block of text which is formatted like an argparse argument group, including a title.

Title: Here is the first row of text. Here is yet another row of text.

TextGroup initializer.

PARAMETER DESCRIPTION
title

the group's title

TYPE: str

text

the group's text (string or object that may be rendered by Rich)

TYPE: RenderableType

formatter_creator

callable which returns a Cmd2HelpFormatter instance

TYPE: Callable[[], Cmd2HelpFormatter]

Source code in cmd2/argparse_custom.py
def __init__(
    self,
    title: str,
    text: RenderableType,
    formatter_creator: Callable[[], Cmd2HelpFormatter],
) -> None:
    """TextGroup initializer.

    :param title: the group's title
    :param text: the group's text (string or object that may be rendered by Rich)
    :param formatter_creator: callable which returns a Cmd2HelpFormatter instance
    """
    self.title = title
    self.text = text
    self.formatter_creator = formatter_creator

title instance-attribute

title = title

text instance-attribute

text = text

formatter_creator instance-attribute

formatter_creator = formatter_creator

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, *, ap_completer_type=None)

Bases: ArgumentParser

Custom ArgumentParser class that improves error and help output.

Initialize the Cmd2ArgumentParser instance, a custom ArgumentParser added by cmd2.

PARAMETER DESCRIPTION
ap_completer_type

optional parameter which specifies a subclass of ArgparseCompleter for custom tab completion behavior on this parser. If this is None or not present, then cmd2 will use argparse_completer.DEFAULT_AP_COMPLETER when tab completing this parser's arguments

TYPE: type[ArgparseCompleter] | None DEFAULT: None

Source code in cmd2/argparse_custom.py
def __init__(
    self,
    prog: str | None = None,
    usage: str | None = None,
    description: RenderableType | None = None,
    epilog: RenderableType | None = None,
    parents: Sequence[argparse.ArgumentParser] = (),
    formatter_class: type[Cmd2HelpFormatter] = Cmd2HelpFormatter,
    prefix_chars: str = '-',
    fromfile_prefix_chars: str | None = None,
    argument_default: str | None = None,
    conflict_handler: str = 'error',
    add_help: bool = True,
    allow_abbrev: bool = True,
    exit_on_error: bool = True,
    suggest_on_error: bool = False,
    color: bool = False,
    *,
    ap_completer_type: type['ArgparseCompleter'] | None = None,
) -> None:
    """Initialize the Cmd2ArgumentParser instance, a custom ArgumentParser added by cmd2.

    :param ap_completer_type: optional parameter which specifies a subclass of ArgparseCompleter for custom tab completion
                              behavior on this parser. If this is None or not present, then cmd2 will use
                              argparse_completer.DEFAULT_AP_COMPLETER when tab completing this parser's arguments
    """
    kwargs: dict[str, bool] = {}
    if sys.version_info >= (3, 14):
        # Python >= 3.14 so pass new arguments to parent argparse.ArgumentParser class
        kwargs = {
            "suggest_on_error": suggest_on_error,
            "color": color,
        }

    super().__init__(
        prog=prog,
        usage=usage,
        description=description,  # type: ignore[arg-type]
        epilog=epilog,  # type: ignore[arg-type]
        parents=parents or [],
        formatter_class=formatter_class,
        prefix_chars=prefix_chars,
        fromfile_prefix_chars=fromfile_prefix_chars,
        argument_default=argument_default,
        conflict_handler=conflict_handler,
        add_help=add_help,
        allow_abbrev=allow_abbrev,
        exit_on_error=exit_on_error,  # added in Python 3.9
        **kwargs,  # added in Python 3.14
    )

    # Recast to assist type checkers since these can be Rich renderables in a Cmd2HelpFormatter.
    self.description: RenderableType | None  # type: ignore[assignment]
    self.epilog: RenderableType | None  # type: ignore[assignment]

    self.set_ap_completer_type(ap_completer_type)  # type: ignore[attr-defined]

description instance-attribute

description

epilog instance-attribute

epilog

argument_default instance-attribute

argument_default = argument_default

prefix_chars instance-attribute

prefix_chars = prefix_chars

conflict_handler instance-attribute

conflict_handler = conflict_handler

prog instance-attribute

prog = prog

usage instance-attribute

usage = usage

formatter_class instance-attribute

formatter_class = formatter_class

fromfile_prefix_chars instance-attribute

fromfile_prefix_chars = fromfile_prefix_chars

add_help instance-attribute

add_help = add_help

allow_abbrev instance-attribute

allow_abbrev = allow_abbrev

exit_on_error instance-attribute

exit_on_error = exit_on_error

add_subparsers

add_subparsers(**kwargs)

Add a subcommand parser.

Set a default title if one was not given.

PARAMETER DESCRIPTION
kwargs

additional keyword arguments

TYPE: Any DEFAULT: {}

RETURNS DESCRIPTION
_SubParsersAction

argparse Subparser Action

Source code in cmd2/argparse_custom.py
def add_subparsers(self, **kwargs: Any) -> argparse._SubParsersAction:  # type: ignore[type-arg]
    """Add a subcommand parser.

    Set a default title if one was not given.

    :param kwargs: additional keyword arguments
    :return: argparse Subparser Action
    """
    if 'title' not in kwargs:
        kwargs['title'] = 'subcommands'

    return super().add_subparsers(**kwargs)

error

error(message)

Override that applies custom formatting to the error message.

Source code in cmd2/argparse_custom.py
def error(self, message: str) -> NoReturn:
    """Override that applies custom formatting to the error message."""
    lines = message.split('\n')
    formatted_message = ''
    for linum, line in enumerate(lines):
        if linum == 0:
            formatted_message = 'Error: ' + line
        else:
            formatted_message += '\n       ' + line

    self.print_usage(sys.stderr)

    # Use console to add style since it will respect ALLOW_STYLE's value
    console = self._get_formatter().console
    with console.capture() as capture:
        console.print(formatted_message, style=Cmd2Style.ERROR)
    formatted_message = f"{capture.get()}"

    self.exit(2, f'{formatted_message}\n')

format_help

format_help()

Override to add a newline.

Source code in cmd2/argparse_custom.py
def format_help(self) -> str:
    """Override to add a newline."""
    return super().format_help() + '\n'

create_text_group

create_text_group(title, text)

Create a TextGroup using this parser's formatter creator.

Source code in cmd2/argparse_custom.py
def create_text_group(self, title: str, text: RenderableType) -> TextGroup:
    """Create a TextGroup using this parser's formatter creator."""
    return TextGroup(title, text, self._get_formatter)

register

register(registry_name, value, object)
Source code in python3.13/argparse.py
def register(self, registry_name, value, object):
    registry = self._registries.setdefault(registry_name, {})
    registry[value] = object

set_defaults

set_defaults(**kwargs)
Source code in python3.13/argparse.py
def set_defaults(self, **kwargs):
    self._defaults.update(kwargs)

    # if these defaults match any existing arguments, replace
    # the previous default on the object with the new one
    for action in self._actions:
        if action.dest in kwargs:
            action.default = kwargs[action.dest]

get_default

get_default(dest)
Source code in python3.13/argparse.py
def get_default(self, dest):
    for action in self._actions:
        if action.dest == dest and action.default is not None:
            return action.default
    return self._defaults.get(dest, None)

add_argument

add_argument(*args, **kwargs)

add_argument(dest, ..., name=value, ...) add_argument(option_string, option_string, ..., name=value, ...)

Source code in python3.13/argparse.py
def add_argument(self, *args, **kwargs):
    """
    add_argument(dest, ..., name=value, ...)
    add_argument(option_string, option_string, ..., name=value, ...)
    """

    # if no positional args are supplied or only one is supplied and
    # it doesn't look like an option string, parse a positional
    # argument
    chars = self.prefix_chars
    if not args or len(args) == 1 and args[0][0] not in chars:
        if args and 'dest' in kwargs:
            raise ValueError('dest supplied twice for positional argument')
        kwargs = self._get_positional_kwargs(*args, **kwargs)

    # otherwise, we're adding an optional argument
    else:
        kwargs = self._get_optional_kwargs(*args, **kwargs)

    # if no default was supplied, use the parser-level default
    if 'default' not in kwargs:
        dest = kwargs['dest']
        if dest in self._defaults:
            kwargs['default'] = self._defaults[dest]
        elif self.argument_default is not None:
            kwargs['default'] = self.argument_default

    # create the action object, and add it to the parser
    action_class = self._pop_action_class(kwargs)
    if not callable(action_class):
        raise ValueError('unknown action "%s"' % (action_class,))
    action = action_class(**kwargs)

    # raise an error if the action type is not callable
    type_func = self._registry_get('type', action.type, action.type)
    if not callable(type_func):
        raise ValueError('%r is not callable' % (type_func,))

    if type_func is FileType:
        raise ValueError('%r is a FileType class object, instance of it'
                         ' must be passed' % (type_func,))

    # raise an error if the metavar does not match the type
    if hasattr(self, "_get_formatter"):
        try:
            self._get_formatter()._format_args(action, None)
        except TypeError:
            raise ValueError("length of metavar tuple does not match nargs")

    return self._add_action(action)

add_argument_group

add_argument_group(*args, **kwargs)
Source code in python3.13/argparse.py
def add_argument_group(self, *args, **kwargs):
    group = _ArgumentGroup(self, *args, **kwargs)
    self._action_groups.append(group)
    return group

add_mutually_exclusive_group

add_mutually_exclusive_group(**kwargs)
Source code in python3.13/argparse.py
def add_mutually_exclusive_group(self, **kwargs):
    group = _MutuallyExclusiveGroup(self, **kwargs)
    self._mutually_exclusive_groups.append(group)
    return group

parse_args

parse_args(args=None, namespace=None)
Source code in python3.13/argparse.py
def parse_args(self, args=None, namespace=None):
    args, argv = self.parse_known_args(args, namespace)
    if argv:
        msg = _('unrecognized arguments: %s') % ' '.join(argv)
        if self.exit_on_error:
            self.error(msg)
        else:
            raise ArgumentError(None, msg)
    return args

parse_known_args

parse_known_args(args=None, namespace=None)
Source code in python3.13/argparse.py
def parse_known_args(self, args=None, namespace=None):
    return self._parse_known_args2(args, namespace, intermixed=False)

convert_arg_line_to_args

convert_arg_line_to_args(arg_line)
Source code in python3.13/argparse.py
def convert_arg_line_to_args(self, arg_line):
    return [arg_line]

parse_intermixed_args

parse_intermixed_args(args=None, namespace=None)
Source code in python3.13/argparse.py
def parse_intermixed_args(self, args=None, namespace=None):
    args, argv = self.parse_known_intermixed_args(args, namespace)
    if argv:
        msg = _('unrecognized arguments: %s') % ' '.join(argv)
        if self.exit_on_error:
            self.error(msg)
        else:
            raise ArgumentError(None, msg)
    return args

parse_known_intermixed_args

parse_known_intermixed_args(args=None, namespace=None)
Source code in python3.13/argparse.py
def parse_known_intermixed_args(self, args=None, namespace=None):
    # returns a namespace and list of extras
    #
    # positional can be freely intermixed with optionals.  optionals are
    # first parsed with all positional arguments deactivated.  The 'extras'
    # are then parsed.  If the parser definition is incompatible with the
    # intermixed assumptions (e.g. use of REMAINDER, subparsers) a
    # TypeError is raised.

    positionals = self._get_positional_actions()
    a = [action for action in positionals
         if action.nargs in [PARSER, REMAINDER]]
    if a:
        raise TypeError('parse_intermixed_args: positional arg'
                        ' with nargs=%s'%a[0].nargs)

    return self._parse_known_args2(args, namespace, intermixed=True)

format_usage

format_usage()
Source code in python3.13/argparse.py
def format_usage(self):
    formatter = self._get_formatter()
    formatter.add_usage(self.usage, self._actions,
                        self._mutually_exclusive_groups)
    return formatter.format_help()

print_usage

print_usage(file=None)
Source code in python3.13/argparse.py
def print_usage(self, file=None):
    if file is None:
        file = _sys.stdout
    self._print_message(self.format_usage(), file)

print_help

print_help(file=None)
Source code in python3.13/argparse.py
def print_help(self, file=None):
    if file is None:
        file = _sys.stdout
    self._print_message(self.format_help(), file)

exit

exit(status=0, message=None)
Source code in python3.13/argparse.py
def exit(self, status=0, message=None):
    if message:
        self._print_message(message, _sys.stderr)
    _sys.exit(status)

Cmd2AttributeWrapper

Cmd2AttributeWrapper(attribute)

Wraps a cmd2-specific attribute added to an argparse Namespace.

This makes it easy to know which attributes in a Namespace are arguments from a parser and which were added by cmd2.

Initialize Cmd2AttributeWrapper instances.

Source code in cmd2/argparse_custom.py
def __init__(self, attribute: Any) -> None:
    """Initialize Cmd2AttributeWrapper instances."""
    self.__attribute = attribute

get

get()

Get the value of the attribute.

Source code in cmd2/argparse_custom.py
def get(self) -> Any:
    """Get the value of the attribute."""
    return self.__attribute

set

set(new_val)

Set the value of the attribute.

Source code in cmd2/argparse_custom.py
def set(self, new_val: Any) -> None:
    """Set the value of the attribute."""
    self.__attribute = new_val

generate_range_error

generate_range_error(range_min, range_max)

Generate an error message when the the number of arguments provided is not within the expected range.

Source code in cmd2/argparse_custom.py
def generate_range_error(range_min: int, range_max: float) -> str:
    """Generate an error message when the the number of arguments provided is not within the expected range."""
    err_str = "expected "

    if range_max == constants.INFINITY:
        plural = '' if range_min == 1 else 's'
        err_str += f"at least {range_min}"
    else:
        plural = '' if range_max == 1 else 's'
        if range_min == range_max:
            err_str += f"{range_min}"
        else:
            err_str += f"{range_min} to {range_max}"

    err_str += f" argument{plural}"

    return err_str

set_parser_prog

set_parser_prog(parser, prog)

Recursively set prog attribute of a parser and all of its subparsers.

Does so that the root command is a command name and not sys.argv[0].

PARAMETER DESCRIPTION
parser

the parser being edited

TYPE: ArgumentParser

prog

new value for the parser's prog attribute

TYPE: str

Source code in cmd2/argparse_custom.py
def set_parser_prog(parser: argparse.ArgumentParser, prog: str) -> None:
    """Recursively set prog attribute of a parser and all of its subparsers.

    Does so that the root command is a command name and not sys.argv[0].

    :param parser: the parser being edited
    :param prog: new value for the parser's prog attribute
    """
    # Set the prog value for this parser
    parser.prog = prog
    req_args: list[str] = []

    # Set the prog value for the parser's subcommands
    for action in parser._actions:
        if isinstance(action, argparse._SubParsersAction):
            # Set the _SubParsersAction's _prog_prefix value. That way if its add_parser() method is called later,
            # the correct prog value will be set on the parser being added.
            action._prog_prefix = parser.prog

            # The keys of action.choices are subcommand names as well as subcommand aliases. The aliases point to the
            # same parser as the actual subcommand. We want to avoid placing an alias into a parser's prog value.
            # Unfortunately there is nothing about an action.choices entry which tells us it's an alias. In most cases
            # we can filter out the aliases by checking the contents of action._choices_actions. This list only contains
            # help information and names for the subcommands and not aliases. However, subcommands without help text
            # won't show up in that list. Since dictionaries are ordered in Python 3.6 and above and argparse inserts the
            # subcommand name into choices dictionary before aliases, we should be OK assuming the first time we see a
            # parser, the dictionary key is a subcommand and not alias.
            processed_parsers = []

            # Set the prog value for each subcommand's parser
            for subcmd_name, subcmd_parser in action.choices.items():
                # Check if we've already edited this parser
                if subcmd_parser in processed_parsers:
                    continue

                subcmd_prog = parser.prog
                if req_args:
                    subcmd_prog += " " + " ".join(req_args)
                subcmd_prog += " " + subcmd_name
                set_parser_prog(subcmd_parser, subcmd_prog)
                processed_parsers.append(subcmd_parser)

            # We can break since argparse only allows 1 group of subcommands per level
            break

        # Need to save required args so they can be prepended to the subcommand usage
        if action.required:
            req_args.append(action.dest)

register_argparse_argument_parameter

register_argparse_argument_parameter(param_name, param_type)

Register a custom argparse argument parameter.

The registered name will then be a recognized keyword parameter to the parser's add_argument() function.

An accessor functions will be added to the parameter's Action object in the form of: get_{param_name}() and set_{param_name}(value).

PARAMETER DESCRIPTION
param_name

Name of the parameter to add.

TYPE: str

param_type

Type of the parameter to add.

TYPE: type[Any] | None

Source code in cmd2/argparse_custom.py
def register_argparse_argument_parameter(param_name: str, param_type: type[Any] | None) -> None:
    """Register a custom argparse argument parameter.

    The registered name will then be a recognized keyword parameter to the parser's `add_argument()` function.

    An accessor functions will be added to the parameter's Action object in the form of: ``get_{param_name}()``
    and ``set_{param_name}(value)``.

    :param param_name: Name of the parameter to add.
    :param param_type: Type of the parameter to add.
    """
    attr_name = f'{_CUSTOM_ATTRIB_PFX}{param_name}'
    if param_name in CUSTOM_ACTION_ATTRIBS or hasattr(argparse.Action, attr_name):
        raise KeyError(f'Custom parameter {param_name} already exists')
    if not re.search('^[A-Za-z_][A-Za-z0-9_]*$', param_name):
        raise KeyError(f'Invalid parameter name {param_name} - cannot be used as a python identifier')

    getter_name = f'get_{param_name}'

    def _action_get_custom_parameter(self: argparse.Action) -> Any:
        """Get the custom attribute of an argparse Action.

        This function is added by cmd2 as a method called ``get_<param_name>()`` to ``argparse.Action`` class.

        To call: ``action.get_<param_name>()``

        :param self: argparse Action being queried
        :return: The value of the custom attribute or None if attribute does not exist
        """
        return getattr(self, attr_name, None)

    setattr(argparse.Action, getter_name, _action_get_custom_parameter)

    setter_name = f'set_{param_name}'

    def _action_set_custom_parameter(self: argparse.Action, value: Any) -> None:
        """Set the custom attribute of an argparse Action.

        This function is added by cmd2 as a method called ``set_<param_name>()`` to ``argparse.Action`` class.

        To call: ``action.set_<param_name>(<param_value>)``

        :param self: argparse Action being updated
        :param value: value being assigned
        """
        if param_type and not isinstance(value, param_type):
            raise TypeError(f'{param_name} must be of type {param_type}, got: {value} ({type(value)})')
        setattr(self, attr_name, value)

    setattr(argparse.Action, setter_name, _action_set_custom_parameter)

    CUSTOM_ACTION_ATTRIBS.add(param_name)

set_default_argument_parser_type

set_default_argument_parser_type(parser_type)

Set the default ArgumentParser 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.

Source code in cmd2/argparse_custom.py
def set_default_argument_parser_type(parser_type: type[Cmd2ArgumentParser]) -> None:
    """Set the default ArgumentParser 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.
    """
    global DEFAULT_ARGUMENT_PARSER  # noqa: PLW0603
    DEFAULT_ARGUMENT_PARSER = parser_type