Skip to content

Commit 2323818

Browse files
committed
Force use of future annotations to enable better support for modern type hints that don't require things like Optional
This also supports better runtime performance by allowing imports only used for type hints to be moved under `if TYPE_CHECKING:` blocks.
1 parent 896c7bb commit 2323818

File tree

111 files changed

+534
-302
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

111 files changed

+534
-302
lines changed

cmd2/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
"""Import certain things for backwards compatibility."""
22

3+
from __future__ import annotations
4+
35
import argparse
46
import contextlib
57
import importlib.metadata as importlib_metadata

cmd2/ansi.py

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
These are used for things like applying style to text, setting the window title, and asynchronous alerts.
44
"""
55

6+
from __future__ import annotations
7+
68
import functools
79
import re
810
from enum import (
@@ -11,7 +13,6 @@
1113
from typing import (
1214
IO,
1315
Any,
14-
Optional,
1516
cast,
1617
)
1718

@@ -951,14 +952,14 @@ def __str__(self) -> str:
951952
def style(
952953
value: Any,
953954
*,
954-
fg: Optional[FgColor] = None,
955-
bg: Optional[BgColor] = None,
956-
bold: Optional[bool] = None,
957-
dim: Optional[bool] = None,
958-
italic: Optional[bool] = None,
959-
overline: Optional[bool] = None,
960-
strikethrough: Optional[bool] = None,
961-
underline: Optional[bool] = None,
955+
fg: FgColor | None = None,
956+
bg: BgColor | None = None,
957+
bold: bool | None = None,
958+
dim: bool | None = None,
959+
italic: bool | None = None,
960+
overline: bool | None = None,
961+
strikethrough: bool | None = None,
962+
underline: bool | None = None,
962963
) -> str:
963964
"""Apply ANSI colors and/or styles to a string and return it.
964965

cmd2/argparse_completer.py

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
See the header of argparse_custom.py for instructions on how to use these features.
44
"""
55

6+
from __future__ import annotations
7+
68
import argparse
79
import inspect
810
import numbers
@@ -11,7 +13,6 @@
1113
)
1214
from typing import (
1315
TYPE_CHECKING,
14-
Optional,
1516
Union,
1617
cast,
1718
)
@@ -28,16 +29,16 @@
2829
from .cmd2 import (
2930
Cmd,
3031
)
32+
from .command_definition import (
33+
CommandSet,
34+
)
3135

3236
from .argparse_custom import (
3337
ChoicesCallable,
3438
ChoicesProviderFuncWithTokens,
3539
CompletionItem,
3640
generate_range_error,
3741
)
38-
from .command_definition import (
39-
CommandSet,
40-
)
4142
from .exceptions import (
4243
CompletionError,
4344
)
@@ -104,8 +105,8 @@ class _ArgumentState:
104105

105106
def __init__(self, arg_action: argparse.Action) -> None:
106107
self.action = arg_action
107-
self.min: Union[int, str]
108-
self.max: Union[float, int, str]
108+
self.min: int | str
109+
self.max: float | int | str
109110
self.count = 0
110111
self.is_remainder = self.action.nargs == argparse.REMAINDER
111112

@@ -162,7 +163,7 @@ class ArgparseCompleter:
162163
"""Automatic command line tab completion based on argparse parameters."""
163164

164165
def __init__(
165-
self, parser: argparse.ArgumentParser, cmd2_app: 'Cmd', *, parent_tokens: Optional[dict[str, list[str]]] = None
166+
self, parser: argparse.ArgumentParser, cmd2_app: Cmd, *, parent_tokens: dict[str, list[str]] | None = None
166167
) -> None:
167168
"""Create an ArgparseCompleter.
168169
@@ -202,7 +203,7 @@ def __init__(
202203
self._subcommand_action = action
203204

204205
def complete(
205-
self, text: str, line: str, begidx: int, endidx: int, tokens: list[str], *, cmd_set: Optional[CommandSet] = None
206+
self, text: str, line: str, begidx: int, endidx: int, tokens: list[str], *, cmd_set: CommandSet | None = None
206207
) -> list[str]:
207208
"""Complete text using argparse metadata.
208209
@@ -227,10 +228,10 @@ def complete(
227228
skip_remaining_flags = False
228229

229230
# _ArgumentState of the current positional
230-
pos_arg_state: Optional[_ArgumentState] = None
231+
pos_arg_state: _ArgumentState | None = None
231232

232233
# _ArgumentState of the current flag
233-
flag_arg_state: Optional[_ArgumentState] = None
234+
flag_arg_state: _ArgumentState | None = None
234235

235236
# Non-reusable flags that we've parsed
236237
matched_flags: list[str] = []
@@ -522,7 +523,7 @@ def _complete_flags(self, text: str, line: str, begidx: int, endidx: int, matche
522523

523524
return matches
524525

525-
def _format_completions(self, arg_state: _ArgumentState, completions: Union[list[str], list[CompletionItem]]) -> list[str]:
526+
def _format_completions(self, arg_state: _ArgumentState, completions: list[str] | list[CompletionItem]) -> list[str]:
526527
"""Format CompletionItems into hint table."""
527528
# Nothing to do if we don't have at least 2 completions which are all CompletionItems
528529
if len(completions) < 2 or not all(isinstance(c, CompletionItem) for c in completions):
@@ -652,15 +653,15 @@ def _complete_arg(
652653
arg_state: _ArgumentState,
653654
consumed_arg_values: dict[str, list[str]],
654655
*,
655-
cmd_set: Optional[CommandSet] = None,
656+
cmd_set: CommandSet | None = None,
656657
) -> list[str]:
657658
"""Tab completion routine for an argparse argument.
658659
659660
:return: list of completions
660661
:raises CompletionError: if the completer or choices function this calls raises one.
661662
"""
662663
# Check if the arg provides choices to the user
663-
arg_choices: Union[list[str], ChoicesCallable]
664+
arg_choices: list[str] | ChoicesCallable
664665
if arg_state.action.choices is not None:
665666
arg_choices = list(arg_state.action.choices)
666667
if not arg_choices:

cmd2/argparse_custom.py

Lines changed: 36 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,8 @@ def my_completer(self, text, line, begidx, endidx, arg_tokens)
221221
sub-parser from a sub-parsers group. See _SubParsersAction_remove_parser` for more details.
222222
"""
223223

224+
from __future__ import annotations
225+
224226
import argparse
225227
import re
226228
import sys
@@ -229,7 +231,6 @@ def my_completer(self, text, line, begidx, endidx, arg_tokens)
229231
ZERO_OR_MORE,
230232
ArgumentError,
231233
)
232-
from collections.abc import Callable, Iterable, Sequence
233234
from gettext import (
234235
gettext,
235236
)
@@ -245,12 +246,16 @@ def my_completer(self, text, line, begidx, endidx, arg_tokens)
245246
runtime_checkable,
246247
)
247248

249+
from typing_extensions import Self
250+
248251
from . import (
249252
ansi,
250253
constants,
251254
)
252255

253256
if TYPE_CHECKING: # pragma: no cover
257+
from collections.abc import Callable, Iterable, Sequence
258+
254259
from .argparse_completer import (
255260
ArgparseCompleter,
256261
)
@@ -281,7 +286,7 @@ class CompletionItem(str): # noqa: SLOT000
281286
See header of this file for more information
282287
"""
283288

284-
def __new__(cls, value: object, *_args: Any, **_kwargs: Any) -> 'CompletionItem':
289+
def __new__(cls, value: object, *_args: Any, **_kwargs: Any) -> Self:
285290
"""Responsible for creating and returning a new instance, called before __init__ when an object is instantiated."""
286291
return super().__new__(cls, value)
287292

@@ -371,7 +376,7 @@ class ChoicesCallable:
371376
def __init__(
372377
self,
373378
is_completer: bool,
374-
to_call: Union[CompleterFunc, ChoicesProviderFunc],
379+
to_call: CompleterFunc | ChoicesProviderFunc,
375380
) -> None:
376381
"""Initialize the ChoiceCallable instance.
377382
@@ -432,7 +437,7 @@ def choices_provider(self) -> ChoicesProviderFunc:
432437
############################################################################################################
433438
# Patch argparse.Action with accessors for choice_callable attribute
434439
############################################################################################################
435-
def _action_get_choices_callable(self: argparse.Action) -> Optional[ChoicesCallable]:
440+
def _action_get_choices_callable(self: argparse.Action) -> ChoicesCallable | None:
436441
"""Get the choices_callable attribute of an argparse Action.
437442
438443
This function is added by cmd2 as a method called ``get_choices_callable()`` to ``argparse.Action`` class.
@@ -518,7 +523,7 @@ def _action_set_completer(
518523
############################################################################################################
519524
# Patch argparse.Action with accessors for descriptive_header attribute
520525
############################################################################################################
521-
def _action_get_descriptive_header(self: argparse.Action) -> Optional[str]:
526+
def _action_get_descriptive_header(self: argparse.Action) -> str | None:
522527
"""Get the descriptive_header attribute of an argparse Action.
523528
524529
This function is added by cmd2 as a method called ``get_descriptive_header()`` to ``argparse.Action`` class.
@@ -534,7 +539,7 @@ def _action_get_descriptive_header(self: argparse.Action) -> Optional[str]:
534539
setattr(argparse.Action, 'get_descriptive_header', _action_get_descriptive_header)
535540

536541

537-
def _action_set_descriptive_header(self: argparse.Action, descriptive_header: Optional[str]) -> None:
542+
def _action_set_descriptive_header(self: argparse.Action, descriptive_header: str | None) -> None:
538543
"""Set the descriptive_header attribute of an argparse Action.
539544
540545
This function is added by cmd2 as a method called ``set_descriptive_header()`` to ``argparse.Action`` class.
@@ -553,7 +558,7 @@ def _action_set_descriptive_header(self: argparse.Action, descriptive_header: Op
553558
############################################################################################################
554559
# Patch argparse.Action with accessors for nargs_range attribute
555560
############################################################################################################
556-
def _action_get_nargs_range(self: argparse.Action) -> Optional[tuple[int, Union[int, float]]]:
561+
def _action_get_nargs_range(self: argparse.Action) -> tuple[int, int | float] | None:
557562
"""Get the nargs_range attribute of an argparse Action.
558563
559564
This function is added by cmd2 as a method called ``get_nargs_range()`` to ``argparse.Action`` class.
@@ -569,7 +574,7 @@ def _action_get_nargs_range(self: argparse.Action) -> Optional[tuple[int, Union[
569574
setattr(argparse.Action, 'get_nargs_range', _action_get_nargs_range)
570575

571576

572-
def _action_set_nargs_range(self: argparse.Action, nargs_range: Optional[tuple[int, Union[int, float]]]) -> None:
577+
def _action_set_nargs_range(self: argparse.Action, nargs_range: tuple[int, int | float] | None) -> None:
573578
"""Set the nargs_range attribute of an argparse Action.
574579
575580
This function is added by cmd2 as a method called ``set_nargs_range()`` to ``argparse.Action`` class.
@@ -628,7 +633,7 @@ def _action_set_suppress_tab_hint(self: argparse.Action, suppress_tab_hint: bool
628633
_CUSTOM_ATTRIB_PFX = '_attr_'
629634

630635

631-
def register_argparse_argument_parameter(param_name: str, param_type: Optional[type[Any]]) -> None:
636+
def register_argparse_argument_parameter(param_name: str, param_type: type[Any] | None) -> None:
632637
"""Register a custom argparse argument parameter.
633638
634639
The registered name will then be a recognized keyword parameter to the parser's `add_argument()` function.
@@ -694,11 +699,11 @@ def _action_set_custom_parameter(self: argparse.Action, value: Any) -> None:
694699
def _add_argument_wrapper(
695700
self: argparse._ActionsContainer,
696701
*args: Any,
697-
nargs: Union[int, str, tuple[int], tuple[int, int], tuple[int, float], None] = None,
698-
choices_provider: Optional[ChoicesProviderFunc] = None,
699-
completer: Optional[CompleterFunc] = None,
702+
nargs: int | str | tuple[int] | tuple[int, int] | tuple[int, float] | None = None,
703+
choices_provider: ChoicesProviderFunc | None = None,
704+
completer: CompleterFunc | None = None,
700705
suppress_tab_hint: bool = False,
701-
descriptive_header: Optional[str] = None,
706+
descriptive_header: str | None = None,
702707
**kwargs: Any,
703708
) -> argparse.Action:
704709
"""Wrap ActionsContainer.add_argument() which supports more settings used by cmd2.
@@ -744,7 +749,7 @@ def _add_argument_wrapper(
744749
nargs_range = None
745750

746751
if nargs is not None:
747-
nargs_adjusted: Union[int, str, tuple[int], tuple[int, int], tuple[int, float], None]
752+
nargs_adjusted: int | str | tuple[int] | tuple[int, int] | tuple[int, float] | None
748753
# Check if nargs was given as a range
749754
if isinstance(nargs, tuple):
750755
# Handle 1-item tuple by setting max to INFINITY
@@ -885,7 +890,7 @@ def _match_argument_wrapper(self: argparse.ArgumentParser, action: argparse.Acti
885890
ATTR_AP_COMPLETER_TYPE = 'ap_completer_type'
886891

887892

888-
def _ArgumentParser_get_ap_completer_type(self: argparse.ArgumentParser) -> Optional[type['ArgparseCompleter']]: # noqa: N802
893+
def _ArgumentParser_get_ap_completer_type(self: argparse.ArgumentParser) -> type[ArgparseCompleter] | None: # noqa: N802
889894
"""Get the ap_completer_type attribute of an argparse ArgumentParser.
890895
891896
This function is added by cmd2 as a method called ``get_ap_completer_type()`` to ``argparse.ArgumentParser`` class.
@@ -901,7 +906,7 @@ def _ArgumentParser_get_ap_completer_type(self: argparse.ArgumentParser) -> Opti
901906
setattr(argparse.ArgumentParser, 'get_ap_completer_type', _ArgumentParser_get_ap_completer_type)
902907

903908

904-
def _ArgumentParser_set_ap_completer_type(self: argparse.ArgumentParser, ap_completer_type: type['ArgparseCompleter']) -> None: # noqa: N802
909+
def _ArgumentParser_set_ap_completer_type(self: argparse.ArgumentParser, ap_completer_type: type[ArgparseCompleter]) -> None: # noqa: N802
905910
"""Set the ap_completer_type attribute of an argparse ArgumentParser.
906911
907912
This function is added by cmd2 as a method called ``set_ap_completer_type()`` to ``argparse.ArgumentParser`` class.
@@ -996,10 +1001,10 @@ class Cmd2HelpFormatter(argparse.RawTextHelpFormatter):
9961001

9971002
def _format_usage(
9981003
self,
999-
usage: Optional[str],
1004+
usage: str | None,
10001005
actions: Iterable[argparse.Action],
10011006
groups: Iterable[argparse._ArgumentGroup],
1002-
prefix: Optional[str] = None,
1007+
prefix: str | None = None,
10031008
) -> str:
10041009
if prefix is None:
10051010
prefix = gettext('Usage: ')
@@ -1053,7 +1058,7 @@ def _format_usage(
10531058
# End cmd2 customization
10541059

10551060
# helper for wrapping lines
1056-
def get_lines(parts: list[str], indent: str, prefix: Optional[str] = None) -> list[str]:
1061+
def get_lines(parts: list[str], indent: str, prefix: str | None = None) -> list[str]:
10571062
lines: list[str] = []
10581063
line: list[str] = []
10591064
line_len = len(prefix) - 1 if prefix is not None else len(indent) - 1
@@ -1133,8 +1138,8 @@ def _format_action_invocation(self, action: argparse.Action) -> str:
11331138
def _determine_metavar(
11341139
self,
11351140
action: argparse.Action,
1136-
default_metavar: Union[str, tuple[str, ...]],
1137-
) -> Union[str, tuple[str, ...]]:
1141+
default_metavar: str | tuple[str, ...],
1142+
) -> str | tuple[str, ...]:
11381143
"""Determine what to use as the metavar value of an action."""
11391144
if action.metavar is not None:
11401145
result = action.metavar
@@ -1150,7 +1155,7 @@ def _determine_metavar(
11501155
def _metavar_formatter(
11511156
self,
11521157
action: argparse.Action,
1153-
default_metavar: Union[str, tuple[str, ...]],
1158+
default_metavar: str | tuple[str, ...],
11541159
) -> Callable[[int], tuple[str, ...]]:
11551160
metavar = self._determine_metavar(action, default_metavar)
11561161

@@ -1161,7 +1166,7 @@ def format_tuple(tuple_size: int) -> tuple[str, ...]:
11611166

11621167
return format_tuple
11631168

1164-
def _format_args(self, action: argparse.Action, default_metavar: Union[str, tuple[str, ...]]) -> str:
1169+
def _format_args(self, action: argparse.Action, default_metavar: str | tuple[str, ...]) -> str:
11651170
"""Handle ranged nargs and make other output less verbose."""
11661171
metavar = self._determine_metavar(action, default_metavar)
11671172
metavar_formatter = self._metavar_formatter(action, default_metavar)
@@ -1191,23 +1196,23 @@ class Cmd2ArgumentParser(argparse.ArgumentParser):
11911196

11921197
def __init__(
11931198
self,
1194-
prog: Optional[str] = None,
1195-
usage: Optional[str] = None,
1196-
description: Optional[str] = None,
1197-
epilog: Optional[str] = None,
1199+
prog: str | None = None,
1200+
usage: str | None = None,
1201+
description: str | None = None,
1202+
epilog: str | None = None,
11981203
parents: Sequence[argparse.ArgumentParser] = (),
11991204
formatter_class: type[argparse.HelpFormatter] = Cmd2HelpFormatter,
12001205
prefix_chars: str = '-',
1201-
fromfile_prefix_chars: Optional[str] = None,
1202-
argument_default: Optional[str] = None,
1206+
fromfile_prefix_chars: str | None = None,
1207+
argument_default: str | None = None,
12031208
conflict_handler: str = 'error',
12041209
add_help: bool = True,
12051210
allow_abbrev: bool = True,
12061211
exit_on_error: bool = True,
12071212
suggest_on_error: bool = False,
12081213
color: bool = False,
12091214
*,
1210-
ap_completer_type: Optional[type['ArgparseCompleter']] = None,
1215+
ap_completer_type: type[ArgparseCompleter] | None = None,
12111216
) -> None:
12121217
"""Initialize the Cmd2ArgumentParser instance, a custom ArgumentParser added by cmd2.
12131218
@@ -1341,7 +1346,7 @@ def format_help(self) -> str:
13411346
# determine help from format above
13421347
return formatter.format_help() + '\n'
13431348

1344-
def _print_message(self, message: str, file: Optional[IO[str]] = None) -> None: # type: ignore[override]
1349+
def _print_message(self, message: str, file: IO[str] | None = None) -> None: # type: ignore[override]
13451350
# Override _print_message to use style_aware_write() since we use ANSI escape characters to support color
13461351
if message:
13471352
if file is None:

0 commit comments

Comments
 (0)