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=type['cmd2.Cmd'] | type[CommandSet])

### `` RawCommandFuncOptionalBoolReturn `module-attribute`

    RawCommandFuncOptionalBoolReturn = Callable[[CommandParent, Statement | str], bool | None]

### `` ArgListCommandFuncOptionalBoolReturn `module-attribute`

    ArgListCommandFuncOptionalBoolReturn = Callable[[CommandParent, list[str]], bool | None]

### `` ArgListCommandFuncBoolReturn `module-attribute`

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

### `` ArgListCommandFuncNoneReturn `module-attribute`

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

### `` ArgListCommandFunc `module-attribute`

    ArgListCommandFunc = ArgListCommandFuncOptionalBoolReturn[CommandParent] | ArgListCommandFuncBoolReturn[CommandParent] | ArgListCommandFuncNoneReturn[CommandParent]

### `` ArgparseCommandFuncOptionalBoolReturn `module-attribute`

    ArgparseCommandFuncOptionalBoolReturn = Callable[[CommandParent, Namespace], bool | None]

### `` ArgparseCommandFuncWithUnknownArgsOptionalBoolReturn `module-attribute`

    ArgparseCommandFuncWithUnknownArgsOptionalBoolReturn = Callable[[CommandParent, Namespace, list[str]], bool | None]

### `` 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]

### `` ArgparseCommandFunc `module-attribute`

    ArgparseCommandFunc = ArgparseCommandFuncOptionalBoolReturn[CommandParent] | ArgparseCommandFuncWithUnknownArgsOptionalBoolReturn[CommandParent] | ArgparseCommandFuncBoolReturn[CommandParent] | ArgparseCommandFuncWithUnknownArgsBoolReturn[CommandParent] | ArgparseCommandFuncNoneReturn[CommandParent] | ArgparseCommandFuncWithUnknownArgsNoneReturn[CommandParent]

### `` with_category

    with_category(category)

Decorate a `do_*` command method to apply a category.

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`

    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60

    def with_category(category: str) -> Callable[[CommandFunc], CommandFunc]:
        """Decorate a ``do_*`` command method to apply a category.

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

Decorate a `do_*` method to alter the arguments passed to it so it is passed a list[str].

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: `ArgListCommandFunc[CommandParent] | None` DEFAULT: `None`
`preserve_quotes` | if `True`, then argument quotes will not be stripped TYPE: `bool` DEFAULT: `False`

RETURNS | DESCRIPTION
--- | ---
`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`

    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191

    def with_argument_list(
        func_arg: ArgListCommandFunc[CommandParent] | None = None,
        *,
        preserve_quotes: bool = False,
    ) -> (
        RawCommandFuncOptionalBoolReturn[CommandParent]
        | Callable[[ArgListCommandFunc[CommandParent]], RawCommandFuncOptionalBoolReturn[CommandParent]]
    ):
        """Decorate a ``do_*`` method to alter the arguments passed to it so it is passed a list[str].

        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]:
            """Decorate 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) -> bool | None:
                """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)

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

### `` with_argparser

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

Decorate a `do_*` method to populate its `args` argument with the given instance of argparse.ArgumentParser.

PARAMETER | DESCRIPTION
--- | ---
`parser` | instance of ArgumentParser or a callable that returns an ArgumentParser for this command TYPE: `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: `Callable[..., Namespace] | None` 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`

    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    255
    256
    257
    258
    259
    260
    261
    262
    263
    264
    265
    266
    267
    268
    269
    270
    271
    272
    273
    274
    275
    276
    277
    278
    279
    280
    281
    282
    283
    284
    285
    286
    287
    288
    289
    290
    291
    292
    293
    294
    295
    296
    297
    298
    299
    300
    301
    302
    303
    304
    305
    306
    307
    308
    309
    310
    311
    312
    313
    314
    315
    316
    317
    318
    319
    320
    321
    322
    323
    324
    325
    326
    327
    328
    329
    330
    331
    332
    333
    334
    335
    336
    337
    338
    339
    340
    341
    342
    343
    344
    345
    346
    347
    348
    349

    def with_argparser(
        parser: argparse.ArgumentParser  # existing parser
        | Callable[[], argparse.ArgumentParser]  # function or staticmethod
        | Callable[[CommandParentType], argparse.ArgumentParser],  # Cmd or CommandSet classmethod
        *,
        ns_provider: Callable[..., argparse.Namespace] | None = None,
        preserve_quotes: bool = False,
        with_unknown_args: bool = False,
    ) -> Callable[[ArgparseCommandFunc[CommandParent]], RawCommandFuncOptionalBoolReturn[CommandParent]]:
        """Decorate a ``do_*`` method to populate its ``args`` argument with the given instance of argparse.ArgumentParser.

        :param parser: instance of ArgumentParser or a callable that returns an ArgumentParser for this command
        :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]:
            """Decorate 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]) -> bool | None:
                """Command function wrapper which translates command line into argparse Namespace and call 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: 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 as exc:
                    raise Cmd2ArgparseError from exc
                else:
                    # Add wrapped statement to Namespace as cmd2_statement
                    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)
                    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)

            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` | instance of ArgumentParser or a callable that returns an ArgumentParser for this subcommand TYPE: `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: `str | None` DEFAULT: `None`
`aliases` | Alternative names for this subcommand. This is passed as the alias argument to subparsers.add_parser(). TYPE: `list[str] | None` DEFAULT: `None`

RETURNS | DESCRIPTION
--- | ---
`Callable[[ArgparseCommandFunc[CommandParent]], ArgparseCommandFunc[CommandParent]]` | Wrapper function that can receive an argparse.Namespace

Source code in `cmd2/decorators.py`

    352
    353
    354
    355
    356
    357
    358
    359
    360
    361
    362
    363
    364
    365
    366
    367
    368
    369
    370
    371
    372
    373
    374
    375
    376
    377
    378
    379
    380
    381
    382
    383
    384
    385
    386
    387
    388
    389
    390
    391

    def as_subcommand_to(
        command: str,
        subcommand: str,
        parser: argparse.ArgumentParser  # existing parser
        | Callable[[], argparse.ArgumentParser]  # function or staticmethod
        | Callable[[CommandParentType], argparse.ArgumentParser],  # Cmd or CommandSet classmethod
        *,
        help: str | None = None,  # noqa: A002
        aliases: list[str] | None = 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: instance of ArgumentParser or a callable that returns an ArgumentParser 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] = {}
            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