Skip to content

cmd2.decorators

cmd2.decorators

Decorators for cmd2 commands

CommandParent module-attribute

CommandParent = TypeVar('CommandParent', bound=Union['cmd2.Cmd', CommandSet])

CommandParentType module-attribute

CommandParentType = TypeVar('CommandParentType', bound=Union[Type['cmd2.Cmd'], Type[CommandSet]])

RawCommandFuncOptionalBoolReturn module-attribute

RawCommandFuncOptionalBoolReturn = Callable[[CommandParent, Union[Statement, str]], Optional[bool]]

ArgListCommandFuncOptionalBoolReturn module-attribute

ArgListCommandFuncOptionalBoolReturn = Callable[[CommandParent, List[str]], Optional[bool]]

ArgListCommandFuncBoolReturn module-attribute

ArgListCommandFuncBoolReturn = Callable[[CommandParent, List[str]], bool]

ArgListCommandFuncNoneReturn module-attribute

ArgListCommandFuncNoneReturn = Callable[[CommandParent, List[str]], None]

ArgparseCommandFuncOptionalBoolReturn module-attribute

ArgparseCommandFuncOptionalBoolReturn = Callable[[CommandParent, Namespace], Optional[bool]]

ArgparseCommandFuncWithUnknownArgsOptionalBoolReturn module-attribute

ArgparseCommandFuncWithUnknownArgsOptionalBoolReturn = Callable[[CommandParent, Namespace, List[str]], Optional[bool]]

ArgparseCommandFuncBoolReturn module-attribute

ArgparseCommandFuncBoolReturn = Callable[[CommandParent, Namespace], bool]

ArgparseCommandFuncWithUnknownArgsBoolReturn module-attribute

ArgparseCommandFuncWithUnknownArgsBoolReturn = Callable[[CommandParent, Namespace, List[str]], bool]

ArgparseCommandFuncNoneReturn module-attribute

ArgparseCommandFuncNoneReturn = Callable[[CommandParent, Namespace], None]

ArgparseCommandFuncWithUnknownArgsNoneReturn module-attribute

ArgparseCommandFuncWithUnknownArgsNoneReturn = Callable[[CommandParent, Namespace, List[str]], None]

with_category

with_category(category)

A decorator to apply a category to a do_* command method.

PARAMETER DESCRIPTION
category

the name of the category in which this command should be grouped when displaying the list of commands. Example: py class MyApp(cmd2.Cmd): @cmd2.with_category('Text Functions') def do_echo(self, args) self.poutput(args) For an alternative approach to categorizing commands using a function, see cmd2.utils.categorize

TYPE: str

Source code in cmd2/decorators.py
def with_category(category: str) -> Callable[[CommandFunc], CommandFunc]:
    """A decorator to apply a category to a ``do_*`` command method.

    :param category: the name of the category in which this command should
                     be grouped when displaying the list of commands.

    Example:

    ```py
    class MyApp(cmd2.Cmd):
        @cmd2.with_category('Text Functions')
        def do_echo(self, args)
            self.poutput(args)
    ```

    For an alternative approach to categorizing commands using a function, see
    [cmd2.utils.categorize][]
    """

    def cat_decorator(func: CommandFunc) -> CommandFunc:
        from .utils import (
            categorize,
        )

        categorize(func, category)
        return func

    return cat_decorator

with_argument_list

with_argument_list(func_arg=None, *, preserve_quotes=False)

A decorator to alter the arguments passed to a do_* method. Default passes a string of whatever the user typed. With this decorator, the decorated method will receive a list of arguments parsed from user input.

PARAMETER DESCRIPTION
func_arg

Single-element positional argument list containing doi_* method this decorator is wrapping

TYPE: Optional[ArgListCommandFunc[CommandParent]] DEFAULT: None

preserve_quotes

if True, then argument quotes will not be stripped

TYPE: bool DEFAULT: False

RETURNS DESCRIPTION
Union[RawCommandFuncOptionalBoolReturn[CommandParent], Callable[[ArgListCommandFunc[CommandParent]], RawCommandFuncOptionalBoolReturn[CommandParent]]]

function that gets passed a list of argument strings Example: py class MyApp(cmd2.Cmd): @cmd2.with_argument_list def do_echo(self, arglist): self.poutput(' '.join(arglist)

Source code in cmd2/decorators.py
def with_argument_list(
    func_arg: Optional[ArgListCommandFunc[CommandParent]] = None,
    *,
    preserve_quotes: bool = False,
) -> Union[
    RawCommandFuncOptionalBoolReturn[CommandParent],
    Callable[[ArgListCommandFunc[CommandParent]], RawCommandFuncOptionalBoolReturn[CommandParent]],
]:
    """
    A decorator to alter the arguments passed to a ``do_*`` method. Default
    passes a string of whatever the user typed. With this decorator, the
    decorated method will receive a list of arguments parsed from user input.

    :param func_arg: Single-element positional argument list containing ``doi_*`` method
                 this decorator is wrapping
    :param preserve_quotes: if ``True``, then argument quotes will not be stripped
    :return: function that gets passed a list of argument strings

    Example:
    ```py
    class MyApp(cmd2.Cmd):
        @cmd2.with_argument_list
        def do_echo(self, arglist):
            self.poutput(' '.join(arglist)
    ```
    """
    import functools

    def arg_decorator(func: ArgListCommandFunc[CommandParent]) -> RawCommandFuncOptionalBoolReturn[CommandParent]:
        """
        Decorator function that ingests an Argument List function and returns a raw command function.
        The returned function will process the raw input into an argument list to be passed to the wrapped function.

        :param func: The defined argument list command function
        :return: Function that takes raw input and converts to an argument list to pass to the wrapped function.
        """

        @functools.wraps(func)
        def cmd_wrapper(*args: Any, **kwargs: Any) -> Optional[bool]:
            """
            Command function wrapper which translates command line into an argument list and calls actual command function

            :param args: All positional arguments to this function.  We're expecting there to be:
                            cmd2_app, statement: Union[Statement, str]
                            contiguously somewhere in the list
            :param kwargs: any keyword arguments being passed to command function
            :return: return value of command function
            """
            cmd2_app, statement = _parse_positionals(args)
            _, parsed_arglist = cmd2_app.statement_parser.get_command_arg_list(command_name, statement, preserve_quotes)
            args_list = _arg_swap(args, statement, parsed_arglist)
            return func(*args_list, **kwargs)  # type: ignore[call-arg]

        command_name = func.__name__[len(constants.COMMAND_FUNC_PREFIX) :]
        cmd_wrapper.__doc__ = func.__doc__
        return cmd_wrapper

    if callable(func_arg):
        return arg_decorator(func_arg)
    else:
        return arg_decorator

with_argparser

with_argparser(parser, *, ns_provider=None, preserve_quotes=False, with_unknown_args=False)

A decorator to alter a cmd2 method to populate its args argument by parsing arguments with the given instance of argparse.ArgumentParser.

PARAMETER DESCRIPTION
parser

unique instance of ArgumentParser or a callable that returns an ArgumentParser

TYPE: Union[ArgumentParser, Callable[[], ArgumentParser], Callable[[CommandParentType], ArgumentParser]]

ns_provider

An optional function that accepts a cmd2.Cmd or cmd2.CommandSet object as an argument and returns an argparse.Namespace. This is useful if the Namespace needs to be prepopulated with state data that affects parsing.

TYPE: Optional[Callable[..., Namespace]] DEFAULT: None

preserve_quotes

if True, then arguments passed to argparse maintain their quotes

TYPE: bool DEFAULT: False

with_unknown_args

if true, then capture unknown args

TYPE: bool DEFAULT: False

RETURNS DESCRIPTION
Callable[[ArgparseCommandFunc[CommandParent]], RawCommandFuncOptionalBoolReturn[CommandParent]]

function that gets passed argparse-parsed args in a Namespace A cmd2.argparse_custom.Cmd2AttributeWrapper called cmd2_statement is included in the Namespace to provide access to the cmd2.Statement object that was created when parsing the command line. This can be useful if the command function needs to know the command line. Example: py parser = cmd2.Cmd2ArgumentParser() parser.add_argument('-p', '--piglatin', action='store_true', help='atinLay') parser.add_argument('-s', '--shout', action='store_true', help='N00B EMULATION MODE') parser.add_argument('-r', '--repeat', type=int, help='output [n] times') parser.add_argument('words', nargs='+', help='words to print') class MyApp(cmd2.Cmd): @cmd2.with_argparser(parser, preserve_quotes=True) def do_argprint(self, args): "Print the options and argument list this options command was called with." self.poutput(f'args: {args!r}') Example with unknown args: py parser = cmd2.Cmd2ArgumentParser() parser.add_argument('-p', '--piglatin', action='store_true', help='atinLay') parser.add_argument('-s', '--shout', action='store_true', help='N00B EMULATION MODE') parser.add_argument('-r', '--repeat', type=int, help='output [n] times') class MyApp(cmd2.Cmd): @cmd2.with_argparser(parser, with_unknown_args=True) def do_argprint(self, args, unknown): "Print the options and argument list this options command was called with." self.poutput(f'args: {args!r}') self.poutput(f'unknowns: {unknown}')

Source code in cmd2/decorators.py
def with_argparser(
    parser: Union[
        argparse.ArgumentParser,  # existing parser
        Callable[[], argparse.ArgumentParser],  # function or staticmethod
        Callable[[CommandParentType], argparse.ArgumentParser],  # Cmd or CommandSet classmethod
    ],
    *,
    ns_provider: Optional[Callable[..., argparse.Namespace]] = None,
    preserve_quotes: bool = False,
    with_unknown_args: bool = False,
) -> Callable[[ArgparseCommandFunc[CommandParent]], RawCommandFuncOptionalBoolReturn[CommandParent]]:
    """A decorator to alter a cmd2 method to populate its ``args`` argument by parsing arguments
    with the given instance of argparse.ArgumentParser.

    :param parser: unique instance of ArgumentParser or a callable that returns an ArgumentParser
    :param ns_provider: An optional function that accepts a cmd2.Cmd or cmd2.CommandSet object as an argument and returns an
                        argparse.Namespace. This is useful if the Namespace needs to be prepopulated with state data that
                        affects parsing.
    :param preserve_quotes: if ``True``, then arguments passed to argparse maintain their quotes
    :param with_unknown_args: if true, then capture unknown args
    :return: function that gets passed argparse-parsed args in a ``Namespace``
             A [cmd2.argparse_custom.Cmd2AttributeWrapper][] called ``cmd2_statement`` is included
             in the ``Namespace`` to provide access to the [cmd2.Statement][] object that was created when
             parsing the command line. This can be useful if the command function needs to know the command line.

    Example:

    ```py
    parser = cmd2.Cmd2ArgumentParser()
    parser.add_argument('-p', '--piglatin', action='store_true', help='atinLay')
    parser.add_argument('-s', '--shout', action='store_true', help='N00B EMULATION MODE')
    parser.add_argument('-r', '--repeat', type=int, help='output [n] times')
    parser.add_argument('words', nargs='+', help='words to print')

    class MyApp(cmd2.Cmd):
        @cmd2.with_argparser(parser, preserve_quotes=True)
        def do_argprint(self, args):
            "Print the options and argument list this options command was called with."
            self.poutput(f'args: {args!r}')
    ```

    Example with unknown args:

    ```py
    parser = cmd2.Cmd2ArgumentParser()
    parser.add_argument('-p', '--piglatin', action='store_true', help='atinLay')
    parser.add_argument('-s', '--shout', action='store_true', help='N00B EMULATION MODE')
    parser.add_argument('-r', '--repeat', type=int, help='output [n] times')

    class MyApp(cmd2.Cmd):
        @cmd2.with_argparser(parser, with_unknown_args=True)
        def do_argprint(self, args, unknown):
            "Print the options and argument list this options command was called with."
            self.poutput(f'args: {args!r}')
            self.poutput(f'unknowns: {unknown}')
    ```
    """
    import functools

    def arg_decorator(func: ArgparseCommandFunc[CommandParent]) -> RawCommandFuncOptionalBoolReturn[CommandParent]:
        """
        Decorator function that ingests an Argparse Command Function and returns a raw command function.
        The returned function will process the raw input into an argparse Namespace to be passed to the wrapped function.

        :param func: The defined argparse command function
        :return: Function that takes raw input and converts to an argparse Namespace to passed to the wrapped function.
        """

        @functools.wraps(func)
        def cmd_wrapper(*args: Any, **kwargs: Dict[str, Any]) -> Optional[bool]:
            """
            Command function wrapper which translates command line into argparse Namespace and calls actual
            command function

            :param args: All positional arguments to this function.  We're expecting there to be:
                            cmd2_app, statement: Union[Statement, str]
                            contiguously somewhere in the list
            :param kwargs: any keyword arguments being passed to command function
            :return: return value of command function
            :raises Cmd2ArgparseError: if argparse has error parsing command line
            """
            cmd2_app, statement_arg = _parse_positionals(args)
            statement, parsed_arglist = cmd2_app.statement_parser.get_command_arg_list(
                command_name, statement_arg, preserve_quotes
            )

            # Pass cmd_wrapper instead of func, since it contains the parser info.
            arg_parser = cmd2_app._command_parsers.get(cmd_wrapper)
            if arg_parser is None:
                # This shouldn't be possible to reach
                raise ValueError(f'No argument parser found for {command_name}')  # pragma: no cover

            if ns_provider is None:
                namespace = None
            else:
                # The namespace provider may or may not be defined in the same class as the command. Since provider
                # functions are registered with the command argparser before anything is instantiated, we
                # need to find an instance at runtime that matches the types during declaration
                provider_self = cmd2_app._resolve_func_self(ns_provider, args[0])
                namespace = ns_provider(provider_self if provider_self is not None else cmd2_app)

            try:
                new_args: Union[Tuple[argparse.Namespace], Tuple[argparse.Namespace, List[str]]]
                if with_unknown_args:
                    new_args = arg_parser.parse_known_args(parsed_arglist, namespace)
                else:
                    new_args = (arg_parser.parse_args(parsed_arglist, namespace),)
                ns = new_args[0]
            except SystemExit:
                raise Cmd2ArgparseError
            else:
                # Add wrapped statement to Namespace as cmd2_statement
                setattr(ns, 'cmd2_statement', Cmd2AttributeWrapper(statement))

                # Add wrapped subcmd handler (which can be None) to Namespace as cmd2_handler
                handler = getattr(ns, constants.NS_ATTR_SUBCMD_HANDLER, None)
                setattr(ns, 'cmd2_handler', Cmd2AttributeWrapper(handler))

                # Remove the subcmd handler attribute from the Namespace
                # since cmd2_handler is how a developer accesses it.
                if hasattr(ns, constants.NS_ATTR_SUBCMD_HANDLER):
                    delattr(ns, constants.NS_ATTR_SUBCMD_HANDLER)

                args_list = _arg_swap(args, statement_arg, *new_args)
                return func(*args_list, **kwargs)  # type: ignore[call-arg]

        command_name = func.__name__[len(constants.COMMAND_FUNC_PREFIX) :]

        # Set some custom attributes for this command
        setattr(cmd_wrapper, constants.CMD_ATTR_ARGPARSER, parser)
        setattr(cmd_wrapper, constants.CMD_ATTR_PRESERVE_QUOTES, preserve_quotes)

        return cmd_wrapper

    return arg_decorator

as_subcommand_to

as_subcommand_to(command, subcommand, parser, *, help=None, aliases=None)

Tag this method as a subcommand to an existing argparse decorated command.

PARAMETER DESCRIPTION
command

Command Name. Space-delimited subcommands may optionally be specified

TYPE: str

subcommand

Subcommand name

TYPE: str

parser

argparse Parser for this subcommand

TYPE: Union[ArgumentParser, Callable[[], ArgumentParser], Callable[[CommandParentType], ArgumentParser]]

help

Help message for this subcommand which displays in the list of subcommands of the command we are adding to. This is passed as the help argument to subparsers.add_parser().

TYPE: Optional[str] DEFAULT: None

aliases

Alternative names for this subcommand. This is passed as the alias argument to subparsers.add_parser().

TYPE: Optional[List[str]] DEFAULT: None

RETURNS DESCRIPTION
Callable[[ArgparseCommandFunc[CommandParent]], ArgparseCommandFunc[CommandParent]]

Wrapper function that can receive an argparse.Namespace

Source code in cmd2/decorators.py
def as_subcommand_to(
    command: str,
    subcommand: str,
    parser: Union[
        argparse.ArgumentParser,  # existing parser
        Callable[[], argparse.ArgumentParser],  # function or staticmethod
        Callable[[CommandParentType], argparse.ArgumentParser],  # Cmd or CommandSet classmethod
    ],
    *,
    help: Optional[str] = None,
    aliases: Optional[List[str]] = None,
) -> Callable[[ArgparseCommandFunc[CommandParent]], ArgparseCommandFunc[CommandParent]]:
    """
    Tag this method as a subcommand to an existing argparse decorated command.

    :param command: Command Name. Space-delimited subcommands may optionally be specified
    :param subcommand: Subcommand name
    :param parser: argparse Parser for this subcommand
    :param help: Help message for this subcommand which displays in the list of subcommands of the command we are adding to.
                 This is passed as the help argument to subparsers.add_parser().
    :param aliases: Alternative names for this subcommand. This is passed as the alias argument to
                    subparsers.add_parser().
    :return: Wrapper function that can receive an argparse.Namespace
    """

    def arg_decorator(func: ArgparseCommandFunc[CommandParent]) -> ArgparseCommandFunc[CommandParent]:
        # Set some custom attributes for this command
        setattr(func, constants.SUBCMD_ATTR_COMMAND, command)
        setattr(func, constants.CMD_ATTR_ARGPARSER, parser)
        setattr(func, constants.SUBCMD_ATTR_NAME, subcommand)

        # Keyword arguments for subparsers.add_parser()
        add_parser_kwargs: Dict[str, Any] = dict()
        if help is not None:
            add_parser_kwargs['help'] = help
        if aliases:
            add_parser_kwargs['aliases'] = aliases[:]

        setattr(func, constants.SUBCMD_ATTR_ADD_PARSER_KWARGS, add_parser_kwargs)

        return func

    return arg_decorator