Skip to content

Commit de4ba20

Browse files
committed
Add a missing check and associated unit test
Also: - Reword a couple TypeError messages which read awkwardly
1 parent 705f2ba commit de4ba20

3 files changed

Lines changed: 18 additions & 2 deletions

File tree

‎cmd2/annotated.py‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2931,6 +2931,8 @@ def handler(*args: _CommandParams.args, **kwargs: _CommandParams.kwargs) -> bool
29312931
"""Unpack Namespace into typed kwargs for the subcommand handler."""
29322932
if kwargs:
29332933
raise TypeError("subcommand handlers do not accept keyword arguments")
2934+
if len(args) != 2:
2935+
raise TypeError(f"subcommand handlers require 2 positional arguments (self, namespace), got {len(args)}")
29342936
self_arg, ns = args
29352937
if not isinstance(ns, argparse.Namespace):
29362938
raise TypeError("subcommand handlers require a parsed argparse.Namespace")

‎cmd2/cmd2.py‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5959,7 +5959,7 @@ def _validate_postparsing_callable(cls, func: Callable[[plugin.PostparsingData],
59595959
if par_ann != plugin.PostparsingData:
59605960
raise TypeError(f"{func_name} must have one parameter declared with type 'cmd2.plugin.PostparsingData'")
59615961
if ret_ann != plugin.PostparsingData:
5962-
raise TypeError(f"{func_name} must declare return a return type of 'cmd2.plugin.PostparsingData'")
5962+
raise TypeError(f"{func_name} must declare a return type of 'cmd2.plugin.PostparsingData'")
59635963

59645964
def register_postparsing_hook(self, func: Callable[[plugin.PostparsingData], plugin.PostparsingData]) -> None:
59655965
"""Register a function to be called after parsing user input but before running the command."""
@@ -6016,7 +6016,7 @@ def _validate_cmdfinalization_callable(
60166016
f"{func_name} must have one parameter declared with type {plugin.CommandFinalizationData}, got: {par_ann}"
60176017
)
60186018
if ret_ann != plugin.CommandFinalizationData:
6019-
raise TypeError(f"{func_name} must declare return a return type of {plugin.CommandFinalizationData}")
6019+
raise TypeError(f"{func_name} must declare a return type of {plugin.CommandFinalizationData}")
60206020

60216021
def register_cmdfinalization_hook(
60226022
self, func: Callable[[plugin.CommandFinalizationData], plugin.CommandFinalizationData]

‎tests/test_annotated.py‎

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2318,6 +2318,20 @@ def root_child(self) -> None:
23182318
root_child(object(), argparse.Namespace(), unexpected=True)
23192319

23202320

2321+
def test_subcommand_handler_rejects_wrong_positional_argument_count() -> None:
2322+
"""The internal subcommand adapter requires exactly two positional arguments (self, namespace)."""
2323+
2324+
@with_annotated(subcommand_to="root")
2325+
def root_child(self) -> None:
2326+
pass
2327+
2328+
with pytest.raises(TypeError, match=r"require 2 positional arguments"):
2329+
root_child(object())
2330+
2331+
with pytest.raises(TypeError, match=r"require 2 positional arguments"):
2332+
root_child(object(), argparse.Namespace(), "extra")
2333+
2334+
23212335
def test_subcommand_handler_requires_namespace() -> None:
23222336
"""The internal subcommand adapter rejects calls without a parsed namespace."""
23232337

0 commit comments

Comments
 (0)