@@ -4419,3 +4419,75 @@ def test_auto_suggest_default():
44194419 """Test that auto_suggest defaults to True."""
44204420 app = cmd2 .Cmd ()
44214421 assert isinstance (app .main_session .auto_suggest , AutoSuggestFromHistory )
4422+
4423+
4424+ def test_attach_subcommand () -> None :
4425+ import argparse
4426+
4427+ class SubcmdApp (cmd2 .Cmd ):
4428+ def __init__ (self ) -> None :
4429+ super ().__init__ ()
4430+
4431+ root_parser = cmd2 .Cmd2ArgumentParser ()
4432+ root_parser .add_subparsers ()
4433+
4434+ @cmd2 .with_argparser (root_parser )
4435+ def do_root (self , _args : argparse .Namespace ) -> None :
4436+ pass
4437+
4438+ app = SubcmdApp ()
4439+
4440+ # Verify root exists and uses argparse
4441+ root_parser = app ._command_parsers .get (app .do_root )
4442+ assert root_parser is not None
4443+
4444+ # Attach child to root
4445+ child_parser = cmd2 .Cmd2ArgumentParser (prog = "child" )
4446+ child_parser .add_subparsers ()
4447+ app .attach_subcommand ("root" , "child" , child_parser , help = "child help" )
4448+
4449+ # Verify child was attached
4450+ root_subparsers_action = root_parser ._get_subparsers_action ()
4451+ assert "child" in root_subparsers_action ._name_parser_map
4452+ assert root_subparsers_action ._name_parser_map ["child" ] is child_parser
4453+
4454+ # Attach grandchild to child
4455+ grandchild_parser = cmd2 .Cmd2ArgumentParser (prog = "grandchild" )
4456+ app .attach_subcommand ("root child" , "grandchild" , grandchild_parser )
4457+
4458+ # Verify grandchild was attached
4459+ child_subparsers_action = child_parser ._get_subparsers_action ()
4460+ assert "grandchild" in child_subparsers_action ._name_parser_map
4461+
4462+ # Detach grandchild
4463+ detached_grandchild = app .detach_subcommand ("root child" , "grandchild" )
4464+ assert detached_grandchild is grandchild_parser
4465+ assert "grandchild" not in child_subparsers_action ._name_parser_map
4466+
4467+ # Detach child
4468+ detached_child = app .detach_subcommand ("root" , "child" )
4469+ assert detached_child is child_parser
4470+ assert "child" not in root_subparsers_action ._name_parser_map
4471+
4472+
4473+ def test_attach_subcommand_errors () -> None :
4474+ class SubcmdErrorApp (cmd2 .Cmd ):
4475+ def __init__ (self ) -> None :
4476+ super ().__init__ ()
4477+
4478+ def do_no_argparse (self , _statement : cmd2 .Statement ) -> None :
4479+ pass
4480+
4481+ app = SubcmdErrorApp ()
4482+
4483+ # Test empty command
4484+ with pytest .raises (ValueError , match = "Command path cannot be empty" ):
4485+ app .attach_subcommand ("" , "sub" , cmd2 .Cmd2ArgumentParser ())
4486+
4487+ # Test non-existent command
4488+ with pytest .raises (ValueError , match = "Root command 'fake' not found" ):
4489+ app .attach_subcommand ("fake" , "sub" , cmd2 .Cmd2ArgumentParser ())
4490+
4491+ # Test command that doesn't use argparse
4492+ with pytest .raises (ValueError , match = "Command 'no_argparse' does not use argparse" ):
4493+ app .attach_subcommand ("no_argparse" , "sub" , cmd2 .Cmd2ArgumentParser ())
0 commit comments