Python argparse:如何在帮助文本中插入换行符?

ken*_*ytm 317 python argparse

argparse在Python 2.7中用于解析输入选项.我的一个选择是多选.我想在其帮助文本中列出一个列表,例如

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()
Run Code Online (Sandbox Code Playgroud)

但是,argparse删除所有换行符和连续空格.结果看起来像

~/Downloads:52$ python2.7 x.py -h
usage: x.py [-h] [-g {a,b,g,d,e}]

test

optional arguments:
  -h, --help      show this help message and exit
  -g {a,b,g,d,e}  Some option, where a = alpha b = beta g = gamma d = delta e
                  = epsilon

如何在帮助文本中插入换行符?

Mic*_*ski 363

尝试使用RawTextHelpFormatter:

from argparse import RawTextHelpFormatter
parser = ArgumentParser(description='test', formatter_class=RawTextHelpFormatter)
Run Code Online (Sandbox Code Playgroud)

  • 请尝试使用formatter_class =`RawDescriptionHelpFormatter`,它仅适用于描述和epilog而不是帮助文本. (76认同)
  • 您也可以组合格式化程序,例如`class Formatter(argparse.ArgumentDefaultsHelpFormatter,argparse.RawDescriptionHelpFormatter):pass`然后`formatter_class = Formatter`. (9认同)
  • 很好,谢谢.是否可以仅将其应用于1个选项? (8认同)
  • 我认为不是.你可以继承它,但不幸的是`只有这个类的名称被认为是一个公共API.这个类提供的所有方法都被认为是一个实现细节.所以可能不是一个好主意,虽然它可能并不重要,因为2.7意味着最后的2.x python,你会被要求重构很多东西对于3.x无论如何.我实际上通过`easy_install`安装了`argparse`运行2.6,因此文档本身可能已经过时了. (6认同)
  • 一些链接:for [python 2.7](http://docs.python.org/library/argparse.html#formatter-class)和[python 3.*](http://docs.python.org/dev/库/ argparse.html#格式化级).根据[其维基](http://code.google.com/p/argparse/),2.6软件包应符合官方2.7版本.从文档:"传递RawDescriptionHelpFormatter as formatter_class =表示描述和epilog已经正确格式化,不应该换行" (3认同)
  • 我注意到即使使用`RawTextHelpFormatter`,也会删除前导和尾随换行符.要解决此问题,您只需添加两个或更多连续换行符; 除了一个换行符之外的所有换行符 (2认同)
  • 我在那里发现了我的错误:如果使用了子解析器(add_subparsers,然后是 add_parser 来定义子解析器),则必须为每个子解析器重新指定 formatter_class (2认同)

Ant*_*hon 72

如果您只想覆盖一个选项,则不应使用RawTextHelpFormatter.而是继承子类HelpFormatter并为应该处理"raw"的选项提供一个特殊的介绍(我使用"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)
Run Code Online (Sandbox Code Playgroud)

并使用它:

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()
Run Code Online (Sandbox Code Playgroud)

任何其他调用.add_argument()帮助不会开始的地方R|都将正常包装.

这是我对argparse的改进的一部分.完整的SmartFormatter还支持将默认值添加到所有选项以及实用程序描述的原始输入.完整版本有自己的_split_lines方法,因此保留对例如版本字符串的任何格式:

parser.add_argument('--version', '-v', action="version",
                    version="version...\n   42!")
Run Code Online (Sandbox Code Playgroud)

  • @mc_ Electron 完整版本的 SmartFormatter 也有自己的 `_split_lines` 并保留换行符(无需在开头指定“R|”,如果您需要该选项,请修补 `_VersionAction.__call__` 方法 (2认同)

Wan*_*'an 30

另一种简单的方法是包含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 ... '''))
Run Code Online (Sandbox Code Playgroud)

这样,我们可以避免每条输出线前面的长空间.

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 ...
Run Code Online (Sandbox Code Playgroud)


Ber*_*ner 12

我承认我发现这是一次非常令人沮丧的经历,就像许多其他人一样,考虑到我看到发布的解决方案的数量以及我在网络上看到这个问题的次数。但我发现这些解决方案中的大多数对我来说太复杂了,我想分享我所拥有的最简单的解决方案。

这是演示的脚本:

#!/usr/bin/python3
import textwrap
from argparse import ArgumentParser, HelpFormatter

class RawFormatter(HelpFormatter):
    def _fill_text(self, text, width, indent):
        return "\n".join([textwrap.fill(line, width) for line in textwrap.indent(textwrap.dedent(text), indent).splitlines()])

program_descripton = f'''
    FunkyTool v1.0

    Created by the Funky Guy on January 1 2020
    Copyright 2020. All rights reserved.

    Licensed under The Hippocratic License 2.1
    https://firstdonoharm.dev/

    Distributed on an "AS IS" basis without warranties
    or conditions of any kind, either express or implied.

    USAGE:
    '''

parser = ArgumentParser(description=program_descripton, formatter_class=RawFormatter)
args = parser.parse_args()
Run Code Online (Sandbox Code Playgroud)

这是它的样子test.py

$ ./test.py --help
usage: test.py [-h]

FunkyTool v1.0

Created by the Funky Guy on January 1 2020
Copyright 2020. All rights reserved.

Licensed under The Hippocratic License 2.1
https://firstdonoharm.dev/

Distributed on an "AS IS" basis without warranties
or conditions of any kind, either express or implied.

USAGE:

optional arguments:
  -h, --help  show this help message and exit
Run Code Online (Sandbox Code Playgroud)

因此,原始描述中的所有基本格式都被整齐地保留下来,唉,我们不得不使用自定义格式化程序,但它是一个单行代码。可以更清晰地写成:

$ ./test.py --help
usage: test.py [-h]

FunkyTool v1.0

Created by the Funky Guy on January 1 2020
Copyright 2020. All rights reserved.

Licensed under The Hippocratic License 2.1
https://firstdonoharm.dev/

Distributed on an "AS IS" basis without warranties
or conditions of any kind, either express or implied.

USAGE:

optional arguments:
  -h, --help  show this help message and exit
Run Code Online (Sandbox Code Playgroud)

但我自己更喜欢单行。


fla*_*z14 11

我遇到过类似的问题(Python 2.7.6).我试图将描述部分分成几行,使用RawTextHelpFormatter:

parser = ArgumentParser(description="""First paragraph 

                                       Second paragraph

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

options = parser.parse_args()
Run Code Online (Sandbox Code Playgroud)

得到了:

usage: play-with-argparse.py [OPTIONS]

First paragraph 

                        Second paragraph

                        Third paragraph

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

所以RawTextHelpFormatter不是解决方案.因为它打印源代码中显示的描述,保留所有空格字符(我想在我的源代码中保留额外的选项卡以便于阅读,但我不想全部打印它们.而且原始格式化程序在它是时不会换行太长,例如超过80个字符).

由于@Anton谁启发了正确的方向之上.但是该解决方案需要稍微修改才能格式化描述部分.

无论如何,需要自定义格式化程序.我扩展了现有的HelpFormatter类和overrode _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
Run Code Online (Sandbox Code Playgroud)

与来自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)
Run Code Online (Sandbox Code Playgroud)

在原始代码中,整个描述被包装.在上面的自定义格式化程序中,整个文本被分成几个块,每个块都是独立格式化的.

所以借助自定义格式化程序:

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

options = parser.parse_args()
Run Code Online (Sandbox Code Playgroud)

输出是:

usage: play-with-argparse.py [OPTIONS]

First paragraph

Second paragraph

Third paragraph

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

  • 子类化"HelpFormatter"是有问题的,因为argparse开发人员只能保证类名在argparse的未来版本中能够存活.他们基本上写了一张空白支票,以便他们可以更改方法名称,如果方便他们这样做的话.我发现这令人沮丧; 他们本可以做的最少的事情是在API中暴露了一些方法. (2认同)

小智 10

RawTextHelpFormatter使用和处理缩进来获取新行的另一种简单方法是

import argparse

parser = argparse.ArgumentParser(
    description='test', formatter_class=argparse.RawTextHelpFormatter)

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

Run Code Online (Sandbox Code Playgroud)

输出是

$ python2 x.py -h
usage: x.py [-h] [-g {a,b,g,d,e}]

test

optional arguments:
  -h, --help      show this help message and exit
  -g {a,b,g,d,e}  Some option, where
                   a = alpha
                   b = beta
                   g = gamma
                   d = delta
                   e = epsilon

Run Code Online (Sandbox Code Playgroud)