@@ -222,42 +222,43 @@ def get_choices(self) -> Choices:
222222more details on these arguments.
223223
224224``argparse.ArgumentParser._get_nargs_pattern`` - adds support for nargs ranges.
225- See _get_nargs_pattern_wrapper for more details.
225+ See `` _get_nargs_pattern_wrapper`` for more details.
226226
227227``argparse.ArgumentParser._match_argument`` - adds support for nargs ranges.
228- See _match_argument_wrapper for more details.
229-
230- ``argparse._SubParsersAction.remove_parser`` - new function which removes a
231- sub-parser from a sub-parsers group. See _SubParsersAction_remove_parser for
232- more details.
228+ See ``_match_argument_wrapper`` for more details.
233229
234230**Added accessor methods**
235231
236232cmd2 has patched ``argparse.Action`` to include the following accessor methods
237233for cases in which you need to manually access the cmd2-specific attributes.
238234
239- - ``argparse.Action.get_choices_callable()`` - See `action_get_choices_callable` for more details.
240- - ``argparse.Action.set_choices_provider()`` - See `_action_set_choices_provider` for more details.
241- - ``argparse.Action.set_completer()`` - See `_action_set_completer` for more details.
242- - ``argparse.Action.get_table_columns()`` - See `_action_get_table_columns` for more details.
243- - ``argparse.Action.set_table_columns()`` - See `_action_set_table_columns` for more details.
244- - ``argparse.Action.get_nargs_range()`` - See `_action_get_nargs_range` for more details.
245- - ``argparse.Action.set_nargs_range()`` - See `_action_set_nargs_range` for more details.
246- - ``argparse.Action.get_suppress_tab_hint()`` - See `_action_get_suppress_tab_hint` for more details.
247- - ``argparse.Action.set_suppress_tab_hint()`` - See `_action_set_suppress_tab_hint` for more details.
235+ - ``argparse.Action.get_choices_callable()`` - See `` action_get_choices_callable` ` for more details.
236+ - ``argparse.Action.set_choices_provider()`` - See `` _action_set_choices_provider` ` for more details.
237+ - ``argparse.Action.set_completer()`` - See `` _action_set_completer` ` for more details.
238+ - ``argparse.Action.get_table_columns()`` - See `` _action_get_table_columns` ` for more details.
239+ - ``argparse.Action.set_table_columns()`` - See `` _action_set_table_columns` ` for more details.
240+ - ``argparse.Action.get_nargs_range()`` - See `` _action_get_nargs_range` ` for more details.
241+ - ``argparse.Action.set_nargs_range()`` - See `` _action_set_nargs_range` ` for more details.
242+ - ``argparse.Action.get_suppress_tab_hint()`` - See `` _action_get_suppress_tab_hint` ` for more details.
243+ - ``argparse.Action.set_suppress_tab_hint()`` - See `` _action_set_suppress_tab_hint` ` for more details.
248244
249245cmd2 has patched ``argparse.ArgumentParser`` to include the following accessor methods
250246
251- - ``argparse.ArgumentParser.get_ap_completer_type()`` - See `_ArgumentParser_get_ap_completer_type` for more details.
252- - ``argparse.Action.set_ap_completer_type()`` - See `_ArgumentParser_set_ap_completer_type` for more details.
247+ - ``argparse.ArgumentParser.get_ap_completer_type()`` - See ``_ArgumentParser_get_ap_completer_type`` for more details.
248+ - ``argparse.Action.set_ap_completer_type()`` - See ``_ArgumentParser_set_ap_completer_type`` for more details.
249+
250+ **Subcommand Manipulation**
253251
254- **Subcommand removal**
252+ cmd2 has patched ``argparse._SubParsersAction`` with new functions to better facilitate the
253+ addition and removal of subcommand parsers.
255254
256- cmd2 has patched ``argparse._SubParsersAction`` to include a ``remove_parser()``
257- method which can be used to remove a subcommand.
255+ ``argparse._SubParsersAction.attach_parser`` - new function to attach
256+ an existing ArgumentParser to a subparsers action. See ``_SubParsersAction_attach_parser``
257+ for more details.
258258
259- ``argparse._SubParsersAction.remove_parser`` - new function which removes a
260- sub-parser from a sub-parsers group. See _SubParsersAction_remove_parser` for more details.
259+ ``argparse._SubParsersAction.detach_parser`` - new function to detach a
260+ parser from a subparsers action. See ``_SubParsersAction_detach_parser`` for
261+ more details.
261262"""
262263
263264import argparse
@@ -944,39 +945,85 @@ def _ArgumentParser_check_value(_self: argparse.ArgumentParser, action: argparse
944945
945946
946947############################################################################################################
947- # Patch argparse._SubParsersAction to add remove_parser function
948+ # Patch argparse._SubParsersAction to add attach_parser function
948949############################################################################################################
949950
950951
951- def _SubParsersAction_remove_parser (self : argparse ._SubParsersAction , name : str ) -> None : # type: ignore[type-arg] # noqa: N802
952- """Remove a sub-parser from a sub-parsers group. Used to remove subcommands from a parser.
952+ def _SubParsersAction_attach_parser ( # noqa: N802
953+ self : argparse ._SubParsersAction , # type: ignore[type-arg]
954+ name : str ,
955+ subcmd_parser : argparse .ArgumentParser ,
956+ ** add_parser_kwargs : Any ,
957+ ) -> None :
958+ """Attach an existing ArgumentParser to a subparsers action.
959+
960+ This is useful when a parser is pre-configured (e.g. by cmd2's subcommand decorator)
961+ and needs to be attached to a parent parser.
953962
954- This function is added by cmd2 as a method called ``remove_parser()`` to ``argparse._SubParsersAction`` class.
963+ This function is added by cmd2 as a method called ``attach_parser()``
964+ to ``argparse._SubParsersAction`` class.
955965
956- To call: ``action.remove_parser (name)``
966+ To call: ``action.attach_parser (name, subcmd_parser, **add_parser_kwargs )``
957967
958968 :param self: instance of the _SubParsersAction being edited
959- :param name: name of the subcommand for the sub-parser to remove
969+ :param name: name of the subcommand to add
970+ :param subcmd_parser: the parser for this new subcommand
971+ :param add_parser_kwargs: registration-specific kwargs for add_parser()
972+ (e.g. help, aliases, deprecated [Python 3.13+])
960973 """
961- # Remove this subcommand from its base command's help text
962- for choice_action in self ._choices_actions :
963- if choice_action .dest == name :
964- self ._choices_actions .remove (choice_action )
965- break
974+ # Use add_parser to register the subcommand name and any aliases
975+ self .add_parser (name , ** add_parser_kwargs )
976+
977+ # Replace the parser created by add_parser() with our pre-configured one
978+ self ._name_parser_map [name ] = subcmd_parser
979+
980+ # Remap any aliases to our pre-configured parser
981+ for alias in add_parser_kwargs .get ("aliases" , ()):
982+ self ._name_parser_map [alias ] = subcmd_parser
983+
984+
985+ setattr (argparse ._SubParsersAction , 'attach_parser' , _SubParsersAction_attach_parser )
966986
967- # Remove this subcommand and all its aliases from the base command
987+ ############################################################################################################
988+ # Patch argparse._SubParsersAction to add detach_parser function
989+ ############################################################################################################
990+
991+
992+ def _SubParsersAction_detach_parser ( # noqa: N802
993+ self : argparse ._SubParsersAction , # type: ignore[type-arg]
994+ name : str ,
995+ ) -> argparse .ArgumentParser | None :
996+ """Detach a parser from a subparsers action and return it.
997+
998+ This function is added by cmd2 as a method called ``detach_parser()`` to ``argparse._SubParsersAction`` class.
999+
1000+ To call: ``action.detach_parser(name)``
1001+
1002+ :param self: instance of the _SubParsersAction being edited
1003+ :param name: name of the subcommand for the parser to detach
1004+ :return: the parser which was detached or None if the subcommand doesn't exist
1005+ """
9681006 subparser = self ._name_parser_map .get (name )
1007+
9691008 if subparser is not None :
1009+ # Remove this subcommand and all its aliases from the base command
9701010 to_remove = []
9711011 for cur_name , cur_parser in self ._name_parser_map .items ():
9721012 if cur_parser is subparser :
9731013 to_remove .append (cur_name )
9741014 for cur_name in to_remove :
9751015 del self ._name_parser_map [cur_name ]
9761016
1017+ # Remove this subcommand from its base command's help text
1018+ for choice_action in self ._choices_actions :
1019+ if choice_action .dest == name :
1020+ self ._choices_actions .remove (choice_action )
1021+ break
1022+
1023+ return subparser
9771024
978- setattr (argparse ._SubParsersAction , 'remove_parser' , _SubParsersAction_remove_parser )
9791025
1026+ setattr (argparse ._SubParsersAction , 'detach_parser' , _SubParsersAction_detach_parser )
9801027
9811028############################################################################################################
9821029# Unless otherwise noted, everything below this point are copied from Python's
0 commit comments