Skip to content

Commit 403210a

Browse files
committed
Moved _check_value() override to Cmd2ArgumentParser.
Removed set_ap_completer_type() and get_ap_completer_type() since ap_completer_type is now a public member of Cmd2ArgumentParser.
1 parent 52f6a3d commit 403210a

4 files changed

Lines changed: 33 additions & 87 deletions

File tree

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,8 @@ prompt is displayed.
6666
- Removed `Cmd.ruler` since `cmd2` no longer uses it.
6767
- All parsers used with `cmd2` commands much be an instance of `Cmd2ArgumentParser` or a child
6868
class of it.
69+
- Removed `set_ap_completer_type()` and `get_ap_completer_type()` since `ap_completer_type` is
70+
now a public member of `Cmd2ArgumentParser`.
6971
- Enhancements
7072
- New `cmd2.Cmd` parameters
7173
- **auto_suggest**: (boolean) if `True`, provide fish shell style auto-suggestions. These

cmd2/argparse_custom.py

Lines changed: 22 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -229,11 +229,6 @@ def get_choices(self) -> Choices:
229229
- ``argparse.Action.get_suppress_tab_hint()`` - See ``_action_get_suppress_tab_hint`` for more details.
230230
- ``argparse.Action.set_suppress_tab_hint()`` - See ``_action_set_suppress_tab_hint`` for more details.
231231
232-
cmd2 has patched ``argparse.ArgumentParser`` to include the following accessor methods
233-
234-
- ``argparse.ArgumentParser.get_ap_completer_type()`` - See ``_ArgumentParser_get_ap_completer_type`` for more details.
235-
- ``argparse.Action.set_ap_completer_type()`` - See ``_ArgumentParser_set_ap_completer_type`` for more details.
236-
237232
**Subcommand Manipulation**
238233
239234
cmd2 has patched ``argparse._SubParsersAction`` with new functions to better facilitate the
@@ -810,76 +805,6 @@ def _add_argument_wrapper(
810805
setattr(argparse._ActionsContainer, 'add_argument', _add_argument_wrapper)
811806

812807

813-
############################################################################################################
814-
# Patch argparse.ArgumentParser with accessors for ap_completer_type attribute
815-
############################################################################################################
816-
817-
# An ArgumentParser attribute which specifies a subclass of ArgparseCompleter for custom completion behavior on a
818-
# given parser. If this is None or not present, then cmd2 will use argparse_completer.DEFAULT_AP_COMPLETER when tab
819-
# completing a parser's arguments
820-
ATTR_AP_COMPLETER_TYPE = 'ap_completer_type'
821-
822-
823-
def _ArgumentParser_get_ap_completer_type(self: argparse.ArgumentParser) -> type['ArgparseCompleter'] | None: # noqa: N802
824-
"""Get the ap_completer_type attribute of an argparse ArgumentParser.
825-
826-
This function is added by cmd2 as a method called ``get_ap_completer_type()`` to ``argparse.ArgumentParser`` class.
827-
828-
To call: ``parser.get_ap_completer_type()``
829-
830-
:param self: ArgumentParser being queried
831-
:return: An ArgparseCompleter-based class or None if attribute does not exist
832-
"""
833-
return cast(type['ArgparseCompleter'] | None, getattr(self, ATTR_AP_COMPLETER_TYPE, None))
834-
835-
836-
setattr(argparse.ArgumentParser, 'get_ap_completer_type', _ArgumentParser_get_ap_completer_type)
837-
838-
839-
def _ArgumentParser_set_ap_completer_type(self: argparse.ArgumentParser, ap_completer_type: type['ArgparseCompleter']) -> None: # noqa: N802
840-
"""Set the ap_completer_type attribute of an argparse ArgumentParser.
841-
842-
This function is added by cmd2 as a method called ``set_ap_completer_type()`` to ``argparse.ArgumentParser`` class.
843-
844-
To call: ``parser.set_ap_completer_type(ap_completer_type)``
845-
846-
:param self: ArgumentParser being edited
847-
:param ap_completer_type: the custom ArgparseCompleter-based class to use when completing arguments for this parser
848-
"""
849-
setattr(self, ATTR_AP_COMPLETER_TYPE, ap_completer_type)
850-
851-
852-
setattr(argparse.ArgumentParser, 'set_ap_completer_type', _ArgumentParser_set_ap_completer_type)
853-
854-
855-
############################################################################################################
856-
# Patch ArgumentParser._check_value to support CompletionItems as choices
857-
############################################################################################################
858-
def _ArgumentParser_check_value(_self: argparse.ArgumentParser, action: argparse.Action, value: Any) -> None: # noqa: N802
859-
"""Check_value that supports CompletionItems as choices (Custom override of ArgumentParser._check_value).
860-
861-
When displaying choices, use CompletionItem.value instead of the CompletionItem instance.
862-
863-
:param self: ArgumentParser instance
864-
:param action: the action being populated
865-
:param value: value from command line already run through conversion function by argparse
866-
"""
867-
# Import gettext like argparse does
868-
from gettext import (
869-
gettext as _,
870-
)
871-
872-
if action.choices is not None and value not in action.choices:
873-
# If any choice is a CompletionItem, then display its value property.
874-
choices = [c.value if isinstance(c, CompletionItem) else c for c in action.choices]
875-
args = {'value': value, 'choices': ', '.join(map(repr, choices))}
876-
msg = _('invalid choice: %(value)r (choose from %(choices)s)')
877-
raise ArgumentError(action, msg % args)
878-
879-
880-
setattr(argparse.ArgumentParser, '_check_value', _ArgumentParser_check_value)
881-
882-
883808
############################################################################################################
884809
# Patch argparse._SubParsersAction to add attach_parser function
885810
############################################################################################################
@@ -1221,7 +1146,7 @@ def __init__(
12211146
self.description: RenderableType | None # type: ignore[assignment]
12221147
self.epilog: RenderableType | None # type: ignore[assignment]
12231148

1224-
self.set_ap_completer_type(ap_completer_type) # type: ignore[attr-defined]
1149+
self.ap_completer_type = ap_completer_type
12251150

12261151
def add_subparsers(self, **kwargs: Any) -> argparse._SubParsersAction: # type: ignore[type-arg]
12271152
"""Add a subcommand parser.
@@ -1296,6 +1221,27 @@ def _match_argument(self, action: argparse.Action, arg_strings_pattern: str) ->
12961221

12971222
return super()._match_argument(action, arg_strings_pattern)
12981223

1224+
def _check_value(self, action: argparse.Action, value: Any) -> None:
1225+
"""Override that supports CompletionItems as choices.
1226+
1227+
When displaying choices, use CompletionItem.value instead of the CompletionItem instance.
1228+
1229+
:param self: ArgumentParser instance
1230+
:param action: the action being populated
1231+
:param value: value from command line already run through conversion function by argparse
1232+
"""
1233+
# Import gettext like argparse does
1234+
from gettext import (
1235+
gettext as _,
1236+
)
1237+
1238+
if action.choices is not None and value not in action.choices:
1239+
# If any choice is a CompletionItem, then display its value property.
1240+
choices = [c.value if isinstance(c, CompletionItem) else c for c in action.choices]
1241+
args = {'value': value, 'choices': ', '.join(map(repr, choices))}
1242+
msg = _('invalid choice: %(value)r (choose from %(choices)s)')
1243+
raise ArgumentError(action, msg % args)
1244+
12991245

13001246
class Cmd2AttributeWrapper:
13011247
"""Wraps a cmd2-specific attribute added to an argparse Namespace.

cmd2/cmd2.py

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,6 @@
6262
TYPE_CHECKING,
6363
Any,
6464
TextIO,
65-
TypeAlias,
6665
TypeVar,
6766
Union,
6867
cast,
@@ -2351,12 +2350,9 @@ def _determine_ap_completer_type(parser: Cmd2ArgumentParser) -> type[argparse_co
23512350
:param parser: the parser to examine
23522351
:return: type of ArgparseCompleter
23532352
"""
2354-
APCompleterType: TypeAlias = type[argparse_completer.ArgparseCompleter] | None
2355-
completer_type: APCompleterType = parser.get_ap_completer_type() # type: ignore[attr-defined]
2356-
2357-
if completer_type is None:
2358-
completer_type = argparse_completer.DEFAULT_AP_COMPLETER
2359-
return completer_type
2353+
if parser.ap_completer_type is None:
2354+
return argparse_completer.DEFAULT_AP_COMPLETER
2355+
return parser.ap_completer_type
23602356

23612357
def _perform_completion(
23622358
self, text: str, line: str, begidx: int, endidx: int, custom_settings: utils.CustomCompletionSettings | None = None

tests/test_argparse_completer.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1421,8 +1421,10 @@ def test_add_parser_custom_completer() -> None:
14211421
parser = Cmd2ArgumentParser()
14221422
subparsers = parser.add_subparsers()
14231423

1424-
no_custom_completer_parser = subparsers.add_parser(name="no_custom_completer")
1425-
assert no_custom_completer_parser.get_ap_completer_type() is None # type: ignore[attr-defined]
1424+
no_custom_completer_parser: Cmd2ArgumentParser = subparsers.add_parser(name="no_custom_completer")
1425+
assert no_custom_completer_parser.ap_completer_type is None
14261426

1427-
custom_completer_parser = subparsers.add_parser(name="custom_completer", ap_completer_type=CustomCompleter)
1428-
assert custom_completer_parser.get_ap_completer_type() is CustomCompleter # type: ignore[attr-defined]
1427+
custom_completer_parser: Cmd2ArgumentParser = subparsers.add_parser(
1428+
name="custom_completer", ap_completer_type=CustomCompleter
1429+
)
1430+
assert custom_completer_parser.ap_completer_type is CustomCompleter

0 commit comments

Comments
 (0)