Skip to content

Commit f4e9f31

Browse files
committed
Simplified type aliases in decorators.py.
1 parent fc668f0 commit f4e9f31

3 files changed

Lines changed: 29 additions & 58 deletions

File tree

CHANGELOG.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -109,9 +109,9 @@ prompt is displayed.
109109
- For more details and examples, see the [Help](docs/features/help.md) documentation and the
110110
`examples/default_categories.py` file.
111111
- `CommandSet` is now a generic class, which allows developers to parameterize it with their
112-
specific`cmd2.Cmd`subclass (e.g.,`class MyCommandSet(CommandSet[MyApp]):`). This provides full
113-
type hints and IDE autocompletion for `self._cmd` without needing to override and cast the
114-
property.
112+
specific `cmd2.Cmd`subclass (e.g.,`class MyCommandSet(CommandSet[MyApp]):`). This provides
113+
full type hints and IDE autocompletion for `self._cmd` without needing to override and cast
114+
the property.
115115

116116
## 3.5.0 (April 13, 2026)
117117

cmd2/decorators.py

Lines changed: 20 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
from typing import (
99
TYPE_CHECKING,
1010
Any,
11+
ParamSpec,
1112
TypeAlias,
1213
)
1314

@@ -19,14 +20,18 @@
1920
from .types import (
2021
CmdOrSetClassT,
2122
CmdOrSetT,
22-
UnboundCommandFuncT,
23+
UnboundCommandFunc,
2324
)
2425

2526
if TYPE_CHECKING: # pragma: no cover
2627
from .cmd2 import Cmd
2728

29+
P = ParamSpec("P")
2830

29-
def with_category(category: str) -> Callable[[UnboundCommandFuncT], UnboundCommandFuncT]:
31+
32+
def with_category(
33+
category: str,
34+
) -> Callable[[UnboundCommandFunc[CmdOrSetT, P]], UnboundCommandFunc[CmdOrSetT, P]]:
3035
"""Decorate a ``do_*`` command method to apply a category.
3136
3237
:param category: the name of the category in which this command should
@@ -45,7 +50,7 @@ def do_echo(self, args)
4550
4651
"""
4752

48-
def cat_decorator(func: UnboundCommandFuncT) -> UnboundCommandFuncT:
53+
def cat_decorator(func: UnboundCommandFunc[CmdOrSetT, P]) -> UnboundCommandFunc[CmdOrSetT, P]:
4954
from .utils import categorize
5055

5156
categorize(func, category)
@@ -54,7 +59,8 @@ def cat_decorator(func: UnboundCommandFuncT) -> UnboundCommandFuncT:
5459
return cat_decorator
5560

5661

57-
RawCommandFuncOptionalBoolReturn: TypeAlias = Callable[[CmdOrSetT, Statement | str], bool | None]
62+
# The standard cmd2 command function signature (e.g. do_command(self, statement))
63+
RawCommandFunc: TypeAlias = UnboundCommandFunc[CmdOrSetT, [Statement | str]]
5864

5965

6066
##########################
@@ -102,37 +108,20 @@ def _arg_swap(args: Sequence[Any], search_arg: Any, *replace_arg: Any) -> list[A
102108

103109

104110
# Function signature for a command function that accepts a pre-processed argument list from user input
105-
# and optionally returns a boolean
106-
ArgListCommandFuncOptionalBoolReturn: TypeAlias = Callable[[CmdOrSetT, list[str]], bool | None]
107-
# Function signature for a command function that accepts a pre-processed argument list from user input
108-
# and returns a boolean
109-
ArgListCommandFuncBoolReturn: TypeAlias = Callable[[CmdOrSetT, list[str]], bool]
110-
# Function signature for a command function that accepts a pre-processed argument list from user input
111-
# and returns Nothing
112-
ArgListCommandFuncNoneReturn: TypeAlias = Callable[[CmdOrSetT, list[str]], None]
113-
114-
# Aggregate of all accepted function signatures for command functions that accept a pre-processed argument list
115-
ArgListCommandFunc: TypeAlias = (
116-
ArgListCommandFuncOptionalBoolReturn[CmdOrSetT]
117-
| ArgListCommandFuncBoolReturn[CmdOrSetT]
118-
| ArgListCommandFuncNoneReturn[CmdOrSetT]
119-
)
111+
ArgListCommandFunc: TypeAlias = UnboundCommandFunc[CmdOrSetT, [list[str]]]
120112

121113

122114
def with_argument_list(
123115
func_arg: ArgListCommandFunc[CmdOrSetT] | None = None,
124116
*,
125117
preserve_quotes: bool = False,
126-
) -> (
127-
RawCommandFuncOptionalBoolReturn[CmdOrSetT]
128-
| Callable[[ArgListCommandFunc[CmdOrSetT]], RawCommandFuncOptionalBoolReturn[CmdOrSetT]]
129-
):
118+
) -> RawCommandFunc[CmdOrSetT] | Callable[[ArgListCommandFunc[CmdOrSetT]], RawCommandFunc[CmdOrSetT]]:
130119
"""Decorate a ``do_*`` method to alter the arguments passed to it so it is passed a list[str].
131120
132121
Default passes a string of whatever the user typed. With this decorator, the
133122
decorated method will receive a list of arguments parsed from user input.
134123
135-
:param func_arg: Single-element positional argument list containing ``doi_*`` method
124+
:param func_arg: Single-element positional argument list containing ``do_*`` method
136125
this decorator is wrapping
137126
:param preserve_quotes: if ``True``, then argument quotes will not be stripped
138127
:return: function that gets passed a list of argument strings
@@ -148,7 +137,7 @@ def do_echo(self, arglist):
148137
"""
149138
import functools
150139

151-
def arg_decorator(func: ArgListCommandFunc[CmdOrSetT]) -> RawCommandFuncOptionalBoolReturn[CmdOrSetT]:
140+
def arg_decorator(func: ArgListCommandFunc[CmdOrSetT]) -> RawCommandFunc[CmdOrSetT]:
152141
"""Decorate function that ingests an Argument List function and returns a raw command function.
153142
154143
The returned function will process the raw input into an argument list to be passed to the wrapped function.
@@ -182,30 +171,11 @@ def cmd_wrapper(*args: Any, **kwargs: Any) -> bool | None:
182171

183172

184173
# Function signatures for command functions that use a Cmd2ArgumentParser to process user input
185-
# and optionally return a boolean
186-
ArgparseCommandFuncOptionalBoolReturn: TypeAlias = Callable[[CmdOrSetT, argparse.Namespace], bool | None]
187-
ArgparseCommandFuncWithUnknownArgsOptionalBoolReturn: TypeAlias = Callable[
188-
[CmdOrSetT, argparse.Namespace, list[str]], bool | None
189-
]
190-
191-
# Function signatures for command functions that use a Cmd2ArgumentParser to process user input
192-
# and return a boolean
193-
ArgparseCommandFuncBoolReturn: TypeAlias = Callable[[CmdOrSetT, argparse.Namespace], bool]
194-
ArgparseCommandFuncWithUnknownArgsBoolReturn: TypeAlias = Callable[[CmdOrSetT, argparse.Namespace, list[str]], bool]
195-
196-
# Function signatures for command functions that use a Cmd2ArgumentParser to process user input
197-
# and return nothing
198-
ArgparseCommandFuncNoneReturn: TypeAlias = Callable[[CmdOrSetT, argparse.Namespace], None]
199-
ArgparseCommandFuncWithUnknownArgsNoneReturn: TypeAlias = Callable[[CmdOrSetT, argparse.Namespace, list[str]], None]
200-
201-
# Aggregate of all accepted function signatures for an argparse command function
202174
ArgparseCommandFunc: TypeAlias = (
203-
ArgparseCommandFuncOptionalBoolReturn[CmdOrSetT]
204-
| ArgparseCommandFuncWithUnknownArgsOptionalBoolReturn[CmdOrSetT]
205-
| ArgparseCommandFuncBoolReturn[CmdOrSetT]
206-
| ArgparseCommandFuncWithUnknownArgsBoolReturn[CmdOrSetT]
207-
| ArgparseCommandFuncNoneReturn[CmdOrSetT]
208-
| ArgparseCommandFuncWithUnknownArgsNoneReturn[CmdOrSetT]
175+
# (self, args: argparse.Namespace)
176+
UnboundCommandFunc[CmdOrSetT, [argparse.Namespace]]
177+
# (self, args: argparse.Namespace, unknown_args: list[str])
178+
| UnboundCommandFunc[CmdOrSetT, [argparse.Namespace, list[str]]]
209179
)
210180

211181

@@ -217,7 +187,7 @@ def with_argparser(
217187
ns_provider: Callable[..., argparse.Namespace] | None = None,
218188
preserve_quotes: bool = False,
219189
with_unknown_args: bool = False,
220-
) -> Callable[[ArgparseCommandFunc[CmdOrSetT]], RawCommandFuncOptionalBoolReturn[CmdOrSetT]]:
190+
) -> Callable[[ArgparseCommandFunc[CmdOrSetT]], RawCommandFunc[CmdOrSetT]]:
221191
"""Decorate a ``do_*`` method to populate its ``args`` argument with the given instance of Cmd2ArgumentParser.
222192
223193
:param parser: instance of Cmd2ArgumentParser or a callable that returns a Cmd2ArgumentParser for this command
@@ -265,7 +235,7 @@ def do_argprint(self, args, unknown):
265235
"""
266236
import functools
267237

268-
def arg_decorator(func: ArgparseCommandFunc[CmdOrSetT]) -> RawCommandFuncOptionalBoolReturn[CmdOrSetT]:
238+
def arg_decorator(func: ArgparseCommandFunc[CmdOrSetT]) -> RawCommandFunc[CmdOrSetT]:
269239
"""Decorate function that ingests an Argparse Command Function and returns a raw command function.
270240
271241
The returned function will process the raw input into an argparse Namespace to be passed to the wrapped function.

cmd2/types.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
TYPE_CHECKING,
1010
Any,
1111
Concatenate,
12+
ParamSpec,
1213
TypeAlias,
1314
TypeVar,
1415
Union,
@@ -19,6 +20,10 @@
1920
from .command_set import CommandSet
2021
from .completion import Choices, Completions
2122

23+
# TypeVar for function parameters
24+
P = ParamSpec("P")
25+
26+
2227
##################################################################################################
2328
# Cmd and CommandSet Aliases (For basic inputs)
2429
#
@@ -67,11 +72,7 @@
6772

6873
# An unbound cmd2 command function (e.g. the class method do_command).
6974
# The 'self' argument can be either a Cmd or CommandSet instance.
70-
UnboundCommandFunc: TypeAlias = Callable[Concatenate[CmdOrSetT, ...], bool | None]
71-
72-
# TypeVar for unbound command methods that preserves the specific signature.
73-
# This allows decorators to return a function with the same argument types as the original.
74-
UnboundCommandFuncT = TypeVar("UnboundCommandFuncT", bound=UnboundCommandFunc[Any])
75+
UnboundCommandFunc: TypeAlias = Callable[Concatenate[CmdOrSetT, P], bool | None]
7576

7677

7778
##################################################################################################

0 commit comments

Comments
 (0)