Skip to content

Commit 33951e8

Browse files
committed
More things to make mypy happy.
1 parent f90db55 commit 33951e8

File tree

9 files changed

+240
-174
lines changed

9 files changed

+240
-174
lines changed

cmd2/argparse_custom.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -872,7 +872,7 @@ def __init__(
872872
usage: Optional[str] = None,
873873
description: Optional[str] = None,
874874
epilog: Optional[str] = None,
875-
parents: Sequence[argparse.ArgumentParser] = [],
875+
parents: Sequence[argparse.ArgumentParser] = (),
876876
formatter_class: Type[argparse.HelpFormatter] = Cmd2HelpFormatter,
877877
prefix_chars: str = '-',
878878
fromfile_prefix_chars: Optional[str] = None,
@@ -989,7 +989,7 @@ class Cmd2AttributeWrapper:
989989
arguments from a parser and which were added by cmd2.
990990
"""
991991

992-
def __init__(self, attribute: Any):
992+
def __init__(self, attribute: Any) -> None:
993993
self.__attribute = attribute
994994

995995
def get(self) -> Any:

cmd2/cmd2.py

Lines changed: 135 additions & 115 deletions
Large diffs are not rendered by default.

cmd2/command_definition.py

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
Supports the definition of commands in separate classes to be composed into cmd2.Cmd
44
"""
55
from typing import (
6+
Callable,
67
Dict,
78
Mapping,
89
Optional,
@@ -33,7 +34,12 @@
3334
pass
3435

3536

36-
def with_default_category(category: str, *, heritable: bool = True):
37+
#: Callable signature for a basic command function
38+
#: Further refinements are needed to define the input parameters
39+
CommandFunc = Callable[..., Optional[bool]]
40+
41+
42+
def with_default_category(category: str, *, heritable: bool = True) -> Callable[[Type['CommandSet']], Type['CommandSet']]:
3743
"""
3844
Decorator that applies a category to all ``do_*`` command methods in a class that do not already
3945
have a category specified.
@@ -52,7 +58,7 @@ def with_default_category(category: str, *, heritable: bool = True):
5258
:return: decorator function
5359
"""
5460

55-
def decorate_class(cls: Type[CommandSet]):
61+
def decorate_class(cls: Type[CommandSet]) -> Type[CommandSet]:
5662
if heritable:
5763
setattr(cls, CLASS_ATTR_DEFAULT_HELP_CATEGORY, category)
5864

@@ -93,19 +99,18 @@ class CommandSet(object):
9399
``do_``, ``help_``, and ``complete_`` functions differ only in that self is the CommandSet instead of the cmd2 app
94100
"""
95101

96-
def __init__(self):
102+
def __init__(self) -> None:
97103
self._cmd: Optional[cmd2.Cmd] = None
98104
self._settables: Dict[str, Settable] = {}
99105
self._settable_prefix = self.__class__.__name__
100106

101-
def on_register(self, cmd) -> None:
107+
def on_register(self, cmd: 'cmd2.Cmd') -> None:
102108
"""
103109
Called by cmd2.Cmd as the first step to registering a CommandSet. The commands defined in this class have
104110
not be added to the CLI object at this point. Subclasses can override this to perform any initialization
105111
requiring access to the Cmd object (e.g. configure commands and their parsers based on CLI state data).
106112
107113
:param cmd: The cmd2 main application
108-
:type cmd: cmd2.Cmd
109114
"""
110115
if self._cmd is None:
111116
self._cmd = cmd

cmd2/decorators.py

Lines changed: 47 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
Any,
77
Callable,
88
Dict,
9-
Iterable,
109
List,
1110
Optional,
1211
Tuple,
@@ -19,6 +18,10 @@
1918
from .argparse_custom import (
2019
Cmd2AttributeWrapper,
2120
)
21+
from .command_definition import (
22+
CommandFunc,
23+
CommandSet,
24+
)
2225
from .exceptions import (
2326
Cmd2ArgparseError,
2427
)
@@ -30,7 +33,7 @@
3033
import cmd2
3134

3235

33-
def with_category(category: str) -> Callable:
36+
def with_category(category: str) -> Callable[[CommandFunc], CommandFunc]:
3437
"""A decorator to apply a category to a ``do_*`` command method.
3538
3639
:param category: the name of the category in which this command should
@@ -47,7 +50,7 @@ def with_category(category: str) -> Callable:
4750
:func:`~cmd2.utils.categorize`
4851
"""
4952

50-
def cat_decorator(func):
53+
def cat_decorator(func: CommandFunc) -> CommandFunc:
5154
from .utils import (
5255
categorize,
5356
)
@@ -65,7 +68,7 @@ def cat_decorator(func):
6568
##########################
6669

6770

68-
def _parse_positionals(args: Tuple) -> Tuple[Union['cmd2.Cmd', 'cmd2.CommandSet'], Union[Statement, str]]:
71+
def _parse_positionals(args: Tuple[Any, ...]) -> Tuple['cmd2.Cmd', Union[Statement, str]]:
6972
"""
7073
Helper function for cmd2 decorators to inspect the positional arguments until the cmd2.Cmd argument is found
7174
Assumes that we will find cmd2.Cmd followed by the command statement object or string.
@@ -75,7 +78,6 @@ def _parse_positionals(args: Tuple) -> Tuple[Union['cmd2.Cmd', 'cmd2.CommandSet'
7578
for pos, arg in enumerate(args):
7679
from cmd2 import (
7780
Cmd,
78-
CommandSet,
7981
)
8082

8183
if (isinstance(arg, Cmd) or isinstance(arg, CommandSet)) and len(args) > pos:
@@ -104,13 +106,15 @@ def _arg_swap(args: Union[Tuple[Any], List[Any]], search_arg: Any, *replace_arg:
104106
return args_list
105107

106108

107-
def with_argument_list(*args: List[Callable], preserve_quotes: bool = False) -> Callable[[List], Optional[bool]]:
109+
def with_argument_list(
110+
func_arg: Optional[Callable[[List[str]], Optional[bool]]] = None, *, preserve_quotes: bool = False
111+
) -> Union[Callable[[List[str]], Optional[bool]],]:
108112
"""
109113
A decorator to alter the arguments passed to a ``do_*`` method. Default
110114
passes a string of whatever the user typed. With this decorator, the
111115
decorated method will receive a list of arguments parsed from user input.
112116
113-
:param args: Single-element positional argument list containing ``do_*`` method
117+
:param func_arg: Single-element positional argument list containing ``do_*`` method
114118
this decorator is wrapping
115119
:param preserve_quotes: if ``True``, then argument quotes will not be stripped
116120
:return: function that gets passed a list of argument strings
@@ -124,9 +128,9 @@ def with_argument_list(*args: List[Callable], preserve_quotes: bool = False) ->
124128
"""
125129
import functools
126130

127-
def arg_decorator(func: Callable):
131+
def arg_decorator(func: Callable[[List[str]], Optional[bool]]) -> Callable[..., Optional[bool]]:
128132
@functools.wraps(func)
129-
def cmd_wrapper(*args, **kwargs: Dict[str, Any]) -> Optional[bool]:
133+
def cmd_wrapper(*args: Any, **kwargs: Any) -> Optional[bool]:
130134
"""
131135
Command function wrapper which translates command line into an argument list and calls actual command function
132136
@@ -145,9 +149,9 @@ def cmd_wrapper(*args, **kwargs: Dict[str, Any]) -> Optional[bool]:
145149
cmd_wrapper.__doc__ = func.__doc__
146150
return cmd_wrapper
147151

148-
if len(args) == 1 and callable(args[0]):
152+
if callable(func_arg):
149153
# noinspection PyTypeChecker
150-
return arg_decorator(args[0])
154+
return arg_decorator(func_arg)
151155
else:
152156
# noinspection PyTypeChecker
153157
return arg_decorator
@@ -196,13 +200,30 @@ def _set_parser_prog(parser: argparse.ArgumentParser, prog: str):
196200
break
197201

198202

203+
ArgparseCommandFunc = Union[
204+
Callable[['cmd2.Cmd', argparse.Namespace], Optional[bool]],
205+
Callable[[CommandSet, argparse.Namespace], Optional[bool]],
206+
]
207+
ArgparseCommandFuncBoolReturn = Union[
208+
Callable[['cmd2.Cmd', argparse.Namespace], bool],
209+
Callable[[CommandSet, argparse.Namespace], bool],
210+
]
211+
ArgparseCommandFuncNoneReturn = Union[
212+
Callable[['cmd2.Cmd', argparse.Namespace], None],
213+
Callable[[CommandSet, argparse.Namespace], None],
214+
]
215+
216+
199217
def with_argparser(
200218
parser: argparse.ArgumentParser,
201219
*,
202220
ns_provider: Optional[Callable[..., argparse.Namespace]] = None,
203221
preserve_quotes: bool = False,
204-
with_unknown_args: bool = False
205-
) -> Callable[[argparse.Namespace], Optional[bool]]:
222+
with_unknown_args: bool = False,
223+
) -> Callable[
224+
[Union[ArgparseCommandFunc, ArgparseCommandFuncNoneReturn, ArgparseCommandFuncBoolReturn]],
225+
Callable[[Union['cmd2.Cmd', CommandSet], str], Optional[bool]],
226+
]:
206227
"""A decorator to alter a cmd2 method to populate its ``args`` argument by parsing arguments
207228
with the given instance of argparse.ArgumentParser.
208229
@@ -248,7 +269,9 @@ def with_argparser(
248269
"""
249270
import functools
250271

251-
def arg_decorator(func: Callable):
272+
def arg_decorator(
273+
func: Union[ArgparseCommandFunc, ArgparseCommandFuncBoolReturn, ArgparseCommandFuncNoneReturn],
274+
) -> ArgparseCommandFunc:
252275
@functools.wraps(func)
253276
def cmd_wrapper(*args: Any, **kwargs: Dict[str, Any]) -> Optional[bool]:
254277
"""
@@ -327,8 +350,11 @@ def as_subcommand_to(
327350
parser: argparse.ArgumentParser,
328351
*,
329352
help: Optional[str] = None,
330-
aliases: Iterable[str] = None
331-
) -> Callable[[argparse.Namespace], Optional[bool]]:
353+
aliases: Optional[List[str]] = None,
354+
) -> Callable[
355+
[Union[ArgparseCommandFunc, ArgparseCommandFuncNoneReturn, ArgparseCommandFuncBoolReturn]],
356+
Union[ArgparseCommandFunc, ArgparseCommandFuncBoolReturn, ArgparseCommandFuncNoneReturn],
357+
]:
332358
"""
333359
Tag this method as a subcommand to an existing argparse decorated command.
334360
@@ -342,7 +368,9 @@ def as_subcommand_to(
342368
:return: Wrapper function that can receive an argparse.Namespace
343369
"""
344370

345-
def arg_decorator(func: Callable):
371+
def arg_decorator(
372+
func: Union[ArgparseCommandFunc, ArgparseCommandFuncBoolReturn, ArgparseCommandFuncNoneReturn]
373+
) -> Union[ArgparseCommandFunc, ArgparseCommandFuncBoolReturn, ArgparseCommandFuncNoneReturn]:
346374
_set_parser_prog(parser, command + ' ' + subcommand)
347375

348376
# If the description has not been set, then use the method docstring if one exists
@@ -355,10 +383,10 @@ def arg_decorator(func: Callable):
355383
setattr(func, constants.SUBCMD_ATTR_NAME, subcommand)
356384

357385
# Keyword arguments for ArgumentParser.add_subparser()
358-
add_parser_kwargs = dict()
386+
add_parser_kwargs: Dict[str, Any] = dict()
359387
if help is not None:
360388
add_parser_kwargs['help'] = help
361-
if aliases is not None:
389+
if aliases:
362390
add_parser_kwargs['aliases'] = aliases[:]
363391

364392
setattr(func, constants.SUBCMD_ATTR_ADD_PARSER_KWARGS, add_parser_kwargs)

cmd2/parsing.py

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ def shlex_split(str_to_split: str) -> List[str]:
3535
return shlex.split(str_to_split, comments=False, posix=False)
3636

3737

38-
@attr.s(frozen=True)
38+
@attr.s(auto_attribs=True, frozen=True)
3939
class MacroArg:
4040
"""
4141
Information used to replace or unescape arguments in a macro value when the macro is resolved
@@ -44,15 +44,15 @@ class MacroArg:
4444
"""
4545

4646
# The starting index of this argument in the macro value
47-
start_index = attr.ib(validator=attr.validators.instance_of(int))
47+
start_index: int = attr.ib(validator=attr.validators.instance_of(int))
4848

4949
# The number string that appears between the braces
5050
# This is a string instead of an int because we support unicode digits and must be able
5151
# to reproduce this string later
52-
number_str = attr.ib(validator=attr.validators.instance_of(str))
52+
number_str: str = attr.ib(validator=attr.validators.instance_of(str))
5353

5454
# Tells if this argument is escaped and therefore needs to be unescaped
55-
is_escaped = attr.ib(validator=attr.validators.instance_of(bool))
55+
is_escaped: bool = attr.ib(validator=attr.validators.instance_of(bool))
5656

5757
# Pattern used to find normal argument
5858
# Digits surrounded by exactly 1 brace on a side and 1 or more braces on the opposite side
@@ -68,24 +68,24 @@ class MacroArg:
6868
digit_pattern = re.compile(r'\d+')
6969

7070

71-
@attr.s(frozen=True)
71+
@attr.s(auto_attribs=True, frozen=True)
7272
class Macro:
7373
"""Defines a cmd2 macro"""
7474

7575
# Name of the macro
76-
name = attr.ib(validator=attr.validators.instance_of(str))
76+
name: str = attr.ib(validator=attr.validators.instance_of(str))
7777

7878
# The string the macro resolves to
79-
value = attr.ib(validator=attr.validators.instance_of(str))
79+
value: str = attr.ib(validator=attr.validators.instance_of(str))
8080

8181
# The minimum number of args the user has to pass to this macro
82-
minimum_arg_count = attr.ib(validator=attr.validators.instance_of(int))
82+
minimum_arg_count: int = attr.ib(validator=attr.validators.instance_of(int))
8383

8484
# Used to fill in argument placeholders in the macro
85-
arg_list = attr.ib(default=attr.Factory(list), validator=attr.validators.instance_of(list))
85+
arg_list: List[MacroArg] = attr.ib(default=attr.Factory(list), validator=attr.validators.instance_of(list))
8686

8787

88-
@attr.s(frozen=True)
88+
@attr.s(auto_attribs=True, frozen=True)
8989
class Statement(str):
9090
"""String subclass with additional attributes to store the results of parsing.
9191
@@ -117,34 +117,34 @@ class Statement(str):
117117
"""
118118

119119
# the arguments, but not the command, nor the output redirection clauses.
120-
args = attr.ib(default='', validator=attr.validators.instance_of(str))
120+
args: str = attr.ib(default='', validator=attr.validators.instance_of(str))
121121

122122
# string containing exactly what we input by the user
123-
raw = attr.ib(default='', validator=attr.validators.instance_of(str))
123+
raw: str = attr.ib(default='', validator=attr.validators.instance_of(str))
124124

125125
# the command, i.e. the first whitespace delimited word
126-
command = attr.ib(default='', validator=attr.validators.instance_of(str))
126+
command: str = attr.ib(default='', validator=attr.validators.instance_of(str))
127127

128128
# list of arguments to the command, not including any output redirection or terminators; quoted args remain quoted
129-
arg_list = attr.ib(default=attr.Factory(list), validator=attr.validators.instance_of(list))
129+
arg_list: List[str] = attr.ib(default=attr.Factory(list), validator=attr.validators.instance_of(list))
130130

131131
# if the command is a multiline command, the name of the command, otherwise empty
132-
multiline_command = attr.ib(default='', validator=attr.validators.instance_of(str))
132+
multiline_command: str = attr.ib(default='', validator=attr.validators.instance_of(str))
133133

134134
# the character which terminated the multiline command, if there was one
135-
terminator = attr.ib(default='', validator=attr.validators.instance_of(str))
135+
terminator: str = attr.ib(default='', validator=attr.validators.instance_of(str))
136136

137137
# characters appearing after the terminator but before output redirection, if any
138-
suffix = attr.ib(default='', validator=attr.validators.instance_of(str))
138+
suffix: str = attr.ib(default='', validator=attr.validators.instance_of(str))
139139

140140
# if output was piped to a shell command, the shell command as a string
141-
pipe_to = attr.ib(default='', validator=attr.validators.instance_of(str))
141+
pipe_to: str = attr.ib(default='', validator=attr.validators.instance_of(str))
142142

143143
# if output was redirected, the redirection token, i.e. '>>'
144-
output = attr.ib(default='', validator=attr.validators.instance_of(str))
144+
output: str = attr.ib(default='', validator=attr.validators.instance_of(str))
145145

146146
# if output was redirected, the destination file token (quotes preserved)
147-
output_to = attr.ib(default='', validator=attr.validators.instance_of(str))
147+
output_to: str = attr.ib(default='', validator=attr.validators.instance_of(str))
148148

149149
def __new__(cls, value: object, *pos_args, **kw_args):
150150
"""Create a new instance of Statement.

cmd2/plugin.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
#
22
# coding=utf-8
33
"""Classes for the cmd2 plugin system"""
4+
from typing import (
5+
Optional,
6+
)
7+
48
import attr
59

610
from .parsing import (
@@ -36,4 +40,4 @@ class CommandFinalizationData:
3640
"""Data class containing information passed to command finalization hook methods"""
3741

3842
stop: bool
39-
statement: Statement
43+
statement: Optional[Statement]

0 commit comments

Comments
 (0)