Skip to content

Commit 1b99078

Browse files
committed
Renamed cmd2_handler to cmd2_subcommand_handler in annotated functions.
This is to match what it's called in the Namespace when using with_argparser.
1 parent 88f2e39 commit 1b99078

5 files changed

Lines changed: 68 additions & 96 deletions

File tree

cmd2/annotated.py

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
flag (``dry_run`` -> ``--dry-run``); pass an explicit ``Option("--my_flag")`` to opt out.
1919
Positional-only parameters (before ``/``) and ``**kwargs`` raise ``TypeError``. The parameter
2020
names ``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
@@ -1704,7 +1704,7 @@ def _const_mismatches_type(a: _ArgparseArgument) -> bool:
17041704

17051705
# Parameters handled specially by the decorator and not added to the parser. The first positional
17061706
# parameter (self/cls) is always skipped by position; these cover additional decorator-managed names.
1707-
_SKIP_PARAMS = frozenset({"cmd2_handler", "cmd2_statement"})
1707+
_SKIP_PARAMS = frozenset({constants.NS_ATTR_SUBCOMMAND_FUNC, constants.NS_ATTR_STATEMENT})
17081708

17091709

17101710
def _link_group_membership(
@@ -1735,14 +1735,17 @@ def _resolve_parameters(
17351735
"""Resolve a function signature into a list of argparse-argument builders.
17361736
17371737
``base_command`` marks each argument's context for the base-command :data:`_CONSTRAINTS` rows and
1738-
drives the function-level ``cmd2_handler`` check below. ``groups``/``mutually_exclusive_groups``
1738+
drives the function-level ``cmd2_subcommand_func`` check below. ``groups``/``mutually_exclusive_groups``
17391739
are linked onto each argument as membership facts for the cross-config constraint rows.
17401740
"""
17411741
sig = inspect.signature(func)
17421742
# Function-level check (not a per-argument _CONSTRAINTS row): a base command dispatches through
1743-
# cmd2_handler, so it must exist. Here so it also fires when the function has zero parameters.
1744-
if base_command and "cmd2_handler" not in sig.parameters:
1745-
raise TypeError(f"with_annotated(base_command=True) requires a 'cmd2_handler' parameter in {func.__qualname__}")
1743+
# cmd2_subcommand_func, so it must exist. Here so it also fires when the function has zero parameters.
1744+
if base_command and constants.NS_ATTR_SUBCOMMAND_FUNC not in sig.parameters:
1745+
raise TypeError(
1746+
f"with_annotated(base_command=True) requires a '{constants.NS_ATTR_SUBCOMMAND_FUNC}' "
1747+
f"parameter in {func.__qualname__}"
1748+
)
17461749
try:
17471750
hints = get_type_hints(func, include_extras=True)
17481751
except (NameError, AttributeError, TypeError) as exc:
@@ -1849,8 +1852,6 @@ def _filtered_namespace_kwargs(
18491852
for key, value in vars(ns).items():
18501853
if accepted is not None and key not in accepted:
18511854
continue
1852-
if key == constants.NS_ATTR_SUBCOMMAND_FUNC:
1853-
continue
18541855
if exclude_subcommand and key == "subcommand":
18551856
continue
18561857
filtered[key] = value
@@ -2120,10 +2121,10 @@ def _build_subcommand_handler(
21202121
def handler(self_arg: Any, ns: Any) -> Any:
21212122
"""Unpack Namespace into typed kwargs for the subcommand handler."""
21222123
filtered = _filtered_namespace_kwargs(ns, accepted=_accepted)
2123-
if "cmd2_handler" in filtered:
2124-
cmd2_h = filtered["cmd2_handler"]
2124+
if constants.NS_ATTR_SUBCOMMAND_FUNC in filtered:
2125+
cmd2_h = filtered[constants.NS_ATTR_SUBCOMMAND_FUNC]
21252126
if isinstance(cmd2_h, functools.partial) and cmd2_h.func is handler:
2126-
filtered["cmd2_handler"] = None
2127+
filtered[constants.NS_ATTR_SUBCOMMAND_FUNC] = None
21272128
return _invoke_command_func(
21282129
func, self_arg, filtered, leading_names=_leading_names, var_positional_name=_var_positional_name
21292130
)
@@ -2185,7 +2186,7 @@ def with_annotated(
21852186
:param ns_provider: callable returning a prepopulated Namespace (not with ``subcommand_to``)
21862187
:param preserve_quotes: preserve quotes in arguments (not with ``subcommand_to``)
21872188
:param with_unknown_args: capture unknown args as the ``_unknown`` kwarg (not with ``subcommand_to``)
2188-
:param base_command: add ``add_subparsers()``; requires a ``cmd2_handler`` param and no positionals
2189+
:param base_command: add ``add_subparsers()``; requires a ``cmd2_subcommand_func`` param and no positionals
21892190
:param subcommand_to: parent command name; function must be named ``{parent_underscored}_{subcommand}``
21902191
:param help: subcommand help text (only with ``subcommand_to``)
21912192
:param aliases: alternative subcommand names (only with ``subcommand_to``)
@@ -2247,9 +2248,10 @@ def decorator(fn: Callable[..., Any]) -> Callable[..., Any]:
22472248
if unknown_param.kind is inspect.Parameter.POSITIONAL_ONLY:
22482249
raise TypeError("Parameter _unknown must be keyword-compatible when with_unknown_args=True")
22492250

2250-
if not base_command and "cmd2_handler" in inspect.signature(fn).parameters:
2251+
if not base_command and constants.NS_ATTR_SUBCOMMAND_FUNC in inspect.signature(fn).parameters:
22512252
raise TypeError(
2252-
f"Parameter 'cmd2_handler' in {fn.__qualname__} is only valid when with_annotated(base_command=True) is used."
2253+
f"Parameter '{constants.NS_ATTR_SUBCOMMAND_FUNC}' in {fn.__qualname__} "
2254+
"is only valid when with_annotated(base_command=True) is used."
22532255
)
22542256

22552257
if subcommand_to is not None:
@@ -2314,7 +2316,7 @@ def cmd_wrapper(*args: Any, **kwargs: Any) -> bool | None:
23142316
handler = getattr(ns, constants.NS_ATTR_SUBCOMMAND_FUNC, None)
23152317
if base_command and handler is not None:
23162318
handler = functools.partial(handler, ns)
2317-
ns.cmd2_handler = handler
2319+
setattr(ns, constants.NS_ATTR_SUBCOMMAND_FUNC, handler)
23182320

23192321
func_kwargs = _filtered_namespace_kwargs(ns, accepted=accepted, exclude_subcommand=base_command)
23202322

docs/features/annotated.md

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -116,8 +116,9 @@ Unsupported patterns raise `TypeError`, including:
116116
by the tuple. The tuple type already pins `nargs`; user metadata cannot change it.
117117

118118
The parameter names `dest` and `subcommand` are reserved and may not be used as annotated parameter
119-
names. `cmd2_statement` receives the parsed [cmd2.Statement][] object, and `cmd2_handler` (only on a
120-
command decorated with `@with_annotated(base_command=True)`) receives the subcommand handler.
119+
names. `cmd2_statement` receives the parsed [cmd2.Statement][] object, and `cmd2_subcommand_func`
120+
(only on a command decorated with `@with_annotated(base_command=True)`) receives the subcommand
121+
handler.
121122

122123
## Annotated metadata
123124

@@ -269,8 +270,8 @@ list the values.
269270
- `with_unknown_args` -- if `True`, unrecognised arguments are passed as `_unknown`
270271
- `subcommand_to` -- register the function as an annotated subcommand under a parent command
271272
- `base_command` -- create a base command whose parser also adds subparsers and exposes
272-
`cmd2_handler`. A `cmd2_handler` parameter is only valid on a command decorated with
273-
`base_command=True`; declaring one elsewhere raises `TypeError`.
273+
`cmd2_subcommand_func`. A `cmd2_subcommand_func` parameter is only valid on a command decorated
274+
with `base_command=True`; declaring one elsewhere raises `TypeError`.
274275
- `subcommand_required` -- whether a subcommand must be supplied (only with `base_command=True`,
275276
default `True`)
276277
- `subcommand_metavar` -- metavar shown for the subcommands group (only with `base_command=True`,
@@ -392,10 +393,9 @@ The remaining argparse kwargs cover less-common needs but are wired through unch
392393

393394
```py
394395
@with_annotated(base_command=True)
395-
def do_manage(self, *, cmd2_handler):
396-
handler = cmd2_handler
397-
if handler:
398-
handler()
396+
def do_manage(self, *, cmd2_subcommand_func):
397+
if cmd2_subcommand_func:
398+
cmd2_subcommand_func()
399399

400400
@with_annotated(subcommand_to="manage", help="list projects")
401401
def manage_list(self):
@@ -408,10 +408,9 @@ creates its own subparsers:
408408

409409
```py
410410
@with_annotated(subcommand_to="manage", base_command=True, help="manage projects")
411-
def manage_project(self, *, cmd2_handler):
412-
handler = cmd2_handler
413-
if handler:
414-
handler()
411+
def manage_project(self, *, cmd2_subcommand_func):
412+
if cmd2_subcommand_func:
413+
cmd2_subcommand_func()
415414

416415
@with_annotated(subcommand_to="manage project", help="add a project")
417416
def manage_project_add(self, name: str):

examples/annotated_example.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -440,7 +440,7 @@ def do_flex(self, name: str, _unknown: list[str] | None = None) -> None:
440440

441441
@with_annotated(base_command=True)
442442
@cmd2.with_category(ANNOTATED_CATEGORY)
443-
def do_manage(self, verbose: bool = False, *, cmd2_handler: Callable[[], Any] | None = None) -> None:
443+
def do_manage(self, verbose: bool = False, *, cmd2_subcommand_func: Callable[[], Any] | None = None) -> None:
444444
"""Base command for annotated subcommands.
445445
446446
Try:
@@ -449,13 +449,13 @@ def do_manage(self, verbose: bool = False, *, cmd2_handler: Callable[[], Any] |
449449
"""
450450
if verbose:
451451
self.poutput("verbose mode")
452-
if cmd2_handler:
453-
cmd2_handler()
452+
if cmd2_subcommand_func:
453+
cmd2_subcommand_func()
454454

455455
@with_annotated(subcommand_to="manage", base_command=True, help="manage projects")
456-
def manage_project(self, *, cmd2_handler: Callable[[], Any] | None = None) -> None:
457-
if cmd2_handler:
458-
cmd2_handler()
456+
def manage_project(self, *, cmd2_subcommand_func: Callable[[], Any] | None = None) -> None:
457+
if cmd2_subcommand_func:
458+
cmd2_subcommand_func()
459459

460460
@with_annotated(subcommand_to="manage project", help="add a project")
461461
def manage_project_add(self, name: str) -> None:

0 commit comments

Comments
 (0)