Skip to content

cmd2.argparse_custom

cmd2.argparse_custom

This 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 override_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 descriptions instead of just a table of tokens::

Instead of this:
    1     2     3

The user sees this:
    ITEM_ID     Item Name
    ============================
    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_header parameter of add_argument(). The right column values come from the CompletionItem.description value.

Example::

token = 1
token_description = "My Item"
completion_item = CompletionItem(token, token_description)

Since descriptive_header and CompletionItem.description are just strings, you can format them in such a way to have multiple columns::

ITEM_ID     Item Name            Checked Out    Due Date
==========================================================
1           My item              True           02/02/2022
2           Another item         False
3           Yet another item     False

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.

To avoid printing a ton of 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 description value 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_header() - See _action_get_descriptive_header for more details.
  • argparse.Action.set_descriptive_header() - See _action_set_descriptive_header 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_HEADER module-attribute

ATTR_DESCRIPTIVE_HEADER = 'descriptive_header'

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, description='', *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

description

description text to display

TYPE: str DEFAULT: ''

args

args for str init

TYPE: Any DEFAULT: ()

Source code in cmd2/argparse_custom.py
def __init__(self, value: object, description: str = '', *args: Any) -> None:
    """
    CompletionItem Initializer

    :param value: the value being tab completed
    :param description: description text to display
    :param args: args for str __init__
    """
    super().__init__(*args)
    self.description = description

    # 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

description instance-attribute

description = description

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 and accepts a dictionary of prior arguments.

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.

Initializer

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: Union[CompleterFunc, ChoicesProviderFunc]

Source code in cmd2/argparse_custom.py
def __init__(
    self,
    is_completer: bool,
    to_call: Union[CompleterFunc, ChoicesProviderFunc],
) -> None:
    """
    Initializer
    :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'
            )
    else:
        if 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

choices_provider property

choices_provider

Cmd2HelpFormatter

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

Bases: RawTextHelpFormatter

Custom help formatter to configure ordering of help text

Source code in python3.13/argparse.py
def __init__(self,
             prog,
             indent_increment=2,
             max_help_position=24,
             width=None):

    # default setting for width
    if width is None:
        try:
            import shutil as _shutil
            width = _shutil.get_terminal_size().columns
            width -= 2
        except ImportError:
            width = 70

    self._prog = prog
    self._indent_increment = indent_increment
    self._max_help_position = min(max_help_position,
                                  max(width - 20, indent_increment * 2))
    self._width = width

    self._current_indent = 0
    self._level = 0
    self._action_max_length = 0

    self._root_section = self._Section(self, None)
    self._current_section = self._root_section

    self._whitespace_matcher = _re.compile(r'\s+', _re.ASCII)
    self._long_break_matcher = _re.compile(r'\n\n\n+')

start_section

start_section(heading)
Source code in python3.13/argparse.py
def start_section(self, heading):
    self._indent()
    section = self._Section(self, self._current_section, heading)
    self._add_item(section.format_help, [])
    self._current_section = section

end_section

end_section()
Source code in python3.13/argparse.py
def end_section(self):
    self._current_section = self._current_section.parent
    self._dedent()

add_text

add_text(text)
Source code in python3.13/argparse.py
def add_text(self, text):
    if text is not SUPPRESS and text is not None:
        self._add_item(self._format_text, [text])

add_usage

add_usage(usage, actions, groups, prefix=None)
Source code in python3.13/argparse.py
def add_usage(self, usage, actions, groups, prefix=None):
    if usage is not SUPPRESS:
        args = usage, actions, groups, prefix
        self._add_item(self._format_usage, args)

add_argument

add_argument(action)
Source code in python3.13/argparse.py
def add_argument(self, action):
    if action.help is not SUPPRESS:

        # find all invocations
        get_invocation = self._format_action_invocation
        invocation_lengths = [len(get_invocation(action)) + self._current_indent]
        for subaction in self._iter_indented_subactions(action):
            invocation_lengths.append(len(get_invocation(subaction)) + self._current_indent)

        # update the maximum item length
        action_length = max(invocation_lengths)
        self._action_max_length = max(self._action_max_length,
                                      action_length)

        # add the item to the list
        self._add_item(self._format_action, [action])

add_arguments

add_arguments(actions)
Source code in python3.13/argparse.py
def add_arguments(self, actions):
    for action in actions:
        self.add_argument(action)

format_help

format_help()
Source code in python3.13/argparse.py
def format_help(self):
    help = self._root_section.format_help()
    if help:
        help = self._long_break_matcher.sub('\n\n', help)
        help = help.strip('\n') + '\n'
    return help

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

Bases: ArgumentParser

Custom ArgumentParser class that improves error and help output

Custom parameter 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: Optional[Type[ArgparseCompleter]] DEFAULT: None

Source code in cmd2/argparse_custom.py
def __init__(
    self,
    prog: Optional[str] = None,
    usage: Optional[str] = None,
    description: Optional[str] = None,
    epilog: Optional[str] = None,
    parents: Sequence[argparse.ArgumentParser] = (),
    formatter_class: Type[argparse.HelpFormatter] = Cmd2HelpFormatter,
    prefix_chars: str = '-',
    fromfile_prefix_chars: Optional[str] = None,
    argument_default: Optional[str] = None,
    conflict_handler: str = 'error',
    add_help: bool = True,
    allow_abbrev: bool = True,
    *,
    ap_completer_type: Optional[Type['ArgparseCompleter']] = None,
) -> None:
    """
    # Custom parameter 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
    """
    super(Cmd2ArgumentParser, self).__init__(
        prog=prog,
        usage=usage,
        description=description,
        epilog=epilog,
        parents=parents if parents else [],
        formatter_class=formatter_class,  # type: ignore[arg-type]
        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,
    )

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

description instance-attribute

description = description

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

epilog instance-attribute

epilog = epilog

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

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)

add_subparsers

add_subparsers(**kwargs)

Custom override. Sets 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
    """
    Custom override. Sets 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)

Custom override that applies custom formatting to the error message

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

    self.print_usage(sys.stderr)
    formatted_message = ansi.style_error(formatted_message)
    self.exit(2, f'{formatted_message}\n\n')

format_help

format_help()

Copy of format_help() from argparse.ArgumentParser with tweaks to separately display required parameters

Source code in cmd2/argparse_custom.py
def format_help(self) -> str:
    """Copy of format_help() from argparse.ArgumentParser with tweaks to separately display required parameters"""
    formatter = self._get_formatter()

    # usage
    formatter.add_usage(self.usage, self._actions, self._mutually_exclusive_groups)  # type: ignore[arg-type]

    # description
    formatter.add_text(self.description)

    # Begin cmd2 customization (separate required and optional arguments)

    # positionals, optionals and user-defined groups
    for action_group in self._action_groups:
        if sys.version_info >= (3, 10):
            default_options_group = action_group.title == 'options'
        else:
            default_options_group = action_group.title == 'optional arguments'

        if default_options_group:
            # check if the arguments are required, group accordingly
            req_args = []
            opt_args = []
            for action in action_group._group_actions:
                if action.required:
                    req_args.append(action)
                else:
                    opt_args.append(action)

            # separately display required arguments
            formatter.start_section('required arguments')
            formatter.add_text(action_group.description)
            formatter.add_arguments(req_args)
            formatter.end_section()

            # now display truly optional arguments
            formatter.start_section('optional arguments')
            formatter.add_text(action_group.description)
            formatter.add_arguments(opt_args)
            formatter.end_section()
        else:
            formatter.start_section(action_group.title)
            formatter.add_text(action_group.description)
            formatter.add_arguments(action_group._group_actions)
            formatter.end_section()

    # End cmd2 customization

    # epilog
    formatter.add_text(self.epilog)

    # determine help from format above
    return formatter.format_help() + '\n'

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.

Source code in cmd2/argparse_custom.py
def __init__(self, attribute: Any) -> None:
    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: Union[int, 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

register_argparse_argument_parameter

register_argparse_argument_parameter(param_name, param_type)

Registers 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: Optional[Type[Any]]

Source code in cmd2/argparse_custom.py
def register_argparse_argument_parameter(param_name: str, param_type: Optional[Type[Any]]) -> None:
    """
    Registers 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:
        f"""
        Get the custom {param_name} attribute of an argparse Action.

        This function is added by cmd2 as a method called ``{getter_name}()`` to ``argparse.Action`` class.

        To call: ``action.{getter_name}()``

        :param self: argparse Action being queried
        :return: The value of {param_name} 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:
        f"""
        Set the custom {param_name} attribute of an argparse Action.

        This function is added by cmd2 as a method called ``{setter_name}()`` to ``argparse.Action`` class.

        To call: ``action.{setter_name}({param_name})``

        :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 a cmd2 app. This must be called prior to loading cmd2.py if you want to override the parser for cmd2's built-in commands. See examples/override_parser.py.

Source code in cmd2/argparse_custom.py
def set_default_argument_parser_type(parser_type: Type[argparse.ArgumentParser]) -> None:
    """
    Set the default ArgumentParser class for a cmd2 app. This must be called prior to loading cmd2.py if
    you want to override the parser for cmd2's built-in commands. See examples/override_parser.py.
    """
    global DEFAULT_ARGUMENT_PARSER
    DEFAULT_ARGUMENT_PARSER = parser_type