Skip to content

Commit 9d1b7c7

Browse files
committed
Some mypy validation fixes
1 parent f30627d commit 9d1b7c7

File tree

9 files changed

+121
-112
lines changed

9 files changed

+121
-112
lines changed

cmd2/ansi.py

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,16 @@
1313
Any,
1414
List,
1515
Union,
16+
cast,
1617
)
1718

18-
import colorama
19+
import colorama # type: ignore [import]
1920
from colorama import (
2021
Back,
2122
Fore,
2223
Style,
2324
)
24-
from wcwidth import (
25+
from wcwidth import ( # type: ignore [import]
2526
wcswidth,
2627
)
2728

@@ -86,14 +87,14 @@ def __add__(self, other: Any) -> str:
8687
Support building a color string when self is the left operand
8788
e.g. fg.blue + "hello"
8889
"""
89-
return str(self) + other
90+
return cast(str, str(self) + other)
9091

9192
def __radd__(self, other: Any) -> str:
9293
"""
9394
Support building a color string when self is the right operand
9495
e.g. "hello" + fg.reset
9596
"""
96-
return other + str(self)
97+
return cast(str, other + str(self))
9798

9899
@classmethod
99100
def colors(cls) -> List[str]:
@@ -194,7 +195,7 @@ def style_aware_wcswidth(text: str) -> int:
194195
then this function returns -1. Replace tabs with spaces before calling this.
195196
"""
196197
# Strip ANSI style sequences since they cause wcswidth to return -1
197-
return wcswidth(strip_style(text))
198+
return cast(int, wcswidth(strip_style(text)))
198199

199200

200201
def widest_line(text: str) -> int:
@@ -217,7 +218,7 @@ def widest_line(text: str) -> int:
217218
return max(lines_widths)
218219

219220

220-
def style_aware_write(fileobj: IO, msg: str) -> None:
221+
def style_aware_write(fileobj: IO[str], msg: str) -> None:
221222
"""
222223
Write a string to a fileobject and strip its ANSI style sequences if required by allow_style setting
223224
@@ -229,7 +230,7 @@ def style_aware_write(fileobj: IO, msg: str) -> None:
229230
fileobj.write(msg)
230231

231232

232-
def fg_lookup(fg_name: Union[str, fg]) -> str:
233+
def fg_lookup(fg_name: Union[str, fg]) -> Fore:
233234
"""
234235
Look up ANSI escape codes based on foreground color name.
235236
@@ -247,7 +248,7 @@ def fg_lookup(fg_name: Union[str, fg]) -> str:
247248
return ansi_escape
248249

249250

250-
def bg_lookup(bg_name: Union[str, bg]) -> str:
251+
def bg_lookup(bg_name: Union[str, bg]) -> Back:
251252
"""
252253
Look up ANSI escape codes based on background color name.
253254
@@ -321,7 +322,7 @@ def style(
321322
removals.append(UNDERLINE_DISABLE)
322323

323324
# Combine the ANSI style sequences with the text
324-
return "".join(additions) + text + "".join(removals)
325+
return cast(str, "".join(additions) + text + "".join(removals))
325326

326327

327328
# Default styles for printing strings of various types.
@@ -400,4 +401,4 @@ def set_title_str(title: str) -> str:
400401
:param title: new title for the window
401402
:return: string to write to sys.stderr in order to set the window title to the desired test
402403
"""
403-
return colorama.ansi.set_title(title)
404+
return cast(str, colorama.ansi.set_title(title))

cmd2/argparse_custom.py

Lines changed: 43 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -198,16 +198,21 @@ def my_completer(self, text, line, begidx, endidx, arg_tokens)
198198
ONE_OR_MORE,
199199
ZERO_OR_MORE,
200200
ArgumentError,
201-
_,
201+
)
202+
from gettext import (
203+
gettext,
202204
)
203205
from typing import (
204206
Any,
205207
Callable,
208+
Iterable,
209+
List,
206210
NoReturn,
207211
Optional,
208212
Tuple,
209213
Type,
210214
Union,
215+
cast,
211216
)
212217

213218
from . import (
@@ -261,11 +266,11 @@ class CompletionItem(str):
261266
See header of this file for more information
262267
"""
263268

264-
def __new__(cls, value: object, *args, **kwargs) -> str:
265-
return super().__new__(cls, value)
269+
def __new__(cls, value: object, *args: Any, **kwargs: Any) -> 'CompletionItem':
270+
return cast(CompletionItem, super(CompletionItem, cls).__new__(cls, value)) # type: ignore [call-arg]
266271

267272
# noinspection PyUnusedLocal
268-
def __init__(self, value: object, desc: str = '', *args) -> None:
273+
def __init__(self, value: object, desc: str = '', *args: Any) -> None:
269274
"""
270275
CompletionItem Initializer
271276
@@ -287,7 +292,11 @@ class ChoicesCallable:
287292
While argparse has the built-in choices attribute, it is limited to an iterable.
288293
"""
289294

290-
def __init__(self, is_completer: bool, to_call: Callable):
295+
def __init__(
296+
self,
297+
is_completer: bool,
298+
to_call: Union[Callable[[], List[str]], Callable[[str, str, int, int], List[str]]],
299+
) -> None:
291300
"""
292301
Initializer
293302
:param is_completer: True if to_call is a tab completion routine which expects
@@ -319,12 +328,12 @@ def _set_choices_callable(action: argparse.Action, choices_callable: ChoicesCall
319328
setattr(action, ATTR_CHOICES_CALLABLE, choices_callable)
320329

321330

322-
def set_choices_provider(action: argparse.Action, choices_provider: Callable) -> None:
331+
def set_choices_provider(action: argparse.Action, choices_provider: Callable[[], List[str]]) -> None:
323332
"""Set choices_provider on an argparse action"""
324333
_set_choices_callable(action, ChoicesCallable(is_completer=False, to_call=choices_provider))
325334

326335

327-
def set_completer(action: argparse.Action, completer: Callable) -> None:
336+
def set_completer(action: argparse.Action, completer: Callable[[str, str, int, int], List[str]]) -> None:
328337
"""Set completer on an argparse action"""
329338
_set_choices_callable(action, ChoicesCallable(is_completer=True, to_call=completer))
330339

@@ -339,14 +348,14 @@ def set_completer(action: argparse.Action, completer: Callable) -> None:
339348

340349

341350
def _add_argument_wrapper(
342-
self,
343-
*args,
351+
self: argparse._ActionsContainer,
352+
*args: Any,
344353
nargs: Union[int, str, Tuple[int], Tuple[int, int], Tuple[int, float], None] = None,
345-
choices_provider: Optional[Callable] = None,
346-
completer: Optional[Callable] = None,
354+
choices_provider: Optional[Callable[[], List[str]]] = None,
355+
completer: Optional[Callable[[str, str, int, int], List[str]]] = None,
347356
suppress_tab_hint: bool = False,
348357
descriptive_header: Optional[str] = None,
349-
**kwargs
358+
**kwargs: Any
350359
) -> argparse.Action:
351360
"""
352361
Wrapper around _ActionsContainer.add_argument() which supports more settings used by cmd2
@@ -392,6 +401,7 @@ def _add_argument_wrapper(
392401
nargs_range = None
393402

394403
if nargs is not None:
404+
nargs_adjusted: Union[int, str, Tuple[int], Tuple[int, int], Tuple[int, float], None]
395405
# Check if nargs was given as a range
396406
if isinstance(nargs, tuple):
397407

@@ -402,19 +412,19 @@ def _add_argument_wrapper(
402412
# Validate nargs tuple
403413
if (
404414
len(nargs) != 2
405-
or not isinstance(nargs[0], int)
406-
or not (isinstance(nargs[1], int) or nargs[1] == constants.INFINITY)
415+
or not isinstance(nargs[0], int) # type: ignore[unreachable]
416+
or not (isinstance(nargs[1], int) or nargs[1] == constants.INFINITY) # type: ignore[misc]
407417
):
408418
raise ValueError('Ranged values for nargs must be a tuple of 1 or 2 integers')
409-
if nargs[0] >= nargs[1]:
419+
if nargs[0] >= nargs[1]: # type: ignore[misc]
410420
raise ValueError('Invalid nargs range. The first value must be less than the second')
411421
if nargs[0] < 0:
412422
raise ValueError('Negative numbers are invalid for nargs range')
413423

414424
# Save the nargs tuple as our range setting
415425
nargs_range = nargs
416426
range_min = nargs_range[0]
417-
range_max = nargs_range[1]
427+
range_max = nargs_range[1] # type: ignore[misc]
418428

419429
# Convert nargs into a format argparse recognizes
420430
if range_min == 0:
@@ -460,7 +470,7 @@ def _add_argument_wrapper(
460470

461471
# Overwrite _ActionsContainer.add_argument with our wrapper
462472
# noinspection PyProtectedMember
463-
argparse._ActionsContainer.add_argument = _add_argument_wrapper
473+
setattr(argparse._ActionsContainer, 'add_argument', _add_argument_wrapper)
464474

465475
############################################################################################################
466476
# Patch ArgumentParser._get_nargs_pattern with our wrapper to nargs ranges
@@ -472,7 +482,7 @@ def _add_argument_wrapper(
472482

473483

474484
# noinspection PyProtectedMember
475-
def _get_nargs_pattern_wrapper(self, action) -> str:
485+
def _get_nargs_pattern_wrapper(self: argparse.ArgumentParser, action: argparse.Action) -> str:
476486
# Wrapper around ArgumentParser._get_nargs_pattern behavior to support nargs ranges
477487
nargs_range = getattr(action, ATTR_NARGS_RANGE, None)
478488
if nargs_range is not None:
@@ -494,7 +504,7 @@ def _get_nargs_pattern_wrapper(self, action) -> str:
494504

495505
# Overwrite ArgumentParser._get_nargs_pattern with our wrapper
496506
# noinspection PyProtectedMember
497-
argparse.ArgumentParser._get_nargs_pattern = _get_nargs_pattern_wrapper
507+
setattr(argparse.ArgumentParser, '_get_nargs_pattern', _get_nargs_pattern_wrapper)
498508

499509

500510
############################################################################################################
@@ -505,7 +515,7 @@ def _get_nargs_pattern_wrapper(self, action) -> str:
505515

506516

507517
# noinspection PyProtectedMember
508-
def _match_argument_wrapper(self, action, arg_strings_pattern) -> int:
518+
def _match_argument_wrapper(self: argparse.ArgumentParser, action: argparse.Action, arg_strings_pattern: str) -> int:
509519
# Wrapper around ArgumentParser._match_argument behavior to support nargs ranges
510520
nargs_pattern = self._get_nargs_pattern(action)
511521
match = re.match(nargs_pattern, arg_strings_pattern)
@@ -521,15 +531,15 @@ def _match_argument_wrapper(self, action, arg_strings_pattern) -> int:
521531

522532
# Overwrite ArgumentParser._match_argument with our wrapper
523533
# noinspection PyProtectedMember
524-
argparse.ArgumentParser._match_argument = _match_argument_wrapper
534+
setattr(argparse.ArgumentParser, '_match_argument', _match_argument_wrapper)
525535

526536

527537
############################################################################################################
528538
# Patch argparse._SubParsersAction to add remove_parser function
529539
############################################################################################################
530540

531541
# noinspection PyPep8Naming
532-
def _SubParsersAction_remove_parser(self, name: str):
542+
def _SubParsersAction_remove_parser(self: argparse._SubParsersAction, name: str) -> None:
533543
"""
534544
Removes a sub-parser from a sub-parsers group
535545
@@ -572,20 +582,26 @@ class so cmd2 can remove subcommands from a parser.
572582
class Cmd2HelpFormatter(argparse.RawTextHelpFormatter):
573583
"""Custom help formatter to configure ordering of help text"""
574584

575-
def _format_usage(self, usage, actions, groups, prefix) -> str:
585+
def _format_usage(
586+
self,
587+
usage: Optional[str],
588+
actions: Iterable[argparse.Action],
589+
groups: Iterable[argparse._ArgumentGroup],
590+
prefix: Optional[str] = None,
591+
) -> str:
576592
if prefix is None:
577-
prefix = _('Usage: ')
593+
prefix = gettext('Usage: ')
578594

579595
# if usage is specified, use that
580596
if usage is not None:
581597
usage %= dict(prog=self._prog)
582598

583599
# if no optionals or positionals are available, usage is just prog
584-
elif usage is None and not actions:
600+
elif not actions:
585601
usage = '%(prog)s' % dict(prog=self._prog)
586602

587603
# if optionals and positionals are available, calculate usage
588-
elif usage is None:
604+
else:
589605
prog = '%(prog)s' % dict(prog=self._prog)
590606

591607
# split optionals from positionals
@@ -630,7 +646,7 @@ def _format_usage(self, usage, actions, groups, prefix) -> str:
630646

631647
# helper for wrapping lines
632648
# noinspection PyMissingOrEmptyDocstring,PyShadowingNames
633-
def get_lines(parts, indent, prefix=None):
649+
def get_lines(parts: List[str], indent: str, prefix: Optional[str] = None):
634650
lines = []
635651
line = []
636652
if prefix is not None:

cmd2/clipboard.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,11 @@
22
"""
33
This module provides basic ability to copy from and paste to the clipboard/pastebuffer.
44
"""
5-
import pyperclip
5+
from typing import (
6+
cast,
7+
)
8+
9+
import pyperclip # type: ignore [import]
610

711
# noinspection PyProtectedMember
812
from pyperclip import (
@@ -26,7 +30,7 @@ def get_paste_buffer() -> str:
2630
2731
:return: contents of the clipboard
2832
"""
29-
pb_str = pyperclip.paste()
33+
pb_str = cast(str, pyperclip.paste())
3034
return pb_str
3135

3236

cmd2/exceptions.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
# coding=utf-8
22
"""Custom exceptions for cmd2"""
33

4+
from typing import (
5+
Any,
6+
)
47

58
############################################################################################################
69
# The following exceptions are part of the public API
@@ -49,7 +52,7 @@ class CompletionError(Exception):
4952
- Tab completion hints
5053
"""
5154

52-
def __init__(self, *args, apply_style: bool = True):
55+
def __init__(self, *args: Any, apply_style: bool = True) -> None:
5356
"""
5457
Initializer for CompletionError
5558
:param apply_style: If True, then ansi.style_error will be applied to the message text when printed.
@@ -68,7 +71,7 @@ class PassThroughException(Exception):
6871
This class is used to wrap an exception that should be raised instead of printed.
6972
"""
7073

71-
def __init__(self, *args, wrapped_ex: BaseException):
74+
def __init__(self, *args: Any, wrapped_ex: BaseException) -> None:
7275
"""
7376
Initializer for PassThroughException
7477
:param wrapped_ex: the exception that will be raised

cmd2/plugin.py

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,33 +3,37 @@
33
"""Classes for the cmd2 plugin system"""
44
import attr
55

6+
from .parsing import (
7+
Statement,
8+
)
69

7-
@attr.s
10+
11+
@attr.s(auto_attribs=True)
812
class PostparsingData:
913
"""Data class containing information passed to postparsing hook methods"""
1014

11-
stop = attr.ib()
12-
statement = attr.ib()
15+
stop: bool
16+
statement: Statement
1317

1418

15-
@attr.s
19+
@attr.s(auto_attribs=True)
1620
class PrecommandData:
1721
"""Data class containing information passed to precommand hook methods"""
1822

19-
statement = attr.ib()
23+
statement: Statement
2024

2125

22-
@attr.s
26+
@attr.s(auto_attribs=True)
2327
class PostcommandData:
2428
"""Data class containing information passed to postcommand hook methods"""
2529

26-
stop = attr.ib()
27-
statement = attr.ib()
30+
stop: bool
31+
statement: Statement
2832

2933

30-
@attr.s
34+
@attr.s(auto_attribs=True)
3135
class CommandFinalizationData:
3236
"""Data class containing information passed to command finalization hook methods"""
3337

34-
stop = attr.ib()
35-
statement = attr.ib()
38+
stop: bool
39+
statement: Statement

0 commit comments

Comments
 (0)