Skip to content

Commit

Permalink
Use type hinting generics in standard collections instead of importin…
Browse files Browse the repository at this point in the history
…g from typing (#1377)
  • Loading branch information
tleonhardt authored Nov 10, 2024
1 parent 410849c commit 57ffd7b
Show file tree
Hide file tree
Showing 32 changed files with 255 additions and 338 deletions.
4 changes: 1 addition & 3 deletions cmd2/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@
# package is not installed
pass

from typing import List

from . import plugin
from .ansi import (
Bg,
Expand Down Expand Up @@ -64,7 +62,7 @@
categorize,
)

__all__: List[str] = [
__all__: list[str] = [
'COMMAND_NAME',
'DEFAULT_SHORTCUTS',
# ANSI Exports
Expand Down
9 changes: 4 additions & 5 deletions cmd2/ansi.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
from typing import (
IO,
Any,
List,
Optional,
cast,
)
Expand Down Expand Up @@ -992,11 +991,11 @@ def style(
:raises: TypeError if bg isn't None or a subclass of BgColor
:return: the stylized string
"""
# List of strings that add style
additions: List[AnsiSequence] = []
# list of strings that add style
additions: list[AnsiSequence] = []

# List of strings that remove style
removals: List[AnsiSequence] = []
# list of strings that remove style
removals: list[AnsiSequence] = []

# Process the style settings
if fg is not None:
Expand Down
40 changes: 19 additions & 21 deletions cmd2/argparse_completer.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@
)
from typing import (
TYPE_CHECKING,
Dict,
List,
Optional,
Type,
Union,
Expand Down Expand Up @@ -172,7 +170,7 @@ class ArgparseCompleter:
"""Automatic command line tab completion based on argparse parameters"""

def __init__(
self, parser: argparse.ArgumentParser, cmd2_app: 'Cmd', *, parent_tokens: Optional[Dict[str, List[str]]] = None
self, parser: argparse.ArgumentParser, cmd2_app: 'Cmd', *, parent_tokens: Optional[dict[str, list[str]]] = None
) -> None:
"""
Create an ArgparseCompleter
Expand Down Expand Up @@ -213,8 +211,8 @@ def __init__(
self._subcommand_action = action

def complete(
self, text: str, line: str, begidx: int, endidx: int, tokens: List[str], *, cmd_set: Optional[CommandSet] = None
) -> List[str]:
self, text: str, line: str, begidx: int, endidx: int, tokens: list[str], *, cmd_set: Optional[CommandSet] = None
) -> list[str]:
"""
Complete text using argparse metadata
Expand Down Expand Up @@ -245,13 +243,13 @@ def complete(
flag_arg_state: Optional[_ArgumentState] = None

# Non-reusable flags that we've parsed
matched_flags: List[str] = []
matched_flags: list[str] = []

# Keeps track of arguments we've seen and any tokens they consumed
consumed_arg_values: Dict[str, List[str]] = dict() # dict(arg_name -> List[tokens])
consumed_arg_values: dict[str, list[str]] = dict() # dict(arg_name -> l[tokens])

# Completed mutually exclusive groups
completed_mutex_groups: Dict[argparse._MutuallyExclusiveGroup, argparse.Action] = dict()
completed_mutex_groups: dict[argparse._MutuallyExclusiveGroup, argparse.Action] = dict()

def consume_argument(arg_state: _ArgumentState) -> None:
"""Consuming token as an argument"""
Expand Down Expand Up @@ -507,7 +505,7 @@ def update_mutex_groups(arg_action: argparse.Action) -> None:

return completion_results

def _complete_flags(self, text: str, line: str, begidx: int, endidx: int, matched_flags: List[str]) -> List[str]:
def _complete_flags(self, text: str, line: str, begidx: int, endidx: int, matched_flags: list[str]) -> list[str]:
"""Tab completion routine for a parsers unused flags"""

# Build a list of flags that can be tab completed
Expand All @@ -524,7 +522,7 @@ def _complete_flags(self, text: str, line: str, begidx: int, endidx: int, matche
matches = self._cmd2_app.basic_complete(text, line, begidx, endidx, match_against)

# Build a dictionary linking actions with their matched flag names
matched_actions: Dict[argparse.Action, List[str]] = dict()
matched_actions: dict[argparse.Action, list[str]] = dict()
for flag in matches:
action = self._flag_to_action[flag]
matched_actions.setdefault(action, [])
Expand All @@ -541,14 +539,14 @@ def _complete_flags(self, text: str, line: str, begidx: int, endidx: int, matche

return matches

def _format_completions(self, arg_state: _ArgumentState, completions: Union[List[str], List[CompletionItem]]) -> List[str]:
def _format_completions(self, arg_state: _ArgumentState, completions: Union[list[str], list[CompletionItem]]) -> list[str]:
"""Format CompletionItems into hint table"""

# Nothing to do if we don't have at least 2 completions which are all CompletionItems
if len(completions) < 2 or not all(isinstance(c, CompletionItem) for c in completions):
return cast(List[str], completions)
return cast(list[str], completions)

completion_items = cast(List[CompletionItem], completions)
completion_items = cast(list[CompletionItem], completions)

# Check if the data being completed have a numerical type
all_nums = all(isinstance(c.orig_value, numbers.Number) for c in completion_items)
Expand Down Expand Up @@ -616,17 +614,17 @@ def _format_completions(self, arg_state: _ArgumentState, completions: Union[List
self._cmd2_app.formatted_completions = hint_table.generate_table(table_data, row_spacing=0)

# Return sorted list of completions
return cast(List[str], completions)
return cast(list[str], completions)

def complete_subcommand_help(self, text: str, line: str, begidx: int, endidx: int, tokens: List[str]) -> List[str]:
def complete_subcommand_help(self, text: str, line: str, begidx: int, endidx: int, tokens: list[str]) -> list[str]:
"""
Supports cmd2's help command in the completion of subcommand names
:param text: the string prefix we are attempting to match (all matches must begin with it)
:param line: the current input line with leading whitespace removed
:param begidx: the beginning index of the prefix text
:param endidx: the ending index of the prefix text
:param tokens: arguments passed to command/subcommand
:return: List of subcommand completions
:return: list of subcommand completions
"""
# If our parser has subcommands, we must examine the tokens and check if they are subcommands
# If so, we will let the subcommand's parser handle the rest of the tokens via another ArgparseCompleter.
Expand All @@ -645,7 +643,7 @@ def complete_subcommand_help(self, text: str, line: str, begidx: int, endidx: in
break
return []

def format_help(self, tokens: List[str]) -> str:
def format_help(self, tokens: list[str]) -> str:
"""
Supports cmd2's help command in the retrieval of help text
:param tokens: arguments passed to help command
Expand All @@ -672,17 +670,17 @@ def _complete_arg(
begidx: int,
endidx: int,
arg_state: _ArgumentState,
consumed_arg_values: Dict[str, List[str]],
consumed_arg_values: dict[str, list[str]],
*,
cmd_set: Optional[CommandSet] = None,
) -> List[str]:
) -> list[str]:
"""
Tab completion routine for an argparse argument
:return: list of completions
:raises: CompletionError if the completer or choices function this calls raises one
"""
# Check if the arg provides choices to the user
arg_choices: Union[List[str], ChoicesCallable]
arg_choices: Union[list[str], ChoicesCallable]
if arg_state.action.choices is not None:
arg_choices = list(arg_state.action.choices)
if not arg_choices:
Expand Down Expand Up @@ -739,7 +737,7 @@ def _complete_arg(
# Otherwise use basic_complete on the choices
else:
# Check if the choices come from a function
completion_items: List[str] = []
completion_items: list[str] = []
if isinstance(arg_choices, ChoicesCallable):
if not arg_choices.is_completer:
choices_func = arg_choices.choices_provider
Expand Down
48 changes: 22 additions & 26 deletions cmd2/argparse_custom.py
Original file line number Diff line number Diff line change
Expand Up @@ -250,15 +250,11 @@ def my_completer(self, text, line, begidx, endidx, arg_tokens)
TYPE_CHECKING,
Any,
Callable,
Dict,
Iterable,
List,
NoReturn,
Optional,
Protocol,
Sequence,
Set,
Tuple,
Type,
Union,
cast,
Expand Down Expand Up @@ -350,7 +346,7 @@ class ChoicesProviderFuncBase(Protocol):
Function that returns a list of choices in support of tab completion
"""

def __call__(self) -> List[str]: ... # pragma: no cover
def __call__(self) -> list[str]: ... # pragma: no cover


@runtime_checkable
Expand All @@ -359,7 +355,7 @@ class ChoicesProviderFuncWithTokens(Protocol):
Function that returns a list of choices in support of tab completion and accepts a dictionary of prior arguments.
"""

def __call__(self, *, arg_tokens: Dict[str, List[str]] = {}) -> List[str]: ... # pragma: no cover
def __call__(self, *, arg_tokens: dict[str, list[str]] = {}) -> list[str]: ... # pragma: no cover


ChoicesProviderFunc = Union[ChoicesProviderFuncBase, ChoicesProviderFuncWithTokens]
Expand All @@ -377,7 +373,7 @@ def __call__(
line: str,
begidx: int,
endidx: int,
) -> List[str]: ... # pragma: no cover
) -> list[str]: ... # pragma: no cover


@runtime_checkable
Expand All @@ -394,8 +390,8 @@ def __call__(
begidx: int,
endidx: int,
*,
arg_tokens: Dict[str, List[str]] = {},
) -> List[str]: ... # pragma: no cover
arg_tokens: dict[str, list[str]] = {},
) -> list[str]: ... # pragma: no cover


CompleterFunc = Union[CompleterFuncBase, CompleterFuncWithTokens]
Expand Down Expand Up @@ -598,7 +594,7 @@ def _action_set_descriptive_header(self: argparse.Action, descriptive_header: Op
############################################################################################################
# Patch argparse.Action with accessors for nargs_range attribute
############################################################################################################
def _action_get_nargs_range(self: argparse.Action) -> Optional[Tuple[int, Union[int, float]]]:
def _action_get_nargs_range(self: argparse.Action) -> Optional[tuple[int, Union[int, float]]]:
"""
Get the nargs_range attribute of an argparse Action.
Expand All @@ -609,13 +605,13 @@ def _action_get_nargs_range(self: argparse.Action) -> Optional[Tuple[int, Union[
:param self: argparse Action being queried
:return: The value of nargs_range or None if attribute does not exist
"""
return cast(Optional[Tuple[int, Union[int, float]]], getattr(self, ATTR_NARGS_RANGE, None))
return cast(Optional[tuple[int, Union[int, float]]], getattr(self, ATTR_NARGS_RANGE, None))


setattr(argparse.Action, 'get_nargs_range', _action_get_nargs_range)


def _action_set_nargs_range(self: argparse.Action, nargs_range: Optional[Tuple[int, Union[int, float]]]) -> None:
def _action_set_nargs_range(self: argparse.Action, nargs_range: Optional[tuple[int, Union[int, float]]]) -> None:
"""
Set the nargs_range attribute of an argparse Action.
Expand Down Expand Up @@ -673,7 +669,7 @@ def _action_set_suppress_tab_hint(self: argparse.Action, suppress_tab_hint: bool
# Allow developers to add custom action attributes
############################################################################################################

CUSTOM_ACTION_ATTRIBS: Set[str] = set()
CUSTOM_ACTION_ATTRIBS: set[str] = set()
_CUSTOM_ATTRIB_PFX = '_attr_'


Expand Down Expand Up @@ -746,7 +742,7 @@ def _action_set_custom_parameter(self: argparse.Action, value: Any) -> None:
def _add_argument_wrapper(
self: argparse._ActionsContainer,
*args: Any,
nargs: Union[int, str, Tuple[int], Tuple[int, int], Tuple[int, float], None] = None,
nargs: Union[int, str, tuple[int], tuple[int, int], tuple[int, float], None] = None,
choices_provider: Optional[ChoicesProviderFunc] = None,
completer: Optional[CompleterFunc] = None,
suppress_tab_hint: bool = False,
Expand Down Expand Up @@ -797,7 +793,7 @@ def _add_argument_wrapper(
nargs_range = None

if nargs is not None:
nargs_adjusted: Union[int, str, Tuple[int], Tuple[int, int], Tuple[int, float], None]
nargs_adjusted: Union[int, str, tuple[int], tuple[int, int], tuple[int, float], None]
# Check if nargs was given as a range
if isinstance(nargs, tuple):
# Handle 1-item tuple by setting max to INFINITY
Expand Down Expand Up @@ -847,7 +843,7 @@ def _add_argument_wrapper(
kwargs['nargs'] = nargs_adjusted

# Extract registered custom keyword arguments
custom_attribs: Dict[str, Any] = {}
custom_attribs: dict[str, Any] = {}
for keyword, value in kwargs.items():
if keyword in CUSTOM_ACTION_ATTRIBS:
custom_attribs[keyword] = value
Expand Down Expand Up @@ -1124,9 +1120,9 @@ def _format_usage(
# End cmd2 customization

# helper for wrapping lines
def get_lines(parts: List[str], indent: str, prefix: Optional[str] = None) -> List[str]:
lines: List[str] = []
line: List[str] = []
def get_lines(parts: list[str], indent: str, prefix: Optional[str] = None) -> list[str]:
lines: list[str] = []
line: list[str] = []
if prefix is not None:
line_len = len(prefix) - 1
else:
Expand Down Expand Up @@ -1188,7 +1184,7 @@ def _format_action_invocation(self, action: argparse.Action) -> str:
return metavar

else:
parts: List[str] = []
parts: list[str] = []

# if the Optional doesn't take a value, format is:
# -s, --long
Expand All @@ -1209,8 +1205,8 @@ def _format_action_invocation(self, action: argparse.Action) -> str:
def _determine_metavar(
self,
action: argparse.Action,
default_metavar: Union[str, Tuple[str, ...]],
) -> Union[str, Tuple[str, ...]]:
default_metavar: Union[str, tuple[str, ...]],
) -> Union[str, tuple[str, ...]]:
"""Custom method to determine what to use as the metavar value of an action"""
if action.metavar is not None:
result = action.metavar
Expand All @@ -1226,19 +1222,19 @@ def _determine_metavar(
def _metavar_formatter(
self,
action: argparse.Action,
default_metavar: Union[str, Tuple[str, ...]],
) -> Callable[[int], Tuple[str, ...]]:
default_metavar: Union[str, tuple[str, ...]],
) -> Callable[[int], tuple[str, ...]]:
metavar = self._determine_metavar(action, default_metavar)

def format(tuple_size: int) -> Tuple[str, ...]:
def format(tuple_size: int) -> tuple[str, ...]:
if isinstance(metavar, tuple):
return metavar
else:
return (metavar,) * tuple_size

return format

def _format_args(self, action: argparse.Action, default_metavar: Union[str, Tuple[str, ...]]) -> str:
def _format_args(self, action: argparse.Action, default_metavar: Union[str, tuple[str, ...]]) -> str:
"""Customized to handle ranged nargs and make other output less verbose"""
metavar = self._determine_metavar(action, default_metavar)
metavar_formatter = self._metavar_formatter(action, default_metavar)
Expand Down
Loading

0 comments on commit 57ffd7b

Please sign in to comment.