Argparse 两次输出帮助文本
Argparse outputting help text twice
经过一个小时的谷歌搜索,除了我自己,我找不到任何人遇到过类似的问题。我用 argparse 创建了一个命令行界面。最初我曾尝试利用 argparse 的内置帮助文本行为。但是我的老板对默认的帮助文本不满意,所以他让我在文本文件中写下完整的 usage/help 文本,然后只显示整个文件。
由于某些原因,在某些情况下,它输出了两次文本。
下面是我的程序分解的基础知识:
我有一个顶级解析器。我阅读了我的帮助文本文件,将其设置为字符串 help_text,然后在解析器上设置“usage=help_text”。然后我创建子解析器(其中 4 个,然后是一个基本案例)来创建子命令。这些子解析器中只有一个具有任何附加参数(一个位置参数,一个可选参数)。在我重新编写帮助文本之前,我通过使用“help=”为每个单独的子命令提供了帮助文本,但现在这些都是空白的。最后,我设置了一个基本案例,以便在没有给出子命令时显示帮助文本。
这是我得到的行为:
当我在没有子命令和参数的情况下调用主函数时,我的 help_text 从文本文件输出,然后像 2-3 行样板一样我似乎无法摆脱.也因为单词 usage 出现在我的文本文件中,它说“usage: usage”
当我调用主命令然后键入 --help 时,会发生与上面完全相同的事情。
当我调用一个具有必需位置参数的子命令但我没有包含该参数时...它会吐出整个帮助文本两次。在第二次打印的正上方,它打印了该子命令的默认用法行。
最后,当我使用一个没有参数的不同子命令并给它一个参数(一个太多)时,它会完全正确地吐出所有内容,甚至最后没有额外的几行。
我不知道如何引起注意或讲故事。下面是脚本的main函数(我可以验证这个问题只发生在使用了argparse的main函数,而不是main函数调用的其他函数):
def main():
# Import help text from file
p = Path(__file__).with_name("help_text.txt")
with p.open() as file:
help_text = file.read()
# Configure the top level Parser
parser = argparse.ArgumentParser(prog='hubmap-clt', description='Name of cli', usage=help_text)
subparsers = parser.add_subparsers()
# Create Subparsers to give subcommands
parser_transfer = subparsers.add_parser('subcommandone')
parser_transfer.add_argument('argument1', type=str)
parser_transfer.add_argument('--optionalargument', default='mydefault')
parser_login = subparsers.add_parser('subcommandtwo')
parser_whoami = subparsers.add_parser('subcommandthree')
parser_logout = subparsers.add_parser('subcommandfour')
# Assign subparsers to their respective functions
parser_subcommandone.set_defaults(func=subcommandone)
parser_subcommandtwo.set_defaults(func=subcommandtwo)
parser_subcommandthree.set_defaults(func=subcommandthree)
parser_subcommandfour.set_defaults(func=subcommandfour)
parser.set_defaults(func=base_case)
# Parse the arguments and call appropriate functions
args = parser.parse_args()
if len(sys.argv) == 1:
args.func(args, parser)
else:
args.func(args)
所以澄清一下:
为什么有时会出现额外的几行样板帮助文本,如下所示:
name of cli
positional arguments:
{subcommandone,subcommandtwo,subcommandthree,subcommandfour}
optional arguments:
-h, --help show this help message and exit
为什么使用参数太少的 subcommandone 会打印两次帮助文本(而不是样板帮助文本的额外行。
为什么使用带有太多参数的 subcommandtwo 可以完美地打印所有内容而没有任何额外的行?
修改你的main
:
def foo():
# Import help text from file
# p = Path(__file__).with_name("help_text.txt")
# with p.open() as file:
# help_text = file.read()
help_text = "cli usage: foobar\n morebar"
# Configure the top level Parser
parser = argparse.ArgumentParser(
prog="hubmap-clt", description="Name of cli", usage=help_text
)
subparsers = parser.add_subparsers()
# Create Subparsers to give subcommands
parser_transfer = subparsers.add_parser("subcommandone")
parser_transfer.add_argument("argument1", type=str)
parser_transfer.add_argument("--optionalargument", default="mydefault")
parser_login = subparsers.add_parser("subcommandtwo")
# parser_whoami = subparsers.add_parser("subcommandthree")
# parser_logout = subparsers.add_parser("subcommandfour")
# Assign subparsers to their respective functions
parser_transfer.set_defaults(func="subcommandone")
parser_login.set_defaults(func="subcommandtwo")
# parser_subcommandthree.set_defaults(func="subcommandthree")
# parser_subcommandfour.set_defaults(func="subcommandfour")
parser.set_defaults(func="base_case")
return parser
在迭代 ipython 会话中:
In [8]: p = foo()
In [9]: p.print_usage()
usage: cli usage: foobar
morebar
用法和我指定的完全一样。以及对主要解析器的帮助:
In [10]: p.print_help()
usage: cli usage: foobar
morebar
Name of cli
positional arguments:
{subcommandone,subcommandtwo}
optional arguments:
-h, --help show this help message and exit
这就是我所期望的参数。
对子解析器的帮助:
In [11]: p.parse_args(["subcommandone", "-h"])
usage: cli usage: foobar
morebar subcommandone [-h] [--optionalargument OPTIONALARGUMENT] argument1
positional arguments:
argument1
optional arguments:
-h, --help show this help message and exit
--optionalargument OPTIONALARGUMENT
用法与主要用法类似,但增加了一些有关如何调用此子解析器及其参数的信息。
在没有足够值的情况下调用子解析器时出错:
In [15]: p.parse_args(["subcommandone"])
usage: cli usage: foobar
morebar subcommandone [-h] [--optionalargument OPTIONALARGUMENT] argument1
cli usage: foobar
morebar subcommandone: error: the following arguments are required: argument1
重复 cli usage
是否让您感到困扰?这个错误是由子解析器引发的,我怀疑额外的来自该子解析器的 prog
。我想我在 Python bug/issues 上为 argparse
.
看到了类似的东西
错误过多:
In [17]: p.parse_args(["subcommandone", "test", "extra"])
usage: cli usage: foobar
morebar
hubmap-clt: error: unrecognized arguments: extra
在这种情况下,错误是由主解析器产生的,因此出现“hubmat-clt”prog
.
更改prog
:
...: parser_transfer = subparsers.add_parser(
...: "subcommandone", prog="hubmap-clt sobcommandone"
...:)
In [21]: p.parse_args(["subcommandone", "test", "extra"])
usage: cli usage: foobar
morebar
hubmap-clt: error: unrecognized arguments: extra
In [22]: p.parse_args(["subcommandone"])
usage: hubmap-clt sobcommandone [-h] [--optionalargument OPTIONALARGUMENT] argument1
hubmap-clt sobcommandone: error: the following arguments are required: argument1
[21] 和之前的 [17] 一样。但是 [22] 现在显示的是我设置的 prog
。我也可以为子解析器指定自定义 usage
。
如果我修改函数以使用默认用法和prog,还会显示子解析器的prog。我给了主要一个“main_foo”位置参数:
In [30]: p = foo()
hubmap-clt main_foo subcommandone
In [31]: p.parse_args(["subcommandone"])
Out[31]: Namespace(main_foo='subcommandone')
In [32]: p.parse_args(["foo", "subcommandone"])
usage: hubmap-clt main_foo subcommandone [-h] [--optionalargument OPTIONALARGUMENT] argument1
hubmap-clt main_foo subcommandone: error: the following arguments are required: argument1
注意如何将 main 的用法合并到子解析器的 'prog' 中。
在 bug/issue 中,我发现主解析器的 usage
被合并到子解析器的 prog
中。这就是您看到重复项的原因。
https://bugs.python.org/issue42297
[argparse] 使用自定义用法文本时错误消息格式错误
这个错误问题的最近日期表明自定义用法并不常见,与子解析器一起使用时更是如此。正如我在这个问题上的 post 指出的那样,主解析器、“子解析器”命令和各个子解析器之间的关系变得复杂。
经过一个小时的谷歌搜索,除了我自己,我找不到任何人遇到过类似的问题。我用 argparse 创建了一个命令行界面。最初我曾尝试利用 argparse 的内置帮助文本行为。但是我的老板对默认的帮助文本不满意,所以他让我在文本文件中写下完整的 usage/help 文本,然后只显示整个文件。
由于某些原因,在某些情况下,它输出了两次文本。
下面是我的程序分解的基础知识:
我有一个顶级解析器。我阅读了我的帮助文本文件,将其设置为字符串 help_text,然后在解析器上设置“usage=help_text”。然后我创建子解析器(其中 4 个,然后是一个基本案例)来创建子命令。这些子解析器中只有一个具有任何附加参数(一个位置参数,一个可选参数)。在我重新编写帮助文本之前,我通过使用“help=”为每个单独的子命令提供了帮助文本,但现在这些都是空白的。最后,我设置了一个基本案例,以便在没有给出子命令时显示帮助文本。
这是我得到的行为:
当我在没有子命令和参数的情况下调用主函数时,我的 help_text 从文本文件输出,然后像 2-3 行样板一样我似乎无法摆脱.也因为单词 usage 出现在我的文本文件中,它说“usage: usage”
当我调用主命令然后键入 --help 时,会发生与上面完全相同的事情。
当我调用一个具有必需位置参数的子命令但我没有包含该参数时...它会吐出整个帮助文本两次。在第二次打印的正上方,它打印了该子命令的默认用法行。
最后,当我使用一个没有参数的不同子命令并给它一个参数(一个太多)时,它会完全正确地吐出所有内容,甚至最后没有额外的几行。
我不知道如何引起注意或讲故事。下面是脚本的main函数(我可以验证这个问题只发生在使用了argparse的main函数,而不是main函数调用的其他函数):
def main():
# Import help text from file
p = Path(__file__).with_name("help_text.txt")
with p.open() as file:
help_text = file.read()
# Configure the top level Parser
parser = argparse.ArgumentParser(prog='hubmap-clt', description='Name of cli', usage=help_text)
subparsers = parser.add_subparsers()
# Create Subparsers to give subcommands
parser_transfer = subparsers.add_parser('subcommandone')
parser_transfer.add_argument('argument1', type=str)
parser_transfer.add_argument('--optionalargument', default='mydefault')
parser_login = subparsers.add_parser('subcommandtwo')
parser_whoami = subparsers.add_parser('subcommandthree')
parser_logout = subparsers.add_parser('subcommandfour')
# Assign subparsers to their respective functions
parser_subcommandone.set_defaults(func=subcommandone)
parser_subcommandtwo.set_defaults(func=subcommandtwo)
parser_subcommandthree.set_defaults(func=subcommandthree)
parser_subcommandfour.set_defaults(func=subcommandfour)
parser.set_defaults(func=base_case)
# Parse the arguments and call appropriate functions
args = parser.parse_args()
if len(sys.argv) == 1:
args.func(args, parser)
else:
args.func(args)
所以澄清一下:
为什么有时会出现额外的几行样板帮助文本,如下所示:
name of cli
positional arguments:
{subcommandone,subcommandtwo,subcommandthree,subcommandfour}
optional arguments:
-h, --help show this help message and exit
为什么使用参数太少的 subcommandone 会打印两次帮助文本(而不是样板帮助文本的额外行。
为什么使用带有太多参数的 subcommandtwo 可以完美地打印所有内容而没有任何额外的行?
修改你的main
:
def foo():
# Import help text from file
# p = Path(__file__).with_name("help_text.txt")
# with p.open() as file:
# help_text = file.read()
help_text = "cli usage: foobar\n morebar"
# Configure the top level Parser
parser = argparse.ArgumentParser(
prog="hubmap-clt", description="Name of cli", usage=help_text
)
subparsers = parser.add_subparsers()
# Create Subparsers to give subcommands
parser_transfer = subparsers.add_parser("subcommandone")
parser_transfer.add_argument("argument1", type=str)
parser_transfer.add_argument("--optionalargument", default="mydefault")
parser_login = subparsers.add_parser("subcommandtwo")
# parser_whoami = subparsers.add_parser("subcommandthree")
# parser_logout = subparsers.add_parser("subcommandfour")
# Assign subparsers to their respective functions
parser_transfer.set_defaults(func="subcommandone")
parser_login.set_defaults(func="subcommandtwo")
# parser_subcommandthree.set_defaults(func="subcommandthree")
# parser_subcommandfour.set_defaults(func="subcommandfour")
parser.set_defaults(func="base_case")
return parser
在迭代 ipython 会话中:
In [8]: p = foo()
In [9]: p.print_usage()
usage: cli usage: foobar
morebar
用法和我指定的完全一样。以及对主要解析器的帮助:
In [10]: p.print_help()
usage: cli usage: foobar
morebar
Name of cli
positional arguments:
{subcommandone,subcommandtwo}
optional arguments:
-h, --help show this help message and exit
这就是我所期望的参数。
对子解析器的帮助:
In [11]: p.parse_args(["subcommandone", "-h"])
usage: cli usage: foobar
morebar subcommandone [-h] [--optionalargument OPTIONALARGUMENT] argument1
positional arguments:
argument1
optional arguments:
-h, --help show this help message and exit
--optionalargument OPTIONALARGUMENT
用法与主要用法类似,但增加了一些有关如何调用此子解析器及其参数的信息。
在没有足够值的情况下调用子解析器时出错:
In [15]: p.parse_args(["subcommandone"])
usage: cli usage: foobar
morebar subcommandone [-h] [--optionalargument OPTIONALARGUMENT] argument1
cli usage: foobar
morebar subcommandone: error: the following arguments are required: argument1
重复 cli usage
是否让您感到困扰?这个错误是由子解析器引发的,我怀疑额外的来自该子解析器的 prog
。我想我在 Python bug/issues 上为 argparse
.
错误过多:
In [17]: p.parse_args(["subcommandone", "test", "extra"])
usage: cli usage: foobar
morebar
hubmap-clt: error: unrecognized arguments: extra
在这种情况下,错误是由主解析器产生的,因此出现“hubmat-clt”prog
.
更改prog
:
...: parser_transfer = subparsers.add_parser( ...: "subcommandone", prog="hubmap-clt sobcommandone" ...:)
In [21]: p.parse_args(["subcommandone", "test", "extra"])
usage: cli usage: foobar
morebar
hubmap-clt: error: unrecognized arguments: extra
In [22]: p.parse_args(["subcommandone"])
usage: hubmap-clt sobcommandone [-h] [--optionalargument OPTIONALARGUMENT] argument1
hubmap-clt sobcommandone: error: the following arguments are required: argument1
[21] 和之前的 [17] 一样。但是 [22] 现在显示的是我设置的 prog
。我也可以为子解析器指定自定义 usage
。
如果我修改函数以使用默认用法和prog,还会显示子解析器的prog。我给了主要一个“main_foo”位置参数:
In [30]: p = foo()
hubmap-clt main_foo subcommandone
In [31]: p.parse_args(["subcommandone"])
Out[31]: Namespace(main_foo='subcommandone')
In [32]: p.parse_args(["foo", "subcommandone"])
usage: hubmap-clt main_foo subcommandone [-h] [--optionalargument OPTIONALARGUMENT] argument1
hubmap-clt main_foo subcommandone: error: the following arguments are required: argument1
注意如何将 main 的用法合并到子解析器的 'prog' 中。
在 bug/issue 中,我发现主解析器的 usage
被合并到子解析器的 prog
中。这就是您看到重复项的原因。
https://bugs.python.org/issue42297 [argparse] 使用自定义用法文本时错误消息格式错误
这个错误问题的最近日期表明自定义用法并不常见,与子解析器一起使用时更是如此。正如我在这个问题上的 post 指出的那样,主解析器、“子解析器”命令和各个子解析器之间的关系变得复杂。