Skip to content

Commit fd655f4

Browse files
committed
Raise ValueError in attach_subcommand() when the subcommand already exists.
1 parent 47c492b commit fd655f4

4 files changed

Lines changed: 27 additions & 3 deletions

File tree

cmd2/argparse_utils.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -729,7 +729,8 @@ def attach_subcommand(
729729
:raises TypeError: if subcommand_parser is not an instance of the following or their subclasses:
730730
1. Cmd2ArgumentParser
731731
2. The parser_class configured for the target subcommand group
732-
:raises ValueError: if the command path is invalid or doesn't support subcommands
732+
:raises ValueError: if the command path is invalid, doesn't support subcommands, or the
733+
subcommand already exists
733734
"""
734735
if not isinstance(subcommand_parser, Cmd2ArgumentParser):
735736
raise TypeError(
@@ -752,7 +753,11 @@ def attach_subcommand(
752753
)
753754

754755
# Use add_parser to register the subcommand name and any aliases
755-
placeholder_parser = subparsers_action.add_parser(subcommand, **add_parser_kwargs)
756+
try:
757+
placeholder_parser = subparsers_action.add_parser(subcommand, **add_parser_kwargs)
758+
except ArgumentError as ex:
759+
# The subcommand already exists
760+
raise ValueError(str(ex)) from None
756761

757762
# To ensure accurate usage strings, recursively update 'prog' values
758763
# within the injected parser to match its new location in the command hierarchy.

cmd2/cmd2.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1199,7 +1199,8 @@ def attach_subcommand(
11991199
:raises TypeError: if subcommand_parser is not an instance of the following or their subclasses:
12001200
1. Cmd2ArgumentParser
12011201
2. The parser_class configured for the target subcommand group
1202-
:raises ValueError: if the command path is invalid or doesn't support subcommands
1202+
:raises ValueError: if the command path is invalid, doesn't support subcommands, or the
1203+
subcommand already exists
12031204
"""
12041205
root_parser, subcommand_path = self.get_root_parser_and_subcmd_path(command)
12051206
root_parser.attach_subcommand(subcommand_path, subcommand, subcommand_parser, **add_parser_kwargs)

tests/test_argparse_utils.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -467,6 +467,12 @@ def test_subcommand_attachment_errors() -> None:
467467
with pytest.raises(TypeError, match=r"must be an instance of 'Cmd2ArgumentParser' \(or a subclass\)"):
468468
root_parser.attach_subcommand([], "sub", ap_parser) # type: ignore[arg-type]
469469

470+
# Verify ValueError when subcommand name already exists
471+
sub_parser = Cmd2ArgumentParser(prog="sub")
472+
root_parser.attach_subcommand([], "sub", sub_parser)
473+
with pytest.raises(ValueError, match="conflicting subparser: sub"):
474+
root_parser.attach_subcommand([], "sub", sub_parser)
475+
470476

471477
def test_subcommand_attachment_parser_class_override() -> None:
472478
class MyParser(Cmd2ArgumentParser):

tests/test_cmd2.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4596,6 +4596,13 @@ class SubcmdErrorApp(cmd2.Cmd):
45964596
def __init__(self) -> None:
45974597
super().__init__()
45984598

4599+
test_parser = cmd2.Cmd2ArgumentParser()
4600+
test_parser.add_subparsers(required=True)
4601+
4602+
@cmd2.with_argparser(test_parser)
4603+
def do_test(self, _statement: cmd2.Statement) -> None:
4604+
pass
4605+
45994606
def do_no_argparse(self, _statement: cmd2.Statement) -> None:
46004607
pass
46014608

@@ -4612,3 +4619,8 @@ def do_no_argparse(self, _statement: cmd2.Statement) -> None:
46124619
# Test command that doesn't use argparse
46134620
with pytest.raises(ValueError, match="Command 'no_argparse' does not use argparse"):
46144621
app.attach_subcommand("no_argparse", "sub", cmd2.Cmd2ArgumentParser())
4622+
4623+
# Test duplicate subcommand
4624+
app.attach_subcommand("test", "sub", cmd2.Cmd2ArgumentParser())
4625+
with pytest.raises(ValueError, match="conflicting subparser: sub"):
4626+
app.attach_subcommand("test", "sub", cmd2.Cmd2ArgumentParser())

0 commit comments

Comments
 (0)