Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ cmd2/py_bridge.py @kmvanbrunt
cmd2/rich_utils.py @kmvanbrunt
cmd2/string_utils.py @kmvanbrunt
cmd2/styles.py @tleonhardt @kmvanbrunt
cmd2/types.py @tleonhardt @kmvanbrunt
cmd2/utils.py @tleonhardt @kmvanbrunt

# Documentation
Expand Down
27 changes: 14 additions & 13 deletions cmd2/argparse_custom.py
Original file line number Diff line number Diff line change
Expand Up @@ -294,13 +294,14 @@ def get_choices(self) -> Choices:

from . import constants
from . import rich_utils as ru
from .completion import (
from .completion import CompletionItem
from .rich_utils import Cmd2RichArgparseConsole
from .styles import Cmd2Style
from .types import (
ChoicesProviderUnbound,
CmdOrSet,
CompleterUnbound,
CompletionItem,
)
from .rich_utils import Cmd2RichArgparseConsole
from .styles import Cmd2Style

if TYPE_CHECKING: # pragma: no cover
from .argparse_completer import ArgparseCompleter
Expand Down Expand Up @@ -384,7 +385,7 @@ class ChoicesCallable:
def __init__(
self,
is_completer: bool,
to_call: ChoicesProviderUnbound | CompleterUnbound,
to_call: ChoicesProviderUnbound[CmdOrSet] | CompleterUnbound[CmdOrSet],
) -> None:
"""Initialize the ChoiceCallable instance.

Expand All @@ -396,18 +397,18 @@ def __init__(
self.to_call = to_call

@property
def choices_provider(self) -> ChoicesProviderUnbound:
def choices_provider(self) -> ChoicesProviderUnbound[CmdOrSet]:
"""Retreive the internal choices_provider function."""
if self.is_completer:
raise AttributeError("This instance is configured as a completer, not a choices_provider")
return cast(ChoicesProviderUnbound, self.to_call)
return cast(ChoicesProviderUnbound[CmdOrSet], self.to_call)

@property
def completer(self) -> CompleterUnbound:
def completer(self) -> CompleterUnbound[CmdOrSet]:
"""Retreive the internal completer function."""
if not self.is_completer:
raise AttributeError("This instance is configured as a choices_provider, not a completer")
return cast(CompleterUnbound, self.to_call)
return cast(CompleterUnbound[CmdOrSet], self.to_call)


############################################################################################################
Expand Down Expand Up @@ -476,7 +477,7 @@ def _action_set_choices_callable(self: argparse.Action, choices_callable: Choice

def _action_set_choices_provider(
self: argparse.Action,
choices_provider: ChoicesProviderUnbound,
choices_provider: ChoicesProviderUnbound[CmdOrSet],
) -> None:
"""Set choices_provider of an argparse Action.

Expand All @@ -496,7 +497,7 @@ def _action_set_choices_provider(

def _action_set_completer(
self: argparse.Action,
completer: CompleterUnbound,
completer: CompleterUnbound[CmdOrSet],
) -> None:
"""Set completer of an argparse Action.

Expand Down Expand Up @@ -694,8 +695,8 @@ def _add_argument_wrapper(
self: argparse._ActionsContainer,
*args: Any,
nargs: int | str | tuple[int] | tuple[int, int] | tuple[int, float] | None = None,
choices_provider: ChoicesProviderUnbound | None = None,
completer: CompleterUnbound | None = None,
choices_provider: ChoicesProviderUnbound[CmdOrSet] | None = None,
completer: CompleterUnbound[CmdOrSet] | None = None,
suppress_tab_hint: bool = False,
table_header: Sequence[str | Column] | None = None,
**kwargs: Any,
Expand Down
24 changes: 13 additions & 11 deletions cmd2/cmd2.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,12 +107,8 @@
)
from .completion import (
Choices,
ChoicesProviderUnbound,
CompleterBound,
CompleterUnbound,
CompletionItem,
Completions,
Matchable,
)
from .constants import (
CLASS_ATTR_DEFAULT_HELP_CATEGORY,
Expand All @@ -121,7 +117,6 @@
HELP_FUNC_PREFIX,
)
from .decorators import (
CommandParent,
as_subcommand_to,
with_argparser,
)
Expand Down Expand Up @@ -152,6 +147,13 @@
RichPrintKwargs,
)
from .styles import Cmd2Style
from .types import (
ChoicesProviderUnbound,
CmdOrSet,
CompleterBound,
CompleterUnbound,
Matchable,
)

with contextlib.suppress(ImportError):
from IPython import start_ipython
Expand Down Expand Up @@ -840,7 +842,7 @@ def register_command_set(self, cmdset: CommandSet) -> None:

def _build_parser(
self,
parent: CommandParent,
parent: CmdOrSet,
parser_builder: argparse.ArgumentParser
| Callable[[], argparse.ArgumentParser]
| StaticArgParseBuilder
Expand All @@ -849,7 +851,7 @@ def _build_parser(
) -> argparse.ArgumentParser:
"""Build argument parser for a command/subcommand.

:param parent: CommandParent object which owns the command using the parser.
:param parent: object which owns the command using the parser.
When parser_builder is a classmethod, this function passes
parent's class to it.
:param parser_builder: means used to build the parser
Expand Down Expand Up @@ -3283,8 +3285,8 @@ def _resolve_completer(
self,
preserve_quotes: bool = False,
choices: Iterable[Any] | None = None,
choices_provider: ChoicesProviderUnbound | None = None,
completer: CompleterUnbound | None = None,
choices_provider: ChoicesProviderUnbound[CmdOrSet] | None = None,
completer: CompleterUnbound[CmdOrSet] | None = None,
parser: argparse.ArgumentParser | None = None,
) -> Completer:
"""Determine the appropriate completer based on provided arguments."""
Expand Down Expand Up @@ -3315,8 +3317,8 @@ def read_input(
history: Sequence[str] | None = None,
preserve_quotes: bool = False,
choices: Iterable[Any] | None = None,
choices_provider: ChoicesProviderUnbound | None = None,
completer: CompleterUnbound | None = None,
choices_provider: ChoicesProviderUnbound[CmdOrSet] | None = None,
completer: CompleterUnbound[CmdOrSet] | None = None,
parser: argparse.ArgumentParser | None = None,
) -> str:
"""Read a line of input with optional completion and history.
Expand Down
8 changes: 4 additions & 4 deletions cmd2/command_definition.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
from .utils import Settable

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

#: Callable signature for a basic command function
#: Further refinements are needed to define the input parameters
Expand Down Expand Up @@ -92,13 +92,13 @@ def __init__(self) -> None:
This will be set when the CommandSet is registered and it should be
accessed by child classes using the self._cmd property.
"""
self.__cmd_internal: cmd2.Cmd | None = None
self.__cmd_internal: Cmd | None = None

self._settables: dict[str, Settable] = {}
self._settable_prefix = self.__class__.__name__

@property
def _cmd(self) -> 'cmd2.Cmd':
def _cmd(self) -> 'Cmd':
"""Property for child classes to access self.__cmd_internal.

Using this property ensures that self.__cmd_internal has been set
Expand All @@ -122,7 +122,7 @@ def _cmd(self) -> CustomCmdApp:
raise CommandSetRegistrationError('This CommandSet is not registered')
return self.__cmd_internal

def on_register(self, cmd: 'cmd2.Cmd') -> None:
def on_register(self, cmd: 'Cmd') -> None:
"""First step to registering a CommandSet, called by cmd2.Cmd.

The commands defined in this class have not been added to the CLI object at this point.
Expand Down
54 changes: 0 additions & 54 deletions cmd2/completion.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,31 +3,23 @@
import re
import sys
from collections.abc import (
Callable,
Collection,
Iterable,
Iterator,
Mapping,
Sequence,
)
from dataclasses import (
dataclass,
field,
)
from typing import (
TYPE_CHECKING,
Any,
TypeAlias,
cast,
overload,
)

from . import string_utils as su

if TYPE_CHECKING: # pragma: no cover
from .cmd2 import Cmd
from .command_definition import CommandSet

if sys.version_info >= (3, 11):
from typing import Self
else:
Expand Down Expand Up @@ -264,49 +256,3 @@ class Completions(CompletionResultsBase):
def all_display_numeric(items: Collection[CompletionItem]) -> bool:
"""Return True if items is non-empty and every item.display_plain value is a numeric string."""
return bool(items) and all(NUMERIC_RE.match(item.display_plain) for item in items)


#############################################
# choices_provider function types
#############################################

# Represents the parsed tokens from argparse during completion
ArgTokens: TypeAlias = Mapping[str, Sequence[str]]

# Unbound choices_provider function types used by argparse-based completion.
# These expect a Cmd or CommandSet instance as the first argument.
ChoicesProviderUnbound: TypeAlias = (
# Basic: (self) -> Choices
Callable[["Cmd"], Choices]
| Callable[["CommandSet"], Choices]
|
# Context-aware: (self, arg_tokens) -> Choices
Callable[["Cmd", ArgTokens], Choices]
| Callable[["CommandSet", ArgTokens], Choices]
)

#############################################
# completer function types
#############################################

# Unbound completer function types used by argparse-based completion.
# These expect a Cmd or CommandSet instance as the first argument.
CompleterUnbound: TypeAlias = (
# Basic: (self, text, line, begidx, endidx) -> Completions
Callable[["Cmd", str, str, int, int], Completions]
| Callable[["CommandSet", str, str, int, int], Completions]
|
# Context-aware: (self, text, line, begidx, endidx, arg_tokens) -> Completions
Callable[["Cmd", str, str, int, int, ArgTokens], Completions]
| Callable[["CommandSet", str, str, int, int, ArgTokens], Completions]
)

# A bound completer used internally by cmd2 for basic completion logic.
# The 'self' argument is already tied to an instance and is omitted.
# Format: (text, line, begidx, endidx) -> Completions
CompleterBound: TypeAlias = Callable[[str, str, int, int], Completions]

# Represents a type that can be matched against when completing.
# Strings are matched directly while CompletionItems are matched
# against their 'text' member.
Matchable: TypeAlias = str | CompletionItem
Loading
Loading