web-dev-qa-db-ja.com

Python argparse:ヘルプテキストに改行を挿入する方法

入力オプションの解析に argparse in Python 2.7 を使用しています。私のオプションの1つは複数選択です。ヘルプテキストでリストを作成したい。

from argparse import ArgumentParser

parser = ArgumentParser(description='test')

parser.add_argument('-g', choices=['a', 'b', 'g', 'd', 'e'], default='a',
    help="Some option, where\n"
         " a = alpha\n"
         " b = beta\n"
         " g = gamma\n"
         " d = delta\n"
         " e = epsilon")

parser.parse_args()

ただし、argparseは、すべての改行と連続するスペースを削除します。結果は次のようになります

〜/ Downloads:52 $ python2.7 x.py -h 
 usage:x.py [-h] [-g {a、b、g、d、e}] 
 
 test 
 
オプションの引数:
 -h、--helpこのヘルプメッセージを表示して終了
 -g {a、b 、g、d、e} a =アルファb =ベータg =ガンマd =デルタe 
 = epsilon 

ヘルプテキストに改行を挿入する方法は?

301
kennytm

RawTextHelpFormatter を使用してみてください:

from argparse import RawTextHelpFormatter
parser = ArgumentParser(description='test', formatter_class=RawTextHelpFormatter)
344

1つのオプションをオーバーライドする場合は、RawTextHelpFormatterを使用しないでください。代わりにHelpFormatterをサブクラス化し、「生」で処理する必要があるオプションの特別なイントロを提供します("R|rest of help"を使用します):

import argparse

class SmartFormatter(argparse.HelpFormatter):

    def _split_lines(self, text, width):
        if text.startswith('R|'):
            return text[2:].splitlines()  
        # this is the RawTextHelpFormatter._split_lines
        return argparse.HelpFormatter._split_lines(self, text, width)

そしてそれを使用します:

from argparse import ArgumentParser

parser = ArgumentParser(description='test', formatter_class=SmartFormatter)

parser.add_argument('-g', choices=['a', 'b', 'g', 'd', 'e'], default='a',
    help="R|Some option, where\n"
         " a = alpha\n"
         " b = beta\n"
         " g = gamma\n"
         " d = delta\n"
         " e = epsilon")

parser.parse_args()

ヘルプがR|で始まらない.add_argument()への他の呼び出しは、通常どおりラップされます。

これは argparseの改善点 の一部です。完全なSmartFormatterは、すべてのオプションへのデフォルトの追加、およびユーティリティの説明の生の入力もサポートしています。フルバージョンには独自の_split_linesメソッドがあります。バージョン文字列は保持されます:

parser.add_argument('--version', '-v', action="version",
                    version="version...\n   42!")
68
Anthon

別の簡単な方法は、textwrapを含めることです。

例えば、

import argparse, textwrap
parser = argparse.ArgumentParser(description='some information',
        usage='use "python %(prog)s --help" for more information',
        formatter_class=argparse.RawTextHelpFormatter)

parser.add_argument('--argument', default=somedefault, type=sometype,
        help= textwrap.dedent('''\
        First line
        Second line
        More lines ... '''))

このようにして、各出力行の前にある長い空きスペースを避けることができます。

usage: use "python your_python_program.py --help" for more information

Prepare input file

optional arguments:
-h, --help            show this help message and exit
--argument ARGUMENT
                      First line
                      Second line
                      More lines ...
28
Wang Zong'an

同様の問題に直面しました(Python 2.7.6)。 RawTextHelpFormatterを使用して、descriptionセクションをいくつかの行に分解しようとしました。

parser = ArgumentParser(description="""First paragraph 

                                       Second paragraph

                                       Third paragraph""",  
                                       usage='%(prog)s [OPTIONS]', 
                                       formatter_class=RawTextHelpFormatter)

options = parser.parse_args()

そして得た:

使用法:play-with-argparse.py [オプション] 
 
最初の段落
 
 2番目の段落
 
 3番目の段落
 
オプションの引数:
 -h、--helpこのヘルプメッセージを表示して終了

したがって、RawTextHelpFormatterは解決策ではありません。ソースコードに表示されるとおりに説明を印刷し、すべての空白文字を保持するため(読みやすくするためにソースコードに余分なタブを保持したいが、すべてを印刷したくない。また、生のフォーマッタは行を折り返さない長すぎる、たとえば80文字以上)。

正しい方向を示唆した@Antonに感謝します 上記 。しかし、そのソリューションはdescriptionセクションをフォーマットするためにわずかな修正が必要です。

とにかく、カスタムフォーマッタが必要です。既存のHelpFormatterクラスを拡張し、_fill_textメソッドを次のようにオーバーライドしました。

import textwrap as _textwrap
class MultilineFormatter(argparse.HelpFormatter):
    def _fill_text(self, text, width, indent):
        text = self._whitespace_matcher.sub(' ', text).strip()
        paragraphs = text.split('|n ')
        multiline_text = ''
        for paragraph in paragraphs:
            formatted_paragraph = _textwrap.fill(paragraph, width, initial_indent=indent, subsequent_indent=indent) + '\n\n'
            multiline_text = multiline_text + formatted_paragraph
        return multiline_text

argparse モジュールからの元のソースコードと比較してください:

def _fill_text(self, text, width, indent):
    text = self._whitespace_matcher.sub(' ', text).strip()
    return _textwrap.fill(text, width, initial_indent=indent,
                                       subsequent_indent=indent)

元のコードでは、説明全体がラップされています。上記のカスタムフォーマッタでは、テキスト全体がいくつかのチャンクに分割され、それぞれが個別にフォーマットされます。

そのため、カスタムフォーマッタを使用して:

parser = ArgumentParser(description= """First paragraph 
                                        |n                              
                                        Second paragraph
                                        |n
                                        Third paragraph""",  
                usage='%(prog)s [OPTIONS]',
                formatter_class=MultilineFormatter)

options = parser.parse_args()

出力は次のとおりです。

使用法:play-with-argparse.py [オプション] 
 
最初の段落
 
 2番目の段落
 
 3番目の段落
 
オプションの引数:
 -h、--helpこのヘルプメッセージを表示して終了
11
flaz14

説明テキストに手動で改行を入れ、それを自動で折り返したいと思っていました。しかし、ここでの提案はどれも役に立たなかったので、ここでの回答にあるSmartFormatterクラスを変更しました。 argparseメソッド名の問題はパブリックAPIにもかかわらず、私が持っているものです(test.pyと呼ばれるファイルとして):

import argparse
from argparse import RawDescriptionHelpFormatter

# call with: python test.py -h

class SmartDescriptionFormatter(argparse.RawDescriptionHelpFormatter):
  #def _split_lines(self, text, width): # RawTextHelpFormatter, although function name might change depending on Python
  def _fill_text(self, text, width, indent): # RawDescriptionHelpFormatter, although function name might change depending on Python
    #print("splot",text)
    if text.startswith('R|'):
      paragraphs = text[2:].splitlines()
      rebroken = [argparse._textwrap.wrap(tpar, width) for tpar in paragraphs]
      #print(rebroken)
      rebrokenstr = []
      for tlinearr in rebroken:
        if (len(tlinearr) == 0):
          rebrokenstr.append("")
        else:
          for tlinepiece in tlinearr:
            rebrokenstr.append(tlinepiece)
      #print(rebrokenstr)
      return '\n'.join(rebrokenstr) #(argparse._textwrap.wrap(text[2:], width))
    # this is the RawTextHelpFormatter._split_lines
    #return argparse.HelpFormatter._split_lines(self, text, width)
    return argparse.RawDescriptionHelpFormatter._fill_text(self, text, width, indent)

parser = argparse.ArgumentParser(formatter_class=SmartDescriptionFormatter, description="""R|Blahbla bla blah blahh/blahbla (bla blah-blabla) a blahblah bl a blaha-blah .blah blah

Blah blah bla blahblah, bla blahblah blah blah bl blblah bl blahb; blah bl blah bl bl a blah, bla blahb bl:

  blah blahblah blah bl blah blahblah""")

options = parser.parse_args()

2.7および3.4​​での動作は次のとおりです。

$ python test.py -h
usage: test.py [-h]

Blahbla bla blah blahh/blahbla (bla blah-blabla) a blahblah bl a blaha-blah
.blah blah

Blah blah bla blahblah, bla blahblah blah blah bl blblah bl blahb; blah bl
blah bl bl a blah, bla blahb bl:

  blah blahblah blah bl blah blahblah

optional arguments:
  -h, --help  show this help message and exit
2
sdbbs

上記のSmartFomatterから始めて、私はそのソリューションを終了しました。

class SmartFormatter(argparse.HelpFormatter):
    '''
         Custom Help Formatter used to split help text when '\n' was 
         inserted in it.
    '''

    def _split_lines(self, text, width):
        r = []
        for t in text.splitlines(): r.extend(argparse.HelpFormatter._split_lines(self, t, width))
        return r

奇妙なことに、トップレベルのパーサーに渡されるformatter_class引数はsub_parsersに継承されないため、作成されたsub_parserごとに再度渡す必要があることに注意してください。

0
ermitz