Python的argh库:在帮助信息中保留文档字符串格式

8 投票
4 回答
1901 浏览
提问于 2025-04-18 05:59

在我寻找更快的方式来解析命令行参数时,我发现了一个叫做 argh 库

我很喜欢 argh 的一些功能,但遇到了一个问题,这让我不太想用它。这个问题和默认的帮助信息有关,也就是当我使用 —help 选项时显示的内容:默认情况下,函数的文档字符串会显示在参数列表的上面。这虽然很好,但格式就变得乱了。比如,看看下面这个示例脚本:

import argh

def func(foo=1, bar=True):
    """Sample function.

        Parameters:
            foo: float
                An example argument.
            bar: bool
                Another argument.
    """
    print foo, bar

argh.dispatch_command(func, argv=['-h'])

运行后会得到以下输出:

usage: script.py [-h] [-f FOO] [-b]

Sample function. Parameters: foo: float An example argument. bar: bool Another
argument.

optional arguments:
  -h, --help         show this help message and exit
  -f FOO, --foo FOO
  -b, --bar

有没有什么(简单的)办法可以得到像下面这样的输出呢?

usage: script.py [-h] [-f FOO] [-b]

Sample function.

    Parameters:
        foo: float
            An example argument.
        bar: bool
            Another argument.

optional arguments:
  -h, --help         show this help message and exit
  -f FOO, --foo FOO
  -b, --bar

我更希望不使用注释来定义参数的帮助信息,因为那样每次有改动时,我都得同时修改函数的文档字符串和帮助文本。

4 个回答

0

关于在帮助信息中显示默认值的问题,这段 argparse 脚本结合了两种格式化类。

import argparse

def func(foo=1, bar=True):
    ...
    """
    print foo, bar

class MyFormatter(argparse.RawDescriptionHelpFormatter,
    argparse.ArgumentDefaultsHelpFormatter):
    pass

parser = argparse.ArgumentParser(prog='script.py',
    description=func.__doc__,
    formatter_class=MyFormatter)
parser.add_argument('-f', '--foo', type=float, default=1, help='test')
parser.add_argument('-b', '--bar', action='store_false', help='test')
parser.print_help()

生成的结果是:

usage: script.py [-h] [-f FOO] [-b]

Sample function.
   ...
optional arguments:
  -h, --help         show this help message and exit
  -f FOO, --foo FOO  test (default: 1)
  -b, --bar          test (default: True)

为了在帮助信息中显示默认值,我需要在原始帮助信息中加入一些文字(这里是'test')。

argh 中,你可能需要使用注解来提供帮助文本。

如果你使用注解,你可以通过 $(default)s 来添加帮助信息:

parser = argparse.ArgumentParser(prog='script.py',
    description=func.__doc__,
    formatter_class=argparse.RawDescriptionHelpFormatter)
parser.add_argument('-f', '--foo', type=float, default=1, help='default: %(default)s')
parser.add_argument('-b', '--bar', action='store_false', help='default: %(default)s')
1

感谢你对Argh库的关注。这里讨论的解决方案会在下一个版本中加入(argh ≥ 0.25)。你也可以查看一下第64个问题(已经修复了)。

3

在@hpaulj的帮助下,我终于实现了我想要的效果。为了简化这个过程,我定义了一个自定义的装饰器,类似于argh.arg,目的是为了不需要为每个参数单独写@argh.arg(‘—param’, help=“%(default)s”),而是只需在我的函数上使用一个@arg_custom()装饰器:

def arg_custom():
    from argh.constants import ATTR_ARGS
    from argh.assembling import  _get_args_from_signature, _fix_compat_issue29

    def wrapper(func):
        declared_args = getattr(func, ATTR_ARGS, [])
        for a in list(_get_args_from_signature(func)):
             declared_args.insert(0, dict(option_strings=a['option_strings'], help="(default: %(default)s)"))
        setattr(func, ATTR_ARGS, declared_args)
        _fix_compat_issue29(func)
        return func
    return wrapper

这里的关键是一个for循环,它确保所有参数都有一个对应的help=“%(default)s”选项。 同时还需要修改argh/constants.py中的相关行:

class CustomFormatter(argparse.ArgumentDefaultsHelpFormatter, argparse.RawDescriptionHelpFormatter):
        pass
PARSER_FORMATTER = CustomFormatter

这样我们就可以方便地使用:

@arg_custom()
def func(foo=1, bar=True):
    """Sample function.

        Parameters:
            foo: float
                An example argument.
            bar: bool
                Another argument.
    """
    print foo, bar

argh.dispatch_command(func)

最终在执行脚本时使用-h选项会得到:

usage: script.py [-h] [-f FOO] [-b]

Sample function.

        Parameters:
            foo: float
                An example argument.
            bar: bool
                Another argument.


optional arguments:
  -h, --help         show this help message and exit
  -f FOO, --foo FOO  (default: 1)
  -b, --bar          (default: True) 
8

我对 argh 不是很熟悉,但听说它是 argparse 的一个封装工具。我的猜测是,它会把你的函数的文档字符串 __doc__ 作为解析器的 description,比如:

parser = argparse.ArgumentParser(description=func.__doc__)

https://docs.python.org/2.7/library/argparse.html#argparse.RawDescriptionHelpFormatter

argparse 有一个叫 RawDescriptionHelpFormatter 的格式化工具,它会原样显示描述内容。

parser = argparse.ArgumentParser(description=func.__doc__,
    formatter_class=argparse.RawDescriptionHelpFormatter)

所以问题是,有没有办法让 argh 使用这个格式化工具呢?

这个 argparse 脚本可以生成你想要的帮助信息:

import argparse

def func(foo=1, bar=True):
    """Sample function.

        Parameters:
            foo: float
                An example argument.
            bar: bool
                Another argument.
    """
    print foo, bar

parser = argparse.ArgumentParser(prog='script.py',
    description=func.__doc__,
    formatter_class=argparse.RawDescriptionHelpFormatter)
parser.add_argument('-f', '--foo', type=float)
parser.add_argument('-b', '--bar', action='store_false')
parser.print_help()

argh/dispatching.py 文件中

def dispatch_command(function, *args, **kwargs):
    ...
    parser = argparse.ArgumentParser(formatter_class=PARSER_FORMATTER)
    set_default_command(parser, function)
    dispatch(parser, *args, **kwargs)

所以你可以选择设置:

PARSER_FORMATTER = argparse.RawDescriptionHelpFormatter

或者自己写一个函数:

def raw_dispatch_command(function, *args, **kwargs):
    ...
    parser = argparse.ArgumentParser(formatter_class=argparse.RawDescriptionHelpFormatter)
    set_default_command(parser, function)
    dispatch(parser, *args, **kwargs)

撰写回答