python-3.x 如何在argparse版本输出中保留换行符,同时让argparse自动格式化/ Package 剩余的帮助消息?

00jrzges  于 2023-02-10  发布在  Python
关注(0)|答案(5)|浏览(170)

我写了下面的代码。

import argparse

parser = argparse.ArgumentParser()
parser.add_argument('-v', '--version', action='version',
                    version='%(prog)s 1.0\nCopyright (c) 2016 Lone Learner')
parser.parse_args()

这将生成以下输出。

$ python foo.py --version
foo.py 1.0 Copyright (c) 2016 Lone Learner

你可以看到换行符丢失了。我想版权声明出现在下一行。
如何在版本输出消息中保留新行?
我仍然希望argparse计算python foo.py -h的输出应该如何布局,并且自动换行,但是我希望version输出是多行输出,换行符保持不变。

mdfafbf1

mdfafbf11#

RawTextHelpFormatter将关闭自动换行,允许显式的\n出现。但是它将影响所有help行。没有办法挑选。要么接受默认的换行,要么在所有帮助行中显式地换行。
您对帮助格式的挑剔程度已经达到了自己研究HelpFormatter代码所需的程度。

pgky5nke

pgky5nke2#

还有argparse.RawDescriptionHelpFormatter

parser=argparse.ArgumentParser(add_help=True,
    formatter_class=argparse.RawDescriptionHelpFormatter,
    description="""an
already-wrapped
description
string""")

它只保留descriptionepilog,只 Package 参数帮助字符串,OP的要求正好相反。

hwamh0ep

hwamh0ep3#

您最好使用定制的argparse.Action

import argparse
import os
import sys

class MultilineVersionAction(argparse.Action):
    verbose_version = '1.0\nCopyright (c) 2016 Lone Learner'

    def __init__(self, option_strings, dest, nargs=None, **kwargs):
        if nargs is not None:
            raise ValueError('nargs not allowed')
        # this is how argparse initialises `prog` by default
        self.prog = os.path.basename(sys.argv[0])
        super(MultilineVersionAction, self).__init__(option_strings, dest, nargs=0, **kwargs)

    def __call__(self, parser, namespace, values, option_string=None):
        parser.exit(message='{} {}\n'.format(self.prog, self.verbose_version))

# ...

    self.parser.add_argument('-v', '--version', action=MultilineVersionAction)
jmo0nnb3

jmo0nnb34#

只是不要使用action='version',相同的模式可以在-h中重复。

import os
import sys
import argparse

parser = argparse.ArgumentParser()
parser.add_argument('-v', '--version', action='store_true')
args = parser.parse_args()

if args.version:
    prog = os.path.basename(__file__)
    print('{} 1.0\nCopyright (c) 2016 Lone Learner'.format(prog))
    sys.exit()
2o7dmzc5

2o7dmzc55#

虽然我同意Hamish的观点,即最好使用自定义Action,但也可以利用更多的argparse机制,并与之进行更全面的集成。

import argparse
import sys

__version__ = 1.0
__copyright__ = "Copyright Nobody <nobody@example.com>"

class _MyVersionAction(argparse._VersionAction):
    """Customized _VersionAction with RawDescription-formatted output."""
    def __call__(self, parser, namespace, values, option_string=None):
        version = self.version
        if version is None:           # I have no idea why this is here¹
            version = parser.version  # ← (no such thing)
        formatter = argparse.RawDescriptionHelpFormatter(
            prog=parser.prog)
        formatter.add_text(version)
        parser._print_message(formatter.format_help(), sys.stdout)
        parser.exit()

parser = argparse.ArgumentParser()
parser.register('action', 'my_version', _MyVersionAction)

parser.add_argument(
    '-V', '--version', action='my_version',
    version=f"%(prog)s {__version__}\n{__copyright__}")
parser.parse_args()

这个_MyVersionAction类是argparse._VersionAction的子类,并且90%是其代码的直接复制粘贴。¹(它甚至没有定义__init__,只是继承了父类的。)
但是它对__call__方法做了最小的调整,强制它的格式化器为argparse.RawDescriptionHelpFormatter,原始代码用parser._get_formatter()查找解析器范围的格式化器,但是我们不希望在这里使用它。
然后,在创建解析器示例之后,我们为_MyVersionAction注册操作字符串'my_version',以便它可以像任何其他操作一样在add_argument(..., action='my_version')中使用。
例如,这允许您在版本字符串中使用%(prog)s,或者使用解析器示例中的其他数据,还可以在多个程序中重用action='my_version',因为版本字符串不是硬编码的,您只需像往常一样将其传递给add_argument()即可。

输出
$ python3 /tmp/argtest.py --help
usage: argtest.py [-h] [-V]

options:
  -h, --help     show this help message and exit
  -V, --version  show program's version number and exit

$ python3 /tmp/argtest.py --version
argtest.py 1.0
Copyright Nobody <nobody@example.com>
注解

1.就像评论说的,我不知道为什么在self.version没有设置的情况下,这个动作会试图获取parser.version--没有支持的API来设置parser对象的version属性。你必须用parser.version = X.Y手动强制设置它。我怀疑check只是从旧版本继承来的代码。或者甚至从optparse天开始。

相关问题