summaryrefslogtreecommitdiff
path: root/cmd2
diff options
context:
space:
mode:
authorTodd Leonhardt <todd.leonhardt@gmail.com>2019-10-30 23:28:02 -0400
committerGitHub <noreply@github.com>2019-10-30 23:28:02 -0400
commit245dc33730d2a27bc9744be7cf36f176f5a0c10a (patch)
treeba6cfaae945625c28934b38bf537f78a5040b567 /cmd2
parentb1873c3e6a19276417e7b3a046b48db54a2d6304 (diff)
parent5a58199590f06996cc741063da29ffb166026ced (diff)
downloadcmd2-git-245dc33730d2a27bc9744be7cf36f176f5a0c10a.tar.gz
Merge pull request #796 from python-cmd2/set_prog
Recursively set parser.prog
Diffstat (limited to 'cmd2')
-rw-r--r--cmd2/cmd2.py66
1 files changed, 44 insertions, 22 deletions
diff --git a/cmd2/cmd2.py b/cmd2/cmd2.py
index 1af5e932..0a7097ba 100644
--- a/cmd2/cmd2.py
+++ b/cmd2/cmd2.py
@@ -177,14 +177,38 @@ def with_argument_list(*args: List[Callable], preserve_quotes: bool = False) ->
return arg_decorator
-def with_argparser_and_unknown_args(argparser: argparse.ArgumentParser, *,
+# noinspection PyProtectedMember
+def set_parser_prog(parser: argparse.ArgumentParser, prog: str):
+ """
+ Recursively set prog attribute of a parser and all of its subparsers so that the root command
+ is a command name and not sys.argv[0].
+ :param parser: the parser being edited
+ :param prog: value for the current parsers prog attribute
+ """
+ # Set the prog value for this parser
+ parser.prog = prog
+
+ # Set the prog value for the parser's subcommands
+ for action in parser._actions:
+ if isinstance(action, argparse._SubParsersAction):
+
+ # Set the prog value for each subcommand
+ for sub_cmd, sub_cmd_parser in action.choices.items():
+ sub_cmd_prog = parser.prog + ' ' + sub_cmd
+ set_parser_prog(sub_cmd_parser, sub_cmd_prog)
+
+ # We can break since argparse only allows 1 group of subcommands per level
+ break
+
+
+def with_argparser_and_unknown_args(parser: argparse.ArgumentParser, *,
ns_provider: Optional[Callable[..., argparse.Namespace]] = None,
preserve_quotes: bool = False) -> \
Callable[[argparse.Namespace, List], Optional[bool]]:
"""A decorator to alter a cmd2 method to populate its ``args`` argument by parsing arguments with the given
instance of argparse.ArgumentParser, but also returning unknown args as a list.
- :param argparser: unique instance of ArgumentParser
+ :param parser: unique instance of ArgumentParser
:param ns_provider: An optional function that accepts a cmd2.Cmd object as an argument and returns an
argparse.Namespace. This is useful if the Namespace needs to be prepopulated with
state data that affects parsing.
@@ -209,27 +233,26 @@ def with_argparser_and_unknown_args(argparser: argparse.ArgumentParser, *,
namespace = ns_provider(cmd2_app)
try:
- args, unknown = argparser.parse_known_args(parsed_arglist, namespace)
+ args, unknown = parser.parse_known_args(parsed_arglist, namespace)
except SystemExit:
return
else:
setattr(args, '__statement__', statement)
return func(cmd2_app, args, unknown)
- # argparser defaults the program name to sys.argv[0]
- # we want it to be the name of our command
+ # argparser defaults the program name to sys.argv[0], but we want it to be the name of our command
command_name = func.__name__[len(COMMAND_FUNC_PREFIX):]
- argparser.prog = command_name
+ set_parser_prog(parser, command_name)
# If the description has not been set, then use the method docstring if one exists
- if argparser.description is None and func.__doc__:
- argparser.description = func.__doc__
+ if parser.description is None and func.__doc__:
+ parser.description = func.__doc__
# Set the command's help text as argparser.description (which can be None)
- cmd_wrapper.__doc__ = argparser.description
+ cmd_wrapper.__doc__ = parser.description
# Set some custom attributes for this command
- setattr(cmd_wrapper, CMD_ATTR_ARGPARSER, argparser)
+ setattr(cmd_wrapper, CMD_ATTR_ARGPARSER, parser)
setattr(cmd_wrapper, CMD_ATTR_PRESERVE_QUOTES, preserve_quotes)
return cmd_wrapper
@@ -238,13 +261,13 @@ def with_argparser_and_unknown_args(argparser: argparse.ArgumentParser, *,
return arg_decorator
-def with_argparser(argparser: argparse.ArgumentParser, *,
+def with_argparser(parser: argparse.ArgumentParser, *,
ns_provider: Optional[Callable[..., argparse.Namespace]] = None,
preserve_quotes: bool = False) -> Callable[[argparse.Namespace], Optional[bool]]:
"""A decorator to alter a cmd2 method to populate its ``args`` argument by parsing arguments
with the given instance of argparse.ArgumentParser.
- :param argparser: unique instance of ArgumentParser
+ :param parser: unique instance of ArgumentParser
:param ns_provider: An optional function that accepts a cmd2.Cmd object as an argument and returns an
argparse.Namespace. This is useful if the Namespace needs to be prepopulated with
state data that affects parsing.
@@ -268,27 +291,26 @@ def with_argparser(argparser: argparse.ArgumentParser, *,
namespace = ns_provider(cmd2_app)
try:
- args = argparser.parse_args(parsed_arglist, namespace)
+ args = parser.parse_args(parsed_arglist, namespace)
except SystemExit:
return
else:
setattr(args, '__statement__', statement)
return func(cmd2_app, args)
- # argparser defaults the program name to sys.argv[0]
- # we want it to be the name of our command
+ # argparser defaults the program name to sys.argv[0], but we want it to be the name of our command
command_name = func.__name__[len(COMMAND_FUNC_PREFIX):]
- argparser.prog = command_name
+ set_parser_prog(parser, command_name)
# If the description has not been set, then use the method docstring if one exists
- if argparser.description is None and func.__doc__:
- argparser.description = func.__doc__
+ if parser.description is None and func.__doc__:
+ parser.description = func.__doc__
# Set the command's help text as argparser.description (which can be None)
- cmd_wrapper.__doc__ = argparser.description
+ cmd_wrapper.__doc__ = parser.description
# Set some custom attributes for this command
- setattr(cmd_wrapper, CMD_ATTR_ARGPARSER, argparser)
+ setattr(cmd_wrapper, CMD_ATTR_ARGPARSER, parser)
setattr(cmd_wrapper, CMD_ATTR_PRESERVE_QUOTES, preserve_quotes)
return cmd_wrapper
@@ -2396,7 +2418,7 @@ class Cmd(cmd.Cmd):
"An alias is a command that enables replacement of a word by another string.")
alias_epilog = ("See also:\n"
" macro")
- alias_parser = Cmd2ArgumentParser(description=alias_description, epilog=alias_epilog, prog='alias')
+ alias_parser = Cmd2ArgumentParser(description=alias_description, epilog=alias_epilog)
# Add subcommands to alias
alias_subparsers = alias_parser.add_subparsers(dest='subcommand')
@@ -2573,7 +2595,7 @@ class Cmd(cmd.Cmd):
"A macro is similar to an alias, but it can contain argument placeholders.")
macro_epilog = ("See also:\n"
" alias")
- macro_parser = Cmd2ArgumentParser(description=macro_description, epilog=macro_epilog, prog='macro')
+ macro_parser = Cmd2ArgumentParser(description=macro_description, epilog=macro_epilog)
# Add subcommands to macro
macro_subparsers = macro_parser.add_subparsers(dest='subcommand')