Python argparse:大量的select导致丑陋的帮助输出

我有这个我普遍喜欢的代码:

import argparse servers = [ "ApaServer", "BananServer", "GulServer", "SolServer", "RymdServer", "SkeppServer", "HavsServer", "PiratServer", "SvartServer", "NattServer", "SovServer" ] parser = argparse.ArgumentParser(description="A program to update components on servers.") group = parser.add_mutually_exclusive_group() group.add_argument('-l', '--list', dest="update", action='store_false', default=False, help='list server components') group.add_argument('-u', '--updatepom', dest="update", action='store_true', help='update server components') parser.add_argument('-o', '--only', nargs='*', choices=servers, help='Space separated list of case sensitive server names to process') parser.add_argument('-s', '--skip', nargs='*', choices=servers, help='Space separated list of case sensitive server names to exclude from processing') args = parser.parse_args() 

我喜欢这个select=服务器validation在我的input服务器名称,所以我不必。 然而,有这么多有效的select使得帮助输出看起来很糟糕:

 usage: args.py [-h] [-l | -u] [-o [{ApaServer,BananServer,GulServer,SolServer,RymdServer,SkeppServer,HavsServer,PiratServer,SvartServer,NattServer,SovServer} [{ApaServer,BananServer,GulServer,SolServer,RymdServer,SkeppServer,HavsServer,PiratServer,SvartServer,NattServer,SovServer} ...]]] [-s [{ApaServer,BananServer,GulServer,SolServer,RymdServer,SkeppServer,HavsServer,PiratServer,SvartServer,NattServer,SovServer} [{ApaServer,BananServer,GulServer,SolServer,RymdServer,SkeppServer,HavsServer,PiratServer,SvartServer,NattServer,SovServer} ...]]] A program to update components on servers. optional arguments: -h, --help show this help message and exit -l, --list list server components -u, --updatepom update server components -o [{ApaServer,BananServer,GulServer,SolServer,RymdServer,SkeppServer,HavsServer,PiratServer,SvartServer,NattServer,SovServer} [{ApaServer,BananServer,GulServer,SolServer,RymdServer,SkeppServer,HavsServer,PiratServer,SvartServer,NattServer,SovServer} ...]], --only [{ApaServer,BananServer,GulServer,SolServer,RymdServer,SkeppServer,HavsServer,PiratServer,SvartServer,NattServer,SovServer} [{ApaServer,BananServer,GulServer,SolServer,RymdServer,SkeppServer,HavsServer,PiratServer,SvartServer,NattServer,SovServer} ...]] Space separated list of case sensitive server names to process -s [{ApaServer,BananServer,GulServer,SolServer,RymdServer,SkeppServer,HavsServer,PiratServer,SvartServer,NattServer,SovServer} [{ApaServer,BananServer,GulServer,SolServer,RymdServer,SkeppServer,HavsServer,PiratServer,SvartServer,NattServer,SovServer} ...]], --skip [{ApaServer,BananServer,GulServer,SolServer,RymdServer,SkeppServer,HavsServer,PiratServer,SvartServer,NattServer,SovServer} [{ApaServer,BananServer,GulServer,SolServer,RymdServer,SkeppServer,HavsServer,PiratServer,SvartServer,NattServer,SovServer} ...]] Space separated list of case sensitive server names to exclude from processing 

如果我想要,你会推荐哪种方式:

  • 很好(主要)自动生成的帮助输出
  • validation给予-o或-s选项的条目在servers

奖金:

  • 是否有可能有不区分大小写的string匹配的服务器名称?

附加

我尝试使用michaelfilmsbuild议,其中-o -s选项从上述输出中删除,并添加此部分:

 server optional arguments: Valid server names are: ApaServer, BananServer, GulServer, SolServer, RymdServer, SkeppServer, HavsServer, PiratServer, SvartServer, NattServer, SovServer 

我觉得它看起来不错,但是我真的需要为-o-s选项提供帮助,因为用户不会知道它们。 所以我还没有使用这种方法。

我基本上重复了厄内斯特所说的 – 为了避免丑陋的长select列表,为基于select的参数设置metavar ='(尽pipe它不会摆脱参数和逗号之间的空格(例如-o ,而是然后你可以在一般的描述中详细描述可用的select(RawDescriptionHelpFormatter在这里是有用的,如果你想让他们列出明显的缩进)。

我不明白为什么欧内斯特的答案被否决了。 这个代码

 import argparse servers = [ "ApaServer", "BananServer", "GulServer", "SolServer", "RymdServer", "SkeppServer", "HavsServer", "PiratServer", "SvartServer", "NattServer", "SovServer" ] parser = argparse.ArgumentParser(description="A program to update components on servers.") group = parser.add_mutually_exclusive_group() group.add_argument('-l', '--list', dest="update", action='store_false', default=False, help='list server components') group.add_argument('-u', '--updatepom', dest="update", action='store_true', help='update server components') parser.add_argument('-o', '--only', choices=servers, help='Space separated list of case sensitive server names to process. Allowed values are '+', '.join(servers), metavar='') parser.add_argument('-s', '--skip', choices=servers, help='Space separated list of case sensitive server names to exclude from processing. Allowed values are '+', '.join(servers), metavar='') args = parser.parse_args() 

产生以下帮助输出

 usage: run.py [-h] [-l | -u] [-o] [-s] A program to update components on servers. optional arguments: -h, --help show this help message and exit -l, --list list server components -u, --updatepom update server components -o , --only Space separated list of case sensitive server names to process. Allowed values are ApaServer, BananServer, GulServer, SolServer, RymdServer, SkeppServer, HavsServer, PiratServer, SvartServer, NattServer, SovServer -s , --skip Space separated list of case sensitive server names to exclude from processing. Allowed values are ApaServer, BananServer, GulServer, SolServer, RymdServer, SkeppServer, HavsServer, PiratServer, SvartServer, NattServer, SovServer 

这是希望什么原来的职位正在寻找。

没有必要inheritance任何东西。 只需传递一个metavar参数,并将其显示在帮助消息中。

有关详细信息,请参阅argparse文档 。

我有这个相同的问题,作为一个解决方法,我使用epilog来描述每个选项的select。 我不得不使用argparse.RawTextHelpFormatter,它可以让你指定epilog是预先格式化的。

 def choicesDescriptions(): return """ Choices supports the following: choice1 - the FIRST option choice2 - the SECOND option ... choiceN - the Nth option """ def getChoices(): return ["choice1", "choice2", ..., "choiceN"] parser = argparse.ArgumentParser(formatter_class=argparse.RawTextHelpFormatter, epilog=choicesDescriptions()) parser.add_argument( 'choices', choices=getChoices(), help='Arg choice. See the choices options below' ) args = parser.parse_args() print(args) 

要获得预期的输出,您需要argparse.HelpFormatter并实现所需的格式。 特别是,你需要实现你自己的_metavar_formatter方法,这个方法负责把所有的选项合并成一个由逗号分隔的单个string。

为什么不使用parser.add_argument_group为您的基于服务器的选项创build一个组,并给出一个描述arg显示可能的select列表? 然后将argparse.SUPPRESS传递给每个单独选项的帮助。 我相信会给你想要的。

这在select列表非常长的情况下是不会有帮助的,就像原来的问题一样,但是对于像我这样的人来说,遇到这个问题的时候,要想把一个中等长度的选项分成两行,这里是我的解:

 import argparse class CustomFormatter(argparse.HelpFormatter): """Custom formatter for setting argparse formatter_class. Identical to the default formatter, except that very long option strings are split into two lines. """ def _format_action_invocation(self, action): if not action.option_strings: metavar, = self._metavar_formatter(action, action.dest)(1) return metavar else: parts = [] # if the Optional doesn't take a value, format is: # -s, --long if action.nargs == 0: parts.extend(action.option_strings) # if the Optional takes a value, format is: # -s ARGS, --long ARGS else: default = action.dest.upper() args_string = self._format_args(action, default) for option_string in action.option_strings: parts.append('%s %s' % (option_string, args_string)) if sum(len(s) for s in parts) < self._width - (len(parts) - 1) * 2: return ', '.join(parts) else: return ',\n '.join(parts) 

这段代码覆盖默认的argparse.HelpFormatter方法_format_action_invocation,除了最后四行外,它与默认的实现相同。

默认格式化程序行为:

 parser = argparse.ArgumentParser(description="Argparse default formatter.") parser.add_argument('-a', '--argument', help='not too long') parser.add_argument('-u', '--ugly', choices=range(20), help='looks messy') parser.print_help() 

输出:

 usage: test.py [-h] [-a ARGUMENT] [-u {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19}] Argparse default formatter. optional arguments: -h, --help show this help message and exit -a ARGUMENT, --argument ARGUMENT not too long -u {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19}, --ugly {0,1,2,3,4,5,6, 7,8,9,10,11,12,13,14,15,16,17,18,19} looks messy 

自定义格式器行为:

 parser = argparse.ArgumentParser(description="Argparse custom formatter.", formatter_class=CustomFormatter) parser.add_argument('-a', '--argument', help='not too long') parser.add_argument('-l', '--less-ugly', choices=range(20), help='less messy') 

输出:

 usage: test.py [-h] [-a ARGUMENT] [-l {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19}] Argparse custom formatter. optional arguments: -h, --help show this help message and exit -a ARGUMENT, --argument ARGUMENT not too long -l {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19}, --less-ugly {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19} less messy 

http://bugs.python.org/issue16468 argparse only supports iterable choices是讨论select格式的错误问题。 选项列表可以出现在3个位置:使用行,帮助行和错误消息。

parsing器所关心的是in__contains__ )中进行testing。 但是,对于格式化来说,长列表,无界列表(例如整数> 100)和其他不可迭代的对象会产生问题。 metavar是当前用户可以解决大多数格式问题的方式(它可能无助于错误消息)。 看看这个问题,了解如何更改自己的argparse版本。