2012-02-20 38 views
35

我有這樣的代碼很多,我很一般高興:的Python argparse:價格導致難看的幫助輸出

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() 

我喜歡選擇=服務器驗證輸入我的服務器名字,所以我不需要。然而,有這麼多有效的選擇,使幫助輸出看起來可怕:

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 

哪種方式,你會建議,如果我想:

  • 尼斯(大部分)自動生成的幫助輸出
  • 驗證該提供給-o或-s選項的條目在servers中。

獎勵:

  • 纔有可能有情況下的服務器名稱不區分大小寫字符串匹配?

追加

我嘗試使用michaelfilms建議在-o-s選項從上面的輸出中刪除,這部分增加:

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

我認爲它看起來相當不錯,但我真的需要爲-o-s選項提供幫助,因爲用戶不會知道它們。所以我還沒有使用這種方法。

回答

3

爲什麼不使用parser.add_argument_group爲您創造基於服務器的選項組並給予說明ARG顯示可能的選擇列表?然後將argparse.SUPPRESS傳遞給每個單獨選項的幫助。我相信這會給你想要的東西。

+0

我試過了,它看起來不錯。但我還沒有使用這種方法。我必須通過讓他知道'-o'和'-s'選項來幫助用戶。 – Deleted 2012-02-21 09:26:33

4

要獲得預期的輸出,你需要繼承argparse.HelpFormatter並實現您所需要的格式。尤其是,您需要實現自己的_metavar_formatter方法,該方法負責將所有選項合併爲一個由逗號分隔的單個字符串。

8

我有這個同樣的問題,作爲一種解決方法,我用了收尾描述每個選項的選擇。我不得不使用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) 
20

沒有必要繼承任何東西。只需將一個metavar參數與想要顯示在幫助消息中的字符串一起傳遞。

查看argparse documentation瞭解詳情。

37

我基本上重複了厄內斯特所說的 - 爲了避免醜陋的長選擇列表,爲基於選擇的參數設置了metavar ='(儘管它不會擺脫參數和逗號之間的空格(例如-o ,而不是-o,)然後,您可以在一般描述中詳細描述可用的選項(如果您希望列出明顯的縮進,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 

這是什麼希望原來的職位一直在尋找。

+0

設置metavar爲 '' 或無導致顯示在all.move_parser.add_argument沒有幫助( 'old_host',行動= '店',選擇= distinct_host,幫助= 「老主人」 + ''。加入(distinct_host) metavar = None) – user2601010 2015-05-05 18:19:48

+0

'metavar ='''現在似乎會導致錯誤。將其設置爲空白字符串以外的任何內容(例如參數名稱)會修復它。 – 2016-06-29 19:08:06

1

http://bugs.python.org/issue16468argparse only supports iterable choices是討論選擇格式的bug問題。選項列表可以出現在3個位置:使用行,幫助行和錯誤消息。

解析器關心的是做in__contains__)測試。但是對於格式化來說,長列表,無界列表(例如整數> 100)和其他不可迭代的對象會帶來問題。 metavar是當前用戶可以解決大多數格式問題的方式(它可能無助於解決錯誤消息)。看看這個問題,瞭解如何改變你自己版本的​​。

3

這不會在選項列表非常長,如在原來的問題的情況下幫助,但對於誰像我一樣,碰到這個問題就來了那些人尋找一種方式來打破中等長度的字符串選項分成兩行,這裏是我的解決方案:

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