1818flag (``dry_run`` -> ``--dry-run``); pass an explicit ``Option("--my_flag")`` to opt out.
1919Positional-only parameters (before ``/``) and ``**kwargs`` raise ``TypeError``. The parameter
2020names ``dest`` and ``subcommand`` are reserved; ``cmd2_statement`` receives the parsed
21- ``Statement`` and (with ``base_command=True``) ``cmd2_handler `` receives the subcommand handler:
21+ ``Statement`` and (with ``base_command=True``) ``cmd2_subcommand_func `` receives the subcommand handler:
2222
2323 class MyApp(cmd2.Cmd):
2424 @cmd2.with_annotated
@@ -118,7 +118,7 @@ def do_paint(
118118692 ``**parser_kwargs: Unpack[Cmd2ParserKwargs]``. Anything the parser ctor accepts -- ``description``,
119119``epilog``, ``prog``, ``usage``, ``parents``, ``argument_default``, ``prefix_chars``,
120120``fromfile_prefix_chars``, ``conflict_handler``, ``add_help``, ``allow_abbrev``, ``exit_on_error``,
121- ``formatter_class``, ``ap_completer_type ``, and on Python >= 3.14 ``suggest_on_error`` / ``color`` --
121+ ``formatter_class``, ``completer_class ``, and on Python >= 3.14 ``suggest_on_error`` / ``color`` --
122122flows straight through; the [`Cmd2ParserKwargs`][cmd2.annotated.Cmd2ParserKwargs] ``TypedDict`` is the single source of truth
123123and gives type-checkers/IDEs autocomplete on the decorator's call site. ``parser_class`` stays as
124124its own explicit kwarg because it selects the class itself, not a value passed to it. Two
@@ -181,8 +181,16 @@ def do_paint(
181181import functools
182182import inspect
183183import types
184- from collections .abc import Callable , Container , Iterable , Sequence
185- from dataclasses import dataclass , field
184+ from collections .abc import (
185+ Callable ,
186+ Container ,
187+ Iterable ,
188+ Sequence ,
189+ )
190+ from dataclasses import (
191+ dataclass ,
192+ field ,
193+ )
186194from pathlib import Path
187195from typing import (
188196 TYPE_CHECKING ,
@@ -203,12 +211,20 @@ def do_paint(
203211from rich .table import Column
204212
205213from . import constants
206- from .argparse_utils import DEFAULT_ARGUMENT_PARSER , Cmd2ArgumentParser , SubcommandSpec
214+ from .argparse_utils import (
215+ ArgparseCommandSpec ,
216+ Cmd2ArgumentParser ,
217+ SubcommandSpec ,
218+ )
207219from .completion import CompletionItem
208220from .decorators import _parse_positionals
209221from .exceptions import Cmd2ArgparseError
210222from .rich_utils import Cmd2HelpFormatter , HelpContent
211- from .types import CmdOrSetT , UnboundChoicesProvider , UnboundCompleter
223+ from .types import (
224+ CmdOrSetT ,
225+ UnboundChoicesProvider ,
226+ UnboundCompleter ,
227+ )
212228
213229if TYPE_CHECKING :
214230 from .argparse_completer import ArgparseCompleter
@@ -240,7 +256,7 @@ class Cmd2ParserKwargs(TypedDict, total=False):
240256 exit_on_error : bool
241257 suggest_on_error : bool
242258 color : bool
243- ap_completer_type : "type[ArgparseCompleter] | None"
259+ completer_class : "type[ArgparseCompleter] | None"
244260
245261
246262# ---------------------------------------------------------------------------
@@ -1687,7 +1703,7 @@ def _const_mismatches_type(a: _ArgparseArgument) -> bool:
16871703
16881704# Parameters handled specially by the decorator and not added to the parser. The first positional
16891705# parameter (self/cls) is always skipped by position; these cover additional decorator-managed names.
1690- _SKIP_PARAMS = frozenset ({"cmd2_handler" , "cmd2_statement" })
1706+ _SKIP_PARAMS = frozenset ({constants . NS_ATTR_SUBCOMMAND_FUNC , constants . NS_ATTR_STATEMENT })
16911707
16921708
16931709def _link_group_membership (
@@ -1718,14 +1734,17 @@ def _resolve_parameters(
17181734 """Resolve a function signature into a list of argparse-argument builders.
17191735
17201736 ``base_command`` marks each argument's context for the base-command :data:`_CONSTRAINTS` rows and
1721- drives the function-level ``cmd2_handler `` check below. ``groups``/``mutually_exclusive_groups``
1737+ drives the function-level ``cmd2_subcommand_func `` check below. ``groups``/``mutually_exclusive_groups``
17221738 are linked onto each argument as membership facts for the cross-config constraint rows.
17231739 """
17241740 sig = inspect .signature (func )
17251741 # Function-level check (not a per-argument _CONSTRAINTS row): a base command dispatches through
1726- # cmd2_handler, so it must exist. Here so it also fires when the function has zero parameters.
1727- if base_command and "cmd2_handler" not in sig .parameters :
1728- raise TypeError (f"with_annotated(base_command=True) requires a 'cmd2_handler' parameter in { func .__qualname__ } " )
1742+ # cmd2_subcommand_func, so it must exist. Here so it also fires when the function has zero parameters.
1743+ if base_command and constants .NS_ATTR_SUBCOMMAND_FUNC not in sig .parameters :
1744+ raise TypeError (
1745+ f"with_annotated(base_command=True) requires a '{ constants .NS_ATTR_SUBCOMMAND_FUNC } ' "
1746+ f"parameter in { func .__qualname__ } "
1747+ )
17291748 try :
17301749 hints = get_type_hints (func , include_extras = True )
17311750 except (NameError , AttributeError , TypeError ) as exc :
@@ -1828,14 +1847,10 @@ def _filtered_namespace_kwargs(
18281847 exclude_subcommand : bool = False ,
18291848) -> dict [str , Any ]:
18301849 """Filter a parsed Namespace down to user-visible kwargs."""
1831- from .constants import NS_ATTR_SUBCMD_HANDLER
1832-
18331850 filtered : dict [str , Any ] = {}
18341851 for key , value in vars (ns ).items ():
18351852 if accepted is not None and key not in accepted :
18361853 continue
1837- if key == NS_ATTR_SUBCMD_HANDLER :
1838- continue
18391854 if exclude_subcommand and key == "subcommand" :
18401855 continue
18411856 filtered [key ] = value
@@ -1952,7 +1967,9 @@ def build_parser_from_function(
19521967 :param parser_kwargs: forwarded [`Cmd2ParserKwargs`][cmd2.annotated.Cmd2ParserKwargs]
19531968 :return: a fully configured ``Cmd2ArgumentParser``
19541969 """
1955- parser_cls = parser_class or DEFAULT_ARGUMENT_PARSER
1970+ from . import argparse_utils
1971+
1972+ parser_cls = parser_class or argparse_utils .DEFAULT_ARGUMENT_PARSER
19561973 if "description" not in parser_kwargs :
19571974 auto_description = _docstring_first_paragraph (func .__doc__ )
19581975 if auto_description is not None :
@@ -2105,10 +2122,10 @@ def _build_subcommand_handler(
21052122 def handler (self_arg : Any , ns : Any ) -> Any :
21062123 """Unpack Namespace into typed kwargs for the subcommand handler."""
21072124 filtered = _filtered_namespace_kwargs (ns , accepted = _accepted )
2108- if "cmd2_handler" in filtered :
2109- cmd2_h = filtered ["cmd2_handler" ]
2125+ if constants . NS_ATTR_SUBCOMMAND_FUNC in filtered :
2126+ cmd2_h = filtered [constants . NS_ATTR_SUBCOMMAND_FUNC ]
21102127 if isinstance (cmd2_h , functools .partial ) and cmd2_h .func is handler :
2111- filtered ["cmd2_handler" ] = None
2128+ filtered [constants . NS_ATTR_SUBCOMMAND_FUNC ] = None
21122129 return _invoke_command_func (
21132130 func , self_arg , filtered , leading_names = _leading_names , var_positional_name = _var_positional_name
21142131 )
@@ -2170,7 +2187,7 @@ def with_annotated(
21702187 :param ns_provider: callable returning a prepopulated Namespace (not with ``subcommand_to``)
21712188 :param preserve_quotes: preserve quotes in arguments (not with ``subcommand_to``)
21722189 :param with_unknown_args: capture unknown args as the ``_unknown`` kwarg (not with ``subcommand_to``)
2173- :param base_command: add ``add_subparsers()``; requires a ``cmd2_handler `` param and no positionals
2190+ :param base_command: add ``add_subparsers()``; requires a ``cmd2_subcommand_func `` param and no positionals
21742191 :param subcommand_to: parent command name; function must be named ``{parent_underscored}_{subcommand}``
21752192 :param help: subcommand help text (only with ``subcommand_to``)
21762193 :param aliases: alternative subcommand names (only with ``subcommand_to``)
@@ -2232,9 +2249,10 @@ def decorator(fn: Callable[..., Any]) -> Callable[..., Any]:
22322249 if unknown_param .kind is inspect .Parameter .POSITIONAL_ONLY :
22332250 raise TypeError ("Parameter _unknown must be keyword-compatible when with_unknown_args=True" )
22342251
2235- if not base_command and "cmd2_handler" in inspect .signature (fn ).parameters :
2252+ if not base_command and constants . NS_ATTR_SUBCOMMAND_FUNC in inspect .signature (fn ).parameters :
22362253 raise TypeError (
2237- f"Parameter 'cmd2_handler' in { fn .__qualname__ } is only valid when with_annotated(base_command=True) is used."
2254+ f"Parameter '{ constants .NS_ATTR_SUBCOMMAND_FUNC } ' in { fn .__qualname__ } "
2255+ "is only valid when with_annotated(base_command=True) is used."
22382256 )
22392257
22402258 if subcommand_to is not None :
@@ -2244,15 +2262,15 @@ def decorator(fn: Callable[..., Any]) -> Callable[..., Any]:
22442262 base_command = base_command ,
22452263 options = options ,
22462264 )
2247- spec = SubcommandSpec (
2265+ subcommand_spec = SubcommandSpec (
22482266 name = subcmd_name ,
22492267 command = subcommand_to ,
22502268 help = help ,
22512269 aliases = tuple (aliases ),
22522270 deprecated = deprecated ,
22532271 parser_source = subcmd_parser_builder ,
22542272 )
2255- setattr (handler , constants .SUBCMD_ATTR_SPEC , spec )
2273+ setattr (handler , constants .SUBCOMMAND_ATTR_SPEC , subcommand_spec )
22562274 return handler
22572275
22582276 command_name = fn .__name__ [len (constants .COMMAND_FUNC_PREFIX ) :]
@@ -2296,10 +2314,10 @@ def cmd_wrapper(*args: Any, **kwargs: Any) -> bool | None:
22962314 raise Cmd2ArgparseError from exc
22972315
22982316 setattr (ns , constants .NS_ATTR_STATEMENT , statement )
2299- handler = getattr (ns , constants .NS_ATTR_SUBCMD_HANDLER , None )
2317+ handler = getattr (ns , constants .NS_ATTR_SUBCOMMAND_FUNC , None )
23002318 if base_command and handler is not None :
23012319 handler = functools .partial (handler , ns )
2302- ns . cmd2_handler = handler
2320+ setattr ( ns , constants . NS_ATTR_SUBCOMMAND_FUNC , handler )
23032321
23042322 func_kwargs = _filtered_namespace_kwargs (ns , accepted = accepted , exclude_subcommand = base_command )
23052323
@@ -2312,8 +2330,11 @@ def cmd_wrapper(*args: Any, **kwargs: Any) -> bool | None:
23122330 )
23132331 return result
23142332
2315- setattr (cmd_wrapper , constants .CMD_ATTR_PARSER_SOURCE , parser_builder )
2316- setattr (cmd_wrapper , constants .CMD_ATTR_PRESERVE_QUOTES , preserve_quotes )
2333+ argparse_command_spec = ArgparseCommandSpec (
2334+ parser_source = parser_builder ,
2335+ preserve_quotes = preserve_quotes ,
2336+ )
2337+ setattr (cmd_wrapper , constants .ARGPARSE_COMMAND_ATTR_SPEC , argparse_command_spec )
23172338
23182339 return cmd_wrapper
23192340
0 commit comments